<commit_before>/*Package nmap parses Nmap XML data into a similary formed struct.*/
package nmap

import (
	"encoding/xml"
)

// NmapRun is contains all the data for a single nmap scan.
type NmapRun struct {
	Scanner          string    `xml:"scanner,attr" json:"scanner"`
	Args             string    `xml:"args,attr" json:"args"`
	Start            string    `xml:"start,attr" json:"start"`
	StartStr         string    `xml:"startstr,attr" json:"startstr"`
	Version          string    `xml:"version,attr" json:"version"`
	ProfileName      string    `xml:"profile_name,attr" json:"profile_name"`
	XMLOutputVersion string    `xml:"xmloutputversion,attr" json:"xmloutputversion"`
	ScanInfo         ScanInfo  `xml:"scaninfo" json:"scaninfo"`
	Verbose          Verbose   `xml:"verbose" json:"verbose"`
	Debugging        Debugging `xml:"debugging" json:"debugging"`
	Hosts            []Host    `xml:"host" json:"hosts"`
	Targets          []Target  `xml:"target" json:"targets"`
	RunStats         RunStats  `xml:"runstats" json:"runstats"`
}

// ScanInfo contains informational regarding how the scan
// was run.
type ScanInfo struct {
	Type        string `xml:"type,attr" json:"type"`
	Protocol    string `xml:"protocol,attr" json:"protocol"`
	NumServices string `xml:"numservices,attr" json:"numservices"`
	Services    string `xml:"services,attr" json:"services"`
	ScanFlags   string `xml:"scanflags,attr" json:"scanflags"`
}

// Verbose contains the verbosity level for the Nmap scan.
type Verbose struct {
	Level string `xml:"level,attr" json:"level"`
}

// Debugging contains the debugging level for the Nmap scan.
type Debugging struct {
	Level string `xml:"level,attr" json:"level"`
}

// Target is found in the Nmap xml spec. I have no idea what it
// actually is.
type Target struct {
	Specification string `xml:"specification,attr" json:"specification"`
	Status        string `xml:"status,attr" json:"status"`
	Reason        string `xml:"reason,attr" json:"reason"`
}

// Host contains all information about a single host.
type Host struct {
	StartTime    string       `xml:"starttime,attr" json:"starttime"`
	EndTime      string       `xml:"endtime,attr" json:"endtime"`
	Comment      string       `xml:"comment,attr" json:"comment"`
	Status       Status       `xml:"status" json:"status"`
	Addresses    []Address    `xml:"address" json:"addresses"`
	Hostnames    []Hostname   `xml:"hostnames>hostname" json:"hostnames"`
	Smurf        []Smurf      `xml:"smurf" json:"smurf"`
	Ports        []Port       `xml:"ports>port" json:"ports"`
	Os           Os           `xml:"os" json:"os"`
	Distance     Distance     `xml:"distance" json:"distance"`
	Uptime       Uptime       `xml:"updtime" json:"updtime"`
	TcpSequence  TcpSequence  `xml:"tcpsequence" json:"tcpsequence"`
	IPIdSequence IPIdSequence `xml:"ipidsequence" json:"ipidsequence"`
	Trace        Trace        `xml:"trace" json:"trace"`
}

// Status is the host's status. Up, down, etc.
type Status struct {
	State     string `xml:"state,attr" json:"state"`
	Reason    string `xml:"reason,attr" json:"reason"`
	ReasonTTL string `xml:"reason_ttl,attr" json:"reason_ttl"`
}

// Address contains a IPv4 or IPv6 address for a Host.
type Address struct {
	Addr     string `xml:"addr,attr" json:"addr"`
	AddrType string `xml:"addrtype,attr" json:"addrtype"`
	Vendor   string `xml:"vendor,attr" json:"vendor"`
}

// Hostname is a single name for a Host.
type Hostname struct {
	Name string `xml:"name,attr" json:"name"`
	Type string `xml:"type,attr" json:"type"`
}

// Smurf contains repsonses from a smurf attack. I think.
// Smurf attacks, really?
type Smurf struct {
	Responses string `xml:"responses,attr" json:"responses"`
}

// Port contains all the information about a scanned port.
type Port struct {
	Protocol string   `xml:"protocol,attr" json:"protocol"`
	PortId   int      `xml:"portid,attr" json:"portid"`
	State    State    `xml:"state" json:"state"`
	Owner    Owner    `xml:"owner" json:"owner"`
	Service  Service  `xml:"service" json:"service"`
	Scripts  []Script `xml:"script" json:"scripts"`
}

// State contains information about a given ports
// status. State will be open, closed, etc.
type State struct {
	State     string `xml:"state,attr" json:"state"`
	Reason    string `xml:"reason,attr" json:"reason"`
	ReasonTTL string `xml:"reason_ttl,attr" json:"reason_ttl"`
	ReasonIP  string `xml:"reason_ip,attr" json:"reason_ip"`
}

// Owner contains the name of Port.Owner.
type Owner struct {
	Name string `xml:"name,attr" json:"name"`
}

// Service contains detailed information about a Port's
// service details.
type Service struct {
	Name       string `xml:"name,attr" json:"name"`
	Conf       string `xml:"conf,attr" json:"conf"`
	Method     string `xml:"method,attr" json:"method"`
	Version    string `xml:"version,attr" json:"version"`
	Product    string `xml:"product,attr" json:"product"`
	ExtraInfo  string `xml:"extrainfo,attr" json:"extrainfo"`
	Tunnel     string `xml:"tunnel,attr" json:"tunnel"`
	Proto      string `xml:"proto,attr" json:"proto"`
	Rpcnum     string `xml:"rpcnum,attr" json:"rpcnum"`
	Lowver     string `xml:"lowver,attr" json:"lowver"`
	Highver    string `xml:"hiver,attr" json:"hiver"`
	Hostname   string `xml:"hostname,attr" json:"hostname"`
	OsType     string `xml:"ostype,attr" json:"ostype"`
	DeviceType string `xml:"devicetype,attr" json:"devicetype"`
	ServiceFp  string `xml:"servicefp,attr" json:"servicefp"`
}

// Script contains information from Nmap Scripting Engine.
type Script struct {
	Id     string `xml:"id,attr" json:"id"`
	Output string `xml:"output,attr" json:"output"`
}

// Os contains the fingerprinted operating system for a Host.
type Os struct {
	PortUsed      []PortUsed      `xml:"portused" json:"portsused"`
	OsMatch       []OsMatch       `xml:"osmatch" json:"osmatches"`
	OsFingerprint []OsFingerprint `xml:"osfingerprint" json:"osfingerprints"`
}

// PortUsed is the port used to fingerprint a Os.
type PortUsed struct {
	State  string `xml:"state,attr" json:"state"`
	Proto  string `xml:"proto,attr" json:"proto"`
	PortId string `xml:"portid,attr" json:"portid"`
}

// OsMatch contains detailed information regarding a Os fingerprint.
type OsMatch struct {
	Name     string    `xml:"name,attr" json:"name"`
	Accuracy string    `xml:"accuracy,attr" json:"accuracy"`
	Line     string    `xml:"line,attr" json:"line"`
	OsClass  []OsClass `xml:"osclass" json:"osclasses"`
}

// OsClass contains vendor information for an Os.
type OsClass struct {
	Vendor   string `xml:"vendor,attr" json:"vendor"`
	OsGen    string `xml"osgen,attr"`
	Type     string `xml:"type,attr" json:"type"`
	Accuracy string `xml:"accurancy,attr" json:"accurancy"`
	OsFamily string `xml:"osfamily,attr" json:"osfamily"`
}

// OsFingerprint is the actual fingerprint string.
type OsFingerprint struct {
	Fingerprint string `xml:"fingerprint,attr" json:"fingerprint"`
}

// Distance is the amount of hops to a particular host.
type Distance struct {
	Value string `xml:"value,attr" json:"value"`
}

// Uptime is the amount of time the host has been up.
type Uptime struct {
	Seconds  string `xml:"seconds,attr" json:"seconds"`
	Lastboot string `xml:"lastboot,attr" json:"lastboot"`
}

// TcpSequence contains information regarding the detected tcp sequence.
type TcpSequence struct {
	Index      string `xml:"index,attr" json:"index"`
	Difficulty string `xml:"difficulty,attr" json:"difficulty"`
	Values     string `xml:"vaules,attr" json:"vaules"`
}

// IPIdSequence contains information regarding the detected ip sequence.
type IPIdSequence struct {
	Class  string `xml:"class,attr" json:"class"`
	Values string `xml:"values,attr" json:"values"`
}

// Times contains time statistics for an Nmap scan.
type Times struct {
	Srtt   string `xml:"srtt,attr" json:"srtt"`
	Rttvar string `xml:"rttvar,attr" json:"rttvar"`
	To     string `xml:"to,attr" json:"to"`
}

// Trace contains the hops to a Host.
type Trace struct {
	Hops []Hop `xml:"hop" json:"hops"`
}

// Hop is a ip hop to a Host.
type Hop struct {
	TTL    string `xml:"ttl,attr" json:"ttl"`
	Rtt    string `xml:"rtt,attr" json:"rtt"`
	IPAddr string `xml:"ipaddr,attr" json:"ipaddr"`
	Host   string `xml:"host,attr" json:"host"`
}

// RunStats contains statistics for a
// finished Nmap scan.
type RunStats struct {
	Finished Finished `xml:"finished" json:"finished"`
	Hosts    Stats    `xml:"hosts" json:"hosts"`
}

// Finished contains detailed statistics regarding
// a finished Nmap scan.
type Finished struct {
	Time     string `xml:"time,attr" json:"time"`
	TimeStr  string `xml:"timestr,attr" json:"timestr"`
	Elapsed  string `xml:"elapsed,attr" json:"elapsed"`
	Summary  string `xml:"summary,attr" json:"summary"`
	Exit     string `xml:"exit,attr" json:"exit"`
	ErrorMsg string `xml:"errormsg,attr" json:"errormsg"`
}

// Stats contains the amount of up and down hosts and the total count.
type Stats struct {
	Up    string `xml:"up,attr" json:"up"`
	Down  string `xml:"down,attr" json:"down"`
	Total string `xml:"total,attr" json:"total"`
}

// Parse takes a byte array of nmap xml data and unmarshals it into an
// NmapRun struct. All elements are returned as strings, it is up to the caller
// to check and cast them to the proper type.
func Parse(content []byte) (*NmapRun, error) {
	r := &NmapRun{}
	err := xml.Unmarshal(content, r)
	if err != nil {
		return r, err
	}
	return r, nil
}
<commit_msg>Fixed some field-types.<commit_after>/*Package nmap parses Nmap XML data into a similary formed struct.*/
package nmap

import (
	"encoding/xml"
	"fmt"
	"strconv"
	"time"
)

type Timestamp struct {
	time.Time
}

// str2time converts a string containing a UNIX timestamp to to a time.Time.
func (t *Timestamp) str2time(s string) (err error) {
	ts, err := strconv.Atoi(string(s))
	if err != nil {
		return
	}
	t.Time = time.Unix(int64(ts), 0)
	return
}

// time2str formats the time.Time value as a UNIX timestamp string.
func (t *Timestamp) time2str() string {
	return fmt.Sprint(t.Time.Unix())
}

func (t *Timestamp) MarshalJSON() ([]byte, error) {
	return []byte(t.time2str()), nil
}

func (t *Timestamp) UnmarshalJSON(b []byte) error {
	return t.str2time(string(b))
}

func (t *Timestamp) MarshalXMLAttr(name xml.Name) (xml.Attr, error) {
	return xml.Attr{Name: name, Value: t.time2str()}, nil
}

func (t *Timestamp) UnmarshalXMLAttr(attr xml.Attr) (err error) {
	return t.str2time(attr.Value)
}

// NmapRun is contains all the data for a single nmap scan.
type NmapRun struct {
	Scanner          string    `xml:"scanner,attr" json:"scanner"`
	Args             string    `xml:"args,attr" json:"args"`
	Start            Timestamp `xml:"start,attr" json:"start"`
	StartStr         string    `xml:"startstr,attr" json:"startstr"`
	Version          string    `xml:"version,attr" json:"version"`
	ProfileName      string    `xml:"profile_name,attr" json:"profile_name"`
	XMLOutputVersion string    `xml:"xmloutputversion,attr" json:"xmloutputversion"`
	ScanInfo         ScanInfo  `xml:"scaninfo" json:"scaninfo"`
	Verbose          Verbose   `xml:"verbose" json:"verbose"`
	Debugging        Debugging `xml:"debugging" json:"debugging"`
	Hosts            []Host    `xml:"host" json:"hosts"`
	Targets          []Target  `xml:"target" json:"targets"`
	RunStats         RunStats  `xml:"runstats" json:"runstats"`
}

// ScanInfo contains informational regarding how the scan
// was run.
type ScanInfo struct {
	Type        string `xml:"type,attr" json:"type"`
	Protocol    string `xml:"protocol,attr" json:"protocol"`
	NumServices int    `xml:"numservices,attr" json:"numservices"`
	Services    string `xml:"services,attr" json:"services"`
	ScanFlags   string `xml:"scanflags,attr" json:"scanflags"`
}

// Verbose contains the verbosity level for the Nmap scan.
type Verbose struct {
	Level int `xml:"level,attr" json:"level"`
}

// Debugging contains the debugging level for the Nmap scan.
type Debugging struct {
	Level int `xml:"level,attr" json:"level"`
}

// Target is found in the Nmap xml spec. I have no idea what it
// actually is.
type Target struct {
	Specification string `xml:"specification,attr" json:"specification"`
	Status        string `xml:"status,attr" json:"status"`
	Reason        string `xml:"reason,attr" json:"reason"`
}

// Host contains all information about a single host.
type Host struct {
	StartTime    Timestamp    `xml:"starttime,attr" json:"starttime"`
	EndTime      Timestamp    `xml:"endtime,attr" json:"endtime"`
	Comment      string       `xml:"comment,attr" json:"comment"`
	Status       Status       `xml:"status" json:"status"`
	Addresses    []Address    `xml:"address" json:"addresses"`
	Hostnames    []Hostname   `xml:"hostnames>hostname" json:"hostnames"`
	Smurf        []Smurf      `xml:"smurf" json:"smurf"`
	Ports        []Port       `xml:"ports>port" json:"ports"`
	Os           Os           `xml:"os" json:"os"`
	Distance     Distance     `xml:"distance" json:"distance"`
	Uptime       Uptime       `xml:"uptime" json:"uptime"`
	TcpSequence  TcpSequence  `xml:"tcpsequence" json:"tcpsequence"`
	IPIdSequence IPIdSequence `xml:"ipidsequence" json:"ipidsequence"`
	Trace        Trace        `xml:"trace" json:"trace"`
}

// Status is the host's status. Up, down, etc.
type Status struct {
	State     string  `xml:"state,attr" json:"state"`
	Reason    string  `xml:"reason,attr" json:"reason"`
	ReasonTTL float32 `xml:"reason_ttl,attr" json:"reason_ttl"`
}

// Address contains a IPv4 or IPv6 address for a Host.
type Address struct {
	Addr     string `xml:"addr,attr" json:"addr"`
	AddrType string `xml:"addrtype,attr" json:"addrtype"`
	Vendor   string `xml:"vendor,attr" json:"vendor"`
}

// Hostname is a single name for a Host.
type Hostname struct {
	Name string `xml:"name,attr" json:"name"`
	Type string `xml:"type,attr" json:"type"`
}

// Smurf contains repsonses from a smurf attack. I think.
// Smurf attacks, really?
type Smurf struct {
	Responses string `xml:"responses,attr" json:"responses"`
}

// Port contains all the information about a scanned port.
type Port struct {
	Protocol string   `xml:"protocol,attr" json:"protocol"`
	PortId   int      `xml:"portid,attr" json:"portid"`
	State    State    `xml:"state" json:"state"`
	Owner    Owner    `xml:"owner" json:"owner"`
	Service  Service  `xml:"service" json:"service"`
	Scripts  []Script `xml:"script" json:"scripts"`
}

// State contains information about a given ports
// status. State will be open, closed, etc.
type State struct {
	State     string  `xml:"state,attr" json:"state"`
	Reason    string  `xml:"reason,attr" json:"reason"`
	ReasonTTL float32 `xml:"reason_ttl,attr" json:"reason_ttl"`
	ReasonIP  string  `xml:"reason_ip,attr" json:"reason_ip"`
}

// Owner contains the name of Port.Owner.
type Owner struct {
	Name string `xml:"name,attr" json:"name"`
}

// Service contains detailed information about a Port's
// service details.
type Service struct {
	Name       string `xml:"name,attr" json:"name"`
	Conf       int    `xml:"conf,attr" json:"conf"`
	Method     string `xml:"method,attr" json:"method"`
	Version    string `xml:"version,attr" json:"version"`
	Product    string `xml:"product,attr" json:"product"`
	ExtraInfo  string `xml:"extrainfo,attr" json:"extrainfo"`
	Tunnel     string `xml:"tunnel,attr" json:"tunnel"`
	Proto      string `xml:"proto,attr" json:"proto"`
	Rpcnum     string `xml:"rpcnum,attr" json:"rpcnum"`
	Lowver     string `xml:"lowver,attr" json:"lowver"`
	Highver    string `xml:"hiver,attr" json:"hiver"`
	Hostname   string `xml:"hostname,attr" json:"hostname"`
	OsType     string `xml:"ostype,attr" json:"ostype"`
	DeviceType string `xml:"devicetype,attr" json:"devicetype"`
	ServiceFp  string `xml:"servicefp,attr" json:"servicefp"`
}

// Script contains information from Nmap Scripting Engine.
type Script struct {
	Id     string `xml:"id,attr" json:"id"`
	Output string `xml:"output,attr" json:"output"`
}

// Os contains the fingerprinted operating system for a Host.
type Os struct {
	PortUsed      []PortUsed      `xml:"portused" json:"portsused"`
	OsMatch       []OsMatch       `xml:"osmatch" json:"osmatches"`
	OsFingerprint []OsFingerprint `xml:"osfingerprint" json:"osfingerprints"`
}

// PortUsed is the port used to fingerprint a Os.
type PortUsed struct {
	State  string `xml:"state,attr" json:"state"`
	Proto  string `xml:"proto,attr" json:"proto"`
	PortId string `xml:"portid,attr" json:"portid"`
}

// OsMatch contains detailed information regarding a Os fingerprint.
type OsMatch struct {
	Name     string    `xml:"name,attr" json:"name"`
	Accuracy string    `xml:"accuracy,attr" json:"accuracy"`
	Line     string    `xml:"line,attr" json:"line"`
	OsClass  []OsClass `xml:"osclass" json:"osclasses"`
}

// OsClass contains vendor information for an Os.
type OsClass struct {
	Vendor   string `xml:"vendor,attr" json:"vendor"`
	OsGen    string `xml"osgen,attr"`
	Type     string `xml:"type,attr" json:"type"`
	Accuracy string `xml:"accurancy,attr" json:"accurancy"`
	OsFamily string `xml:"osfamily,attr" json:"osfamily"`
}

// OsFingerprint is the actual fingerprint string.
type OsFingerprint struct {
	Fingerprint string `xml:"fingerprint,attr" json:"fingerprint"`
}

// Distance is the amount of hops to a particular host.
type Distance struct {
	Value int `xml:"value,attr" json:"value"`
}

// Uptime is the amount of time the host has been up.
type Uptime struct {
	Seconds  int    `xml:"seconds,attr" json:"seconds"`
	Lastboot string `xml:"lastboot,attr" json:"lastboot"`
}

// TcpSequence contains information regarding the detected tcp sequence.
type TcpSequence struct {
	Index      int    `xml:"index,attr" json:"index"`
	Difficulty string `xml:"difficulty,attr" json:"difficulty"`
	Values     string `xml:"vaules,attr" json:"vaules"`
}

// IPIdSequence contains information regarding the detected ip sequence.
type IPIdSequence struct {
	Class  string `xml:"class,attr" json:"class"`
	Values string `xml:"values,attr" json:"values"`
}

// Times contains time statistics for an Nmap scan.
type Times struct {
	Srtt   string `xml:"srtt,attr" json:"srtt"`
	Rttvar string `xml:"rttvar,attr" json:"rttvar"`
	To     string `xml:"to,attr" json:"to"`
}

// Trace contains the hops to a Host.
type Trace struct {
	Hops []Hop `xml:"hop" json:"hops"`
}

// Hop is a ip hop to a Host.
type Hop struct {
	TTL    float32 `xml:"ttl,attr" json:"ttl"`
	Rtt    float32 `xml:"rtt,attr" json:"rtt"`
	IPAddr string  `xml:"ipaddr,attr" json:"ipaddr"`
	Host   string  `xml:"host,attr" json:"host"`
}

// RunStats contains statistics for a
// finished Nmap scan.
type RunStats struct {
	Finished Finished `xml:"finished" json:"finished"`
	Hosts    Stats    `xml:"hosts" json:"hosts"`
}

// Finished contains detailed statistics regarding
// a finished Nmap scan.
type Finished struct {
	Time     Timestamp `xml:"time,attr" json:"time"`
	TimeStr  string    `xml:"timestr,attr" json:"timestr"`
	Elapsed  float32   `xml:"elapsed,attr" json:"elapsed"`
	Summary  string    `xml:"summary,attr" json:"summary"`
	Exit     string    `xml:"exit,attr" json:"exit"`
	ErrorMsg string    `xml:"errormsg,attr" json:"errormsg"`
}

// Stats contains the amount of up and down hosts and the total count.
type Stats struct {
	Up    int `xml:"up,attr" json:"up"`
	Down  int `xml:"down,attr" json:"down"`
	Total int `xml:"total,attr" json:"total"`
}

// Parse takes a byte array of nmap xml data and unmarshals it into an
// NmapRun struct. All elements are returned as strings, it is up to the caller
// to check and cast them to the proper type.
func Parse(content []byte) (*NmapRun, error) {
	r := &NmapRun{}
	err := xml.Unmarshal(content, r)
	if err != nil {
		return r, err
	}
	return r, nil
}
<|endoftext|>


<commit_before>/*Package nmap parses Nmap XML data into a similary formed struct.*/
package nmap

import (
	"encoding/xml"
	"fmt"
	"strconv"
	"time"
)

type Timestamp struct {
	time.Time
}

// str2time converts a string containing a UNIX timestamp to to a time.Time.
func (t *Timestamp) str2time(s string) (err error) {
	ts, err := strconv.Atoi(string(s))
	if err != nil {
		return
	}
	t.Time = time.Unix(int64(ts), 0)
	return
}

// time2str formats the time.Time value as a UNIX timestamp string.
func (t *Timestamp) time2str() string {
	return fmt.Sprint(t.Time.Unix())
}

func (t *Timestamp) MarshalJSON() ([]byte, error) {
	return []byte(t.time2str()), nil
}

func (t *Timestamp) UnmarshalJSON(b []byte) error {
	return t.str2time(string(b))
}

func (t *Timestamp) MarshalXMLAttr(name xml.Name) (xml.Attr, error) {
	return xml.Attr{Name: name, Value: t.time2str()}, nil
}

func (t *Timestamp) UnmarshalXMLAttr(attr xml.Attr) (err error) {
	return t.str2time(attr.Value)
}

// NmapRun is contains all the data for a single nmap scan.
type NmapRun struct {
	Scanner          string         `xml:"scanner,attr" json:"scanner"`
	Args             string         `xml:"args,attr" json:"args"`
	Start            Timestamp      `xml:"start,attr" json:"start"`
	StartStr         string         `xml:"startstr,attr" json:"startstr"`
	Version          string         `xml:"version,attr" json:"version"`
	ProfileName      string         `xml:"profile_name,attr" json:"profile_name"`
	XMLOutputVersion string         `xml:"xmloutputversion,attr" json:"xmloutputversion"`
	ScanInfo         ScanInfo       `xml:"scaninfo" json:"scaninfo"`
	Verbose          Verbose        `xml:"verbose" json:"verbose"`
	Debugging        Debugging      `xml:"debugging" json:"debugging"`
	TaskBegin        []Task         `xml:"taskbegin" json:"taskbegin"`
	TaskProgress     []TaskProgress `xml:"taskprogress" json:"taskprogress"`
	TaskEnd          []Task         `xml:"taskend" json:"taskend"`
	PreScripts       []Script       `xml:"prescript>script" json:"prescripts"`
	PostScripts      []Script       `xml:"postscript>script" json:"postscripts"`
	Hosts            []Host         `xml:"host" json:"hosts"`
	Targets          []Target       `xml:"target" json:"targets"`
	RunStats         RunStats       `xml:"runstats" json:"runstats"`
}

// ScanInfo contains informational regarding how the scan
// was run.
type ScanInfo struct {
	Type        string `xml:"type,attr" json:"type"`
	Protocol    string `xml:"protocol,attr" json:"protocol"`
	NumServices int    `xml:"numservices,attr" json:"numservices"`
	Services    string `xml:"services,attr" json:"services"`
	ScanFlags   string `xml:"scanflags,attr" json:"scanflags"`
}

// Verbose contains the verbosity level for the Nmap scan.
type Verbose struct {
	Level int `xml:"level,attr" json:"level"`
}

// Debugging contains the debugging level for the Nmap scan.
type Debugging struct {
	Level int `xml:"level,attr" json:"level"`
}

// Task contains information about started and stopped Nmap tasks.
type Task struct {
	Task      string    `xml:"task,attr" json:"task"`
	Time      Timestamp `xml:"time,attr" json:"time"`
	ExtraInfo string    `xml:"extrainfo,attr" json:"extrainfo"`
}

// TaskProgress contains information about the progression of a Task.
type TaskProgress struct {
	Task      string    `xml:"task,attr" json:"task"`
	Time      Timestamp `xml:"time,attr" json:"time"`
	Percent   float32   `xml:"percent,attr" json:"percent"`
	Remaining int       `xml:"remaining,attr" json:"remaining"`
	Etc       Timestamp `xml:"etc,attr" json:"etc"`
}

// Target is found in the Nmap xml spec. I have no idea what it
// actually is.
type Target struct {
	Specification string `xml:"specification,attr" json:"specification"`
	Status        string `xml:"status,attr" json:"status"`
	Reason        string `xml:"reason,attr" json:"reason"`
}

// Host contains all information about a single host.
type Host struct {
	StartTime     Timestamp     `xml:"starttime,attr" json:"starttime"`
	EndTime       Timestamp     `xml:"endtime,attr" json:"endtime"`
	Comment       string        `xml:"comment,attr" json:"comment"`
	Status        Status        `xml:"status" json:"status"`
	Addresses     []Address     `xml:"address" json:"addresses"`
	Hostnames     []Hostname    `xml:"hostnames>hostname" json:"hostnames"`
	Smurfs        []Smurf       `xml:"smurf" json:"smurfs"`
	Ports         []Port        `xml:"ports>port" json:"ports"`
	ExtraPorts    []ExtraPorts  `xml:"ports>extraports" json:"extraports"`
	Os            Os            `xml:"os" json:"os"`
	Distance      Distance      `xml:"distance" json:"distance"`
	Uptime        Uptime        `xml:"uptime" json:"uptime"`
	TcpSequence   TcpSequence   `xml:"tcpsequence" json:"tcpsequence"`
	IpIdSequence  IpIdSequence  `xml:"ipidsequence" json:"ipidsequence"`
	TcpTsSequence TcpTsSequence `xml:"tcptssequence" json:"tcptssequence"`
	HostScripts   []Script      `xml:"hostscript>script" json:"hostscripts"`
	Trace         Trace         `xml:"trace" json:"trace"`
}

// Status is the host's status. Up, down, etc.
type Status struct {
	State     string  `xml:"state,attr" json:"state"`
	Reason    string  `xml:"reason,attr" json:"reason"`
	ReasonTTL float32 `xml:"reason_ttl,attr" json:"reason_ttl"`
}

// Address contains a IPv4 or IPv6 address for a Host.
type Address struct {
	Addr     string `xml:"addr,attr" json:"addr"`
	AddrType string `xml:"addrtype,attr" json:"addrtype"`
	Vendor   string `xml:"vendor,attr" json:"vendor"`
}

// Hostname is a single name for a Host.
type Hostname struct {
	Name string `xml:"name,attr" json:"name"`
	Type string `xml:"type,attr" json:"type"`
}

// Smurf contains repsonses from a smurf attack. I think.
// Smurf attacks, really?
type Smurf struct {
	Responses string `xml:"responses,attr" json:"responses"`
}

// ExtraPorts contains the information about the closed|filtered ports.
type ExtraPorts struct {
	State   string   `xml:"state,attr" json:"state"`
	Count   int      `xml:"count,attr" json:"count"`
	Reasons []Reason `xml:"extrareasons" json:"reasons"`
}
type Reason struct {
	Reason string `xml:"reason,attr" json:"reason"`
	Count  int    `xml:"count,attr" json:"count"`
}

// Port contains all the information about a scanned port.
type Port struct {
	Protocol string   `xml:"protocol,attr" json:"protocol"`
	PortId   int      `xml:"portid,attr" json:"id"`
	State    State    `xml:"state" json:"state"`
	Owner    Owner    `xml:"owner" json:"owner"`
	Service  Service  `xml:"service" json:"service"`
	Scripts  []Script `xml:"script" json:"scripts"`
}

// State contains information about a given ports
// status. State will be open, closed, etc.
type State struct {
	State     string  `xml:"state,attr" json:"state"`
	Reason    string  `xml:"reason,attr" json:"reason"`
	ReasonTTL float32 `xml:"reason_ttl,attr" json:"reason_ttl"`
	ReasonIP  string  `xml:"reason_ip,attr" json:"reason_ip"`
}

// Owner contains the name of Port.Owner.
type Owner struct {
	Name string `xml:"name,attr" json:"name"`
}

// Service contains detailed information about a Port's
// service details.
type Service struct {
	Name       string `xml:"name,attr" json:"name"`
	Conf       int    `xml:"conf,attr" json:"conf"`
	Method     string `xml:"method,attr" json:"method"`
	Version    string `xml:"version,attr" json:"version"`
	Product    string `xml:"product,attr" json:"product"`
	ExtraInfo  string `xml:"extrainfo,attr" json:"extrainfo"`
	Tunnel     string `xml:"tunnel,attr" json:"tunnel"`
	Proto      string `xml:"proto,attr" json:"proto"`
	Rpcnum     string `xml:"rpcnum,attr" json:"rpcnum"`
	Lowver     string `xml:"lowver,attr" json:"lowver"`
	Highver    string `xml:"hiver,attr" json:"hiver"`
	Hostname   string `xml:"hostname,attr" json:"hostname"`
	OsType     string `xml:"ostype,attr" json:"ostype"`
	DeviceType string `xml:"devicetype,attr" json:"devicetype"`
	ServiceFp  string `xml:"servicefp,attr" json:"servicefp"`
	CPEs       []CPE  `xml:"cpe" json:"cpes"`
}

// CPE (Common Platform Enumeration) is a standardized way to name software
// applications, operating systems, and hardware platforms.
type CPE string

// Script contains information from Nmap Scripting Engine.
type Script struct {
	Id     string  `xml:"id,attr" json:"id"`
	Output string  `xml:"output,attr" json:"output"`
	Tables []Table `xml:"table" json:"tables"`
}

// Table contains the output of the script in a more parse-able form.
// ToDo: This should be a map[string][]string
type Table struct {
	Key      string   `xml:"key,attr" json:"key"`
	Elements []string `xml:"elem" json:"elements"`
}

// Os contains the fingerprinted operating system for a Host.
type Os struct {
	PortsUsed      []PortUsed      `xml:"portused" json:"portsused"`
	OsMatches      []OsMatch       `xml:"osmatch" json:"osmatches"`
	OsFingerprints []OsFingerprint `xml:"osfingerprint" json:"osfingerprints"`
}

// PortsUsed is the port used to fingerprint a Os.
type PortUsed struct {
	State  string `xml:"state,attr" json:"state"`
	Proto  string `xml:"proto,attr" json:"proto"`
	PortId int    `xml:"portid,attr" json:"portid"`
}

// OsClass contains vendor information for an Os.
type OsClass struct {
	Vendor   string `xml:"vendor,attr" json:"vendor"`
	OsGen    string `xml"osgen,attr"`
	Type     string `xml:"type,attr" json:"type"`
	Accuracy string `xml:"accurancy,attr" json:"accurancy"`
	OsFamily string `xml:"osfamily,attr" json:"osfamily"`
	CPEs     []CPE  `xml:"cpe" json:"cpes"`
}

// OsMatch contains detailed information regarding a Os fingerprint.
type OsMatch struct {
	Name      string    `xml:"name,attr" json:"name"`
	Accuracy  string    `xml:"accuracy,attr" json:"accuracy"`
	Line      string    `xml:"line,attr" json:"line"`
	OsClasses []OsClass `xml:"osclass" json:"osclasses"`
}

// OsFingerprint is the actual fingerprint string.
type OsFingerprint struct {
	Fingerprint string `xml:"fingerprint,attr" json:"fingerprint"`
}

// Distance is the amount of hops to a particular host.
type Distance struct {
	Value int `xml:"value,attr" json:"value"`
}

// Uptime is the amount of time the host has been up.
type Uptime struct {
	Seconds  int    `xml:"seconds,attr" json:"seconds"`
	Lastboot string `xml:"lastboot,attr" json:"lastboot"`
}

// TcpSequence contains information regarding the detected tcp sequence.
type TcpSequence struct {
	Index      int    `xml:"index,attr" json:"index"`
	Difficulty string `xml:"difficulty,attr" json:"difficulty"`
	Values     string `xml:"vaules,attr" json:"vaules"`
}

// Sequence contains information regarding the detected X sequence.
type Sequence struct {
	Class  string `xml:"class,attr" json:"class"`
	Values string `xml:"values,attr" json:"values"`
}
type IpIdSequence Sequence
type TcpTsSequence Sequence

// Trace contains the hops to a Host.
type Trace struct {
	Proto string `xml:"proto,attr" json:"proto"`
	Port  int    `xml:"port,attr" json:"port"`
	Hops  []Hop  `xml:"hop" json:"hops"`
}

// Hop is a ip hop to a Host.
type Hop struct {
	TTL    float32 `xml:"ttl,attr" json:"ttl"`
	RTT    float32 `xml:"rtt,attr" json:"rtt"`
	IPAddr string  `xml:"ipaddr,attr" json:"ipaddr"`
	Host   string  `xml:"host,attr" json:"host"`
}

// Times contains time statistics for an Nmap scan.
type Times struct {
	SRTT string `xml:"srtt,attr" json:"srtt"`
	RTT  string `xml:"rttvar,attr" json:"rttv"`
	To   string `xml:"to,attr" json:"to"`
}

// RunStats contains statistics for a
// finished Nmap scan.
type RunStats struct {
	Finished Finished  `xml:"finished" json:"finished"`
	Hosts    HostStats `xml:"hosts" json:"hosts"`
}

// Finished contains detailed statistics regarding
// a finished Nmap scan.
type Finished struct {
	Time     Timestamp `xml:"time,attr" json:"time"`
	TimeStr  string    `xml:"timestr,attr" json:"timestr"`
	Elapsed  float32   `xml:"elapsed,attr" json:"elapsed"`
	Summary  string    `xml:"summary,attr" json:"summary"`
	Exit     string    `xml:"exit,attr" json:"exit"`
	ErrorMsg string    `xml:"errormsg,attr" json:"errormsg"`
}

// HostStats contains the amount of up and down hosts and the total count.
type HostStats struct {
	Up    int `xml:"up,attr" json:"up"`
	Down  int `xml:"down,attr" json:"down"`
	Total int `xml:"total,attr" json:"total"`
}

// Parse takes a byte array of nmap xml data and unmarshals it into an
// NmapRun struct. All elements are returned as strings, it is up to the caller
// to check and cast them to the proper type.
func Parse(content []byte) (*NmapRun, error) {
	r := &NmapRun{}
	err := xml.Unmarshal(content, r)
	if err != nil {
		return r, err
	}
	return r, nil
}
<commit_msg>Simplified the Timestamp type.<commit_after>/*Package nmap parses Nmap XML data into a similary formed struct.*/
package nmap

import (
	"encoding/xml"
	"fmt"
	"strconv"
	"time"
)

type Timestamp time.Time

// str2time converts a string containing a UNIX timestamp to to a time.Time.
func (t Timestamp) str2time(s string) (err error) {
	ts, err := strconv.Atoi(string(s))
	if err != nil {
		return
	}
	t = Timestamp(time.Unix(int64(ts), 0))
	return
}

// time2str formats the time.Time value as a UNIX timestamp string.
func (t Timestamp) time2str() string {
	return fmt.Sprint(time.Time(t).Unix())
}

func (t Timestamp) MarshalJSON() ([]byte, error) {
	return []byte(t.time2str()), nil
}

func (t Timestamp) UnmarshalJSON(b []byte) error {
	return t.str2time(string(b))
}

func (t Timestamp) MarshalXMLAttr(name xml.Name) (xml.Attr, error) {
	return xml.Attr{Name: name, Value: t.time2str()}, nil
}

func (t Timestamp) UnmarshalXMLAttr(attr xml.Attr) (err error) {
	return t.str2time(attr.Value)
}

// NmapRun is contains all the data for a single nmap scan.
type NmapRun struct {
	Scanner          string         `xml:"scanner,attr" json:"scanner"`
	Args             string         `xml:"args,attr" json:"args"`
	Start            Timestamp      `xml:"start,attr" json:"start"`
	StartStr         string         `xml:"startstr,attr" json:"startstr"`
	Version          string         `xml:"version,attr" json:"version"`
	ProfileName      string         `xml:"profile_name,attr" json:"profile_name"`
	XMLOutputVersion string         `xml:"xmloutputversion,attr" json:"xmloutputversion"`
	ScanInfo         ScanInfo       `xml:"scaninfo" json:"scaninfo"`
	Verbose          Verbose        `xml:"verbose" json:"verbose"`
	Debugging        Debugging      `xml:"debugging" json:"debugging"`
	TaskBegin        []Task         `xml:"taskbegin" json:"taskbegin"`
	TaskProgress     []TaskProgress `xml:"taskprogress" json:"taskprogress"`
	TaskEnd          []Task         `xml:"taskend" json:"taskend"`
	PreScripts       []Script       `xml:"prescript>script" json:"prescripts"`
	PostScripts      []Script       `xml:"postscript>script" json:"postscripts"`
	Hosts            []Host         `xml:"host" json:"hosts"`
	Targets          []Target       `xml:"target" json:"targets"`
	RunStats         RunStats       `xml:"runstats" json:"runstats"`
}

// ScanInfo contains informational regarding how the scan
// was run.
type ScanInfo struct {
	Type        string `xml:"type,attr" json:"type"`
	Protocol    string `xml:"protocol,attr" json:"protocol"`
	NumServices int    `xml:"numservices,attr" json:"numservices"`
	Services    string `xml:"services,attr" json:"services"`
	ScanFlags   string `xml:"scanflags,attr" json:"scanflags"`
}

// Verbose contains the verbosity level for the Nmap scan.
type Verbose struct {
	Level int `xml:"level,attr" json:"level"`
}

// Debugging contains the debugging level for the Nmap scan.
type Debugging struct {
	Level int `xml:"level,attr" json:"level"`
}

// Task contains information about started and stopped Nmap tasks.
type Task struct {
	Task      string    `xml:"task,attr" json:"task"`
	Time      Timestamp `xml:"time,attr" json:"time"`
	ExtraInfo string    `xml:"extrainfo,attr" json:"extrainfo"`
}

// TaskProgress contains information about the progression of a Task.
type TaskProgress struct {
	Task      string    `xml:"task,attr" json:"task"`
	Time      Timestamp `xml:"time,attr" json:"time"`
	Percent   float32   `xml:"percent,attr" json:"percent"`
	Remaining int       `xml:"remaining,attr" json:"remaining"`
	Etc       Timestamp `xml:"etc,attr" json:"etc"`
}

// Target is found in the Nmap xml spec. I have no idea what it
// actually is.
type Target struct {
	Specification string `xml:"specification,attr" json:"specification"`
	Status        string `xml:"status,attr" json:"status"`
	Reason        string `xml:"reason,attr" json:"reason"`
}

// Host contains all information about a single host.
type Host struct {
	StartTime     Timestamp     `xml:"starttime,attr" json:"starttime"`
	EndTime       Timestamp     `xml:"endtime,attr" json:"endtime"`
	Comment       string        `xml:"comment,attr" json:"comment"`
	Status        Status        `xml:"status" json:"status"`
	Addresses     []Address     `xml:"address" json:"addresses"`
	Hostnames     []Hostname    `xml:"hostnames>hostname" json:"hostnames"`
	Smurfs        []Smurf       `xml:"smurf" json:"smurfs"`
	Ports         []Port        `xml:"ports>port" json:"ports"`
	ExtraPorts    []ExtraPorts  `xml:"ports>extraports" json:"extraports"`
	Os            Os            `xml:"os" json:"os"`
	Distance      Distance      `xml:"distance" json:"distance"`
	Uptime        Uptime        `xml:"uptime" json:"uptime"`
	TcpSequence   TcpSequence   `xml:"tcpsequence" json:"tcpsequence"`
	IpIdSequence  IpIdSequence  `xml:"ipidsequence" json:"ipidsequence"`
	TcpTsSequence TcpTsSequence `xml:"tcptssequence" json:"tcptssequence"`
	HostScripts   []Script      `xml:"hostscript>script" json:"hostscripts"`
	Trace         Trace         `xml:"trace" json:"trace"`
}

// Status is the host's status. Up, down, etc.
type Status struct {
	State     string  `xml:"state,attr" json:"state"`
	Reason    string  `xml:"reason,attr" json:"reason"`
	ReasonTTL float32 `xml:"reason_ttl,attr" json:"reason_ttl"`
}

// Address contains a IPv4 or IPv6 address for a Host.
type Address struct {
	Addr     string `xml:"addr,attr" json:"addr"`
	AddrType string `xml:"addrtype,attr" json:"addrtype"`
	Vendor   string `xml:"vendor,attr" json:"vendor"`
}

// Hostname is a single name for a Host.
type Hostname struct {
	Name string `xml:"name,attr" json:"name"`
	Type string `xml:"type,attr" json:"type"`
}

// Smurf contains repsonses from a smurf attack. I think.
// Smurf attacks, really?
type Smurf struct {
	Responses string `xml:"responses,attr" json:"responses"`
}

// ExtraPorts contains the information about the closed|filtered ports.
type ExtraPorts struct {
	State   string   `xml:"state,attr" json:"state"`
	Count   int      `xml:"count,attr" json:"count"`
	Reasons []Reason `xml:"extrareasons" json:"reasons"`
}
type Reason struct {
	Reason string `xml:"reason,attr" json:"reason"`
	Count  int    `xml:"count,attr" json:"count"`
}

// Port contains all the information about a scanned port.
type Port struct {
	Protocol string   `xml:"protocol,attr" json:"protocol"`
	PortId   int      `xml:"portid,attr" json:"id"`
	State    State    `xml:"state" json:"state"`
	Owner    Owner    `xml:"owner" json:"owner"`
	Service  Service  `xml:"service" json:"service"`
	Scripts  []Script `xml:"script" json:"scripts"`
}

// State contains information about a given ports
// status. State will be open, closed, etc.
type State struct {
	State     string  `xml:"state,attr" json:"state"`
	Reason    string  `xml:"reason,attr" json:"reason"`
	ReasonTTL float32 `xml:"reason_ttl,attr" json:"reason_ttl"`
	ReasonIP  string  `xml:"reason_ip,attr" json:"reason_ip"`
}

// Owner contains the name of Port.Owner.
type Owner struct {
	Name string `xml:"name,attr" json:"name"`
}

// Service contains detailed information about a Port's
// service details.
type Service struct {
	Name       string `xml:"name,attr" json:"name"`
	Conf       int    `xml:"conf,attr" json:"conf"`
	Method     string `xml:"method,attr" json:"method"`
	Version    string `xml:"version,attr" json:"version"`
	Product    string `xml:"product,attr" json:"product"`
	ExtraInfo  string `xml:"extrainfo,attr" json:"extrainfo"`
	Tunnel     string `xml:"tunnel,attr" json:"tunnel"`
	Proto      string `xml:"proto,attr" json:"proto"`
	Rpcnum     string `xml:"rpcnum,attr" json:"rpcnum"`
	Lowver     string `xml:"lowver,attr" json:"lowver"`
	Highver    string `xml:"hiver,attr" json:"hiver"`
	Hostname   string `xml:"hostname,attr" json:"hostname"`
	OsType     string `xml:"ostype,attr" json:"ostype"`
	DeviceType string `xml:"devicetype,attr" json:"devicetype"`
	ServiceFp  string `xml:"servicefp,attr" json:"servicefp"`
	CPEs       []CPE  `xml:"cpe" json:"cpes"`
}

// CPE (Common Platform Enumeration) is a standardized way to name software
// applications, operating systems, and hardware platforms.
type CPE string

// Script contains information from Nmap Scripting Engine.
type Script struct {
	Id     string  `xml:"id,attr" json:"id"`
	Output string  `xml:"output,attr" json:"output"`
	Tables []Table `xml:"table" json:"tables"`
}

// Table contains the output of the script in a more parse-able form.
// ToDo: This should be a map[string][]string
type Table struct {
	Key      string   `xml:"key,attr" json:"key"`
	Elements []string `xml:"elem" json:"elements"`
}

// Os contains the fingerprinted operating system for a Host.
type Os struct {
	PortsUsed      []PortUsed      `xml:"portused" json:"portsused"`
	OsMatches      []OsMatch       `xml:"osmatch" json:"osmatches"`
	OsFingerprints []OsFingerprint `xml:"osfingerprint" json:"osfingerprints"`
}

// PortsUsed is the port used to fingerprint a Os.
type PortUsed struct {
	State  string `xml:"state,attr" json:"state"`
	Proto  string `xml:"proto,attr" json:"proto"`
	PortId int    `xml:"portid,attr" json:"portid"`
}

// OsClass contains vendor information for an Os.
type OsClass struct {
	Vendor   string `xml:"vendor,attr" json:"vendor"`
	OsGen    string `xml"osgen,attr"`
	Type     string `xml:"type,attr" json:"type"`
	Accuracy string `xml:"accurancy,attr" json:"accurancy"`
	OsFamily string `xml:"osfamily,attr" json:"osfamily"`
	CPEs     []CPE  `xml:"cpe" json:"cpes"`
}

// OsMatch contains detailed information regarding a Os fingerprint.
type OsMatch struct {
	Name      string    `xml:"name,attr" json:"name"`
	Accuracy  string    `xml:"accuracy,attr" json:"accuracy"`
	Line      string    `xml:"line,attr" json:"line"`
	OsClasses []OsClass `xml:"osclass" json:"osclasses"`
}

// OsFingerprint is the actual fingerprint string.
type OsFingerprint struct {
	Fingerprint string `xml:"fingerprint,attr" json:"fingerprint"`
}

// Distance is the amount of hops to a particular host.
type Distance struct {
	Value int `xml:"value,attr" json:"value"`
}

// Uptime is the amount of time the host has been up.
type Uptime struct {
	Seconds  int    `xml:"seconds,attr" json:"seconds"`
	Lastboot string `xml:"lastboot,attr" json:"lastboot"`
}

// TcpSequence contains information regarding the detected tcp sequence.
type TcpSequence struct {
	Index      int    `xml:"index,attr" json:"index"`
	Difficulty string `xml:"difficulty,attr" json:"difficulty"`
	Values     string `xml:"vaules,attr" json:"vaules"`
}

// Sequence contains information regarding the detected X sequence.
type Sequence struct {
	Class  string `xml:"class,attr" json:"class"`
	Values string `xml:"values,attr" json:"values"`
}
type IpIdSequence Sequence
type TcpTsSequence Sequence

// Trace contains the hops to a Host.
type Trace struct {
	Proto string `xml:"proto,attr" json:"proto"`
	Port  int    `xml:"port,attr" json:"port"`
	Hops  []Hop  `xml:"hop" json:"hops"`
}

// Hop is a ip hop to a Host.
type Hop struct {
	TTL    float32 `xml:"ttl,attr" json:"ttl"`
	RTT    float32 `xml:"rtt,attr" json:"rtt"`
	IPAddr string  `xml:"ipaddr,attr" json:"ipaddr"`
	Host   string  `xml:"host,attr" json:"host"`
}

// Times contains time statistics for an Nmap scan.
type Times struct {
	SRTT string `xml:"srtt,attr" json:"srtt"`
	RTT  string `xml:"rttvar,attr" json:"rttv"`
	To   string `xml:"to,attr" json:"to"`
}

// RunStats contains statistics for a
// finished Nmap scan.
type RunStats struct {
	Finished Finished  `xml:"finished" json:"finished"`
	Hosts    HostStats `xml:"hosts" json:"hosts"`
}

// Finished contains detailed statistics regarding
// a finished Nmap scan.
type Finished struct {
	Time     Timestamp `xml:"time,attr" json:"time"`
	TimeStr  string    `xml:"timestr,attr" json:"timestr"`
	Elapsed  float32   `xml:"elapsed,attr" json:"elapsed"`
	Summary  string    `xml:"summary,attr" json:"summary"`
	Exit     string    `xml:"exit,attr" json:"exit"`
	ErrorMsg string    `xml:"errormsg,attr" json:"errormsg"`
}

// HostStats contains the amount of up and down hosts and the total count.
type HostStats struct {
	Up    int `xml:"up,attr" json:"up"`
	Down  int `xml:"down,attr" json:"down"`
	Total int `xml:"total,attr" json:"total"`
}

// Parse takes a byte array of nmap xml data and unmarshals it into an
// NmapRun struct. All elements are returned as strings, it is up to the caller
// to check and cast them to the proper type.
func Parse(content []byte) (*NmapRun, error) {
	r := &NmapRun{}
	err := xml.Unmarshal(content, r)
	if err != nil {
		return r, err
	}
	return r, nil
}
<|endoftext|>


<commit_before>package berlingo

// Node represents a single node on the Map
type Node struct {
	Map                *Map
	Id                 int
	Type               *NodeType
	Paths_Outbound     map[int]*Node
	Paths_Inbound      map[int]*Node
	Player_Id          int
	Number_Of_Soldiers int
	Incoming_Soldiers  int
	Available_Soldiers int
}

func NewNode(m *Map) *Node {
	return &Node{
		Map:            m,
		Paths_Outbound: make(map[int]*Node),
		Paths_Inbound:  make(map[int]*Node),
	}
}

// Sets up a unidirectional link pointing from this node towards another
func (node *Node) link_to(other *Node) {
	node.Paths_Outbound[other.Id] = other
	other.Paths_Inbound[node.Id] = node
}

// IsFree returns whether the node is free, or owned by any player
func (node *Node) IsFree() bool {
	return node.Player_Id < 0
}

// IsOwned returns whether this node is owned by the current player
//
// Note - this deviates from the ruby client implementation, where ruby's owned? is essentially the opposite of free? - this is quite confusing as naturally asking a node.IsOwned() most likely indicates the caller wants to know if they own it themselves
//
// Callers who wish to mimick the owned? behavior of the ruby client may simply ask for !node.IsFree()
func (node *Node) IsOwned() bool {
	return node.IsOwnedBy(node.Map.Game.Player_Id)
}

func (node *Node) IsOwnedBy(player_id int) bool {
	return node.Player_Id == player_id
}

func (node *Node) IsEnemy() bool {
	return !node.IsFree() && !node.IsOwned()
}

func (node *Node) IsControlled() bool {
	return node.IsOwned() && node.Number_Of_Soldiers > 0
}

func (node *Node) reset() {
	node.Incoming_Soldiers = 0
	node.Available_Soldiers = 0
	if node.IsOwned() {
		node.Available_Soldiers = node.Number_Of_Soldiers
	}
}
<commit_msg>Insignificant<commit_after>package berlingo

// Node represents a single node on the Map
type Node struct {
	Map                *Map
	Id                 int
	Type               *NodeType
	Paths_Outbound     map[int]*Node
	Paths_Inbound      map[int]*Node
	Player_Id          int
	Number_Of_Soldiers int
	Incoming_Soldiers  int
	Available_Soldiers int
}

func NewNode(m *Map) *Node {
	return &Node{
		Map:            m,
		Paths_Outbound: make(map[int]*Node),
		Paths_Inbound:  make(map[int]*Node),
	}
}

// Sets up a unidirectional link pointing from this node towards another
func (node *Node) link_to(other *Node) {
	node.Paths_Outbound[other.Id] = other
	other.Paths_Inbound[node.Id] = node
}

func (node *Node) reset() {
	node.Incoming_Soldiers = 0
	node.Available_Soldiers = 0
	if node.IsOwned() {
		node.Available_Soldiers = node.Number_Of_Soldiers
	}
}

// IsFree returns whether the node is free, or owned by any player
func (node *Node) IsFree() bool {
	return node.Player_Id < 0
}

// IsOwned returns whether this node is owned by the current player
//
// Note - this deviates from the ruby client implementation, where ruby's owned? is essentially the opposite of free? - this is quite confusing as naturally asking a node.IsOwned() most likely indicates the caller wants to know if they own it themselves
//
// Callers who wish to mimick the owned? behavior of the ruby client may simply ask for !node.IsFree()
func (node *Node) IsOwned() bool {
	return node.IsOwnedBy(node.Map.Game.Player_Id)
}

func (node *Node) IsOwnedBy(player_id int) bool {
	return node.Player_Id == player_id
}

func (node *Node) IsEnemy() bool {
	return !node.IsFree() && !node.IsOwned()
}

func (node *Node) IsControlled() bool {
	return node.IsOwned() && node.Number_Of_Soldiers > 0
}
<|endoftext|>


<commit_before>/*
 * Copyright 2015 Xuyuan Pang
 * Author: Xuyuan Pang
 *
 * 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 hador

import (
	"fmt"
	"net/http"
)

type nodeType int

const (
	static nodeType = iota
	param
	matchAll
)

type node struct {
	segment    string
	indices    string
	children   []*node
	paramChild *node
	ntype      nodeType
	leaves     map[Method]*Leaf
}

func (n *node) AddRoute(method Method, pattern string, handler interface{}, filters ...Filter) *Leaf {
	if len(pattern) == 0 || pattern[0] != '/' {
		panic("pattern should start with '/', pattern: " + pattern)
	}
	if len(pattern) > 1 && pattern[len(pattern)-1] == '/' {
		pattern = pattern[:len(pattern)-1]
	}
	if handler == nil {
		panic("handler should NOT be nil")
	}
	for _, m := range Methods {
		if m == method {
			return n.addRoute(method, pattern, parseHandler(handler), filters...)
		}
	}
	panic("unknown method: " + method)
}

func min(first, second int) int {
	if first < second {
		return first
	}
	return second
}

func (n *node) addRoute(method Method, pattern string, handler Handler, filters ...Filter) *Leaf {
	if len(n.segment) == 0 {
		return n.init(method, pattern, handler, filters...)
	}

	if n.ntype == static {
		// find longest matched prefix
		max := min(len(n.segment), len(pattern))
		i := 0
		for i < max && pattern[i] == n.segment[i] {
			i++
		}
		n.splitAt(i)
		return n.insertChild(method, pattern[i:], handler, filters...)
	}

	if n.ntype == param {
		i, max := 0, len(pattern)
		for i < max && pattern[i] != '}' {
			i++
		}
		if i == max {
			panic("missing '}'")
		}
		if n.segment != pattern[:i+1] {
			panic("conflict param node")
		}
		if i < max-1 && pattern[i+1] != '/' {
			panic("'}' should be before '/'")
		}
		return n.insertChild(method, pattern[i+1:], handler, filters...)
	}
	return nil
}

func (n *node) splitAt(index int) {
	if index >= len(n.segment) {
		return
	}
	next := &node{
		segment:    n.segment[index:],
		indices:    n.indices,
		children:   n.children,
		leaves:     n.leaves,
		ntype:      n.ntype,
		paramChild: n.paramChild,
	}
	n.indices = n.segment[index : index+1]
	n.segment = n.segment[:index]
	n.children = []*node{next}
	n.paramChild = nil
	n.leaves = nil
}

func (n *node) insertChild(method Method, pattern string, handler Handler, filters ...Filter) *Leaf {
	if len(pattern) == 0 {
		return n.handle(method, handler, filters...)
	}
	if pattern[0] == '{' {
		return n.insertParamChild(method, pattern, handler, filters...)
	}
	return n.insertStaticChild(method, pattern, handler, filters...)
}

func (n *node) insertStaticChild(method Method, pattern string, handler Handler, filters ...Filter) *Leaf {
	for i, ind := range n.indices {
		if ind == rune(pattern[0]) {
			return n.children[i].addRoute(method, pattern, handler, filters...)
		}
	}
	n.indices += pattern[:1]
	child := &node{}
	n.children = append(n.children, child)
	return child.addRoute(method, pattern, handler, filters...)
}

func (n *node) insertParamChild(method Method, pattern string, handler Handler, filters ...Filter) *Leaf {
	if n.paramChild == nil {
		n.paramChild = &node{}
	}
	return n.paramChild.addRoute(method, pattern, handler, filters...)
}

func (n *node) init(method Method, pattern string, handler Handler, filters ...Filter) *Leaf {
	if pattern[0] == '{' {
		return n.initParam(method, pattern, handler, filters...)
	}
	return n.initStatic(method, pattern, handler, filters...)
}

func (n *node) initStatic(method Method, pattern string, handler Handler, filters ...Filter) *Leaf {
	i, max := 0, len(pattern)
	for i < max && pattern[i] != '{' {
		i++
	}
	if i < max && i > 0 && pattern[i-1] != '/' {
		panic("'{' should be after '/'")
	}

	n.segment = pattern[:i]
	n.ntype = static
	n.indices = ""
	n.children = nil
	n.leaves = nil
	return n.insertChild(method, pattern[i:], handler, filters...)
}

func (n *node) initParam(method Method, pattern string, handler Handler, filters ...Filter) *Leaf {
	i, max := 0, len(pattern)
	for i < max && pattern[i] != '}' {
		i++
	}
	if i == max {
		panic("missing '}'")
	}
	if i < max-1 && pattern[i+1] != '/' {
		panic("'}' should be before '/'")
	}
	n.ntype = param
	n.segment = pattern[:i+1]
	n.indices = ""
	n.children = nil
	n.leaves = nil
	return n.insertChild(method, pattern[i+1:], handler, filters...)
}

func (n *node) handle(method Method, handler Handler, filters ...Filter) *Leaf {
	if _, ok := n.leaves[method]; ok {
		panic("route has been registered")
	}
	l := NewLeaf(n, method, handler)
	if n.leaves == nil {
		n.leaves = make(map[Method]*Leaf)
	}
	n.leaves[method] = l
	l.AddFilters(filters...)
	return l
}

func (n *node) find(method Method, path string) *Leaf {
	switch n.ntype {
	case static:
		return n.findStatic(method, path)
	case param:
		return n.findParam(method, path)
	}
	return nil
}

func (n *node) findStatic(method Method, path string) *Leaf {
	if len(path) < len(n.segment) {
		return nil
	}
	if path == n.segment {
		if n.leaves != nil {
			return n.leaves[method]
		}
		return nil
	}
	if path[:len(n.segment)] != n.segment {
		return nil
	}
	c := path[len(n.segment)]
	for i, ind := range n.indices {
		if ind == rune(c) {
			return n.children[i].find(method, path[len(n.segment):])
		}
	}
	if n.paramChild != nil {
		return n.paramChild.find(method, path[len(n.segment):])
	}
	return nil
}

func (n *node) findParam(method Method, path string) *Leaf {
	i, max := 0, len(path)
	for i < max && path[i] != '/' {
		i++
	}
	if i == max {
		if n.leaves != nil {
			return n.leaves[method]
		}
		return nil
	}
	c := path[i]
	for index, ind := range n.indices {
		if ind == rune(c) {
			return n.children[index].find(method, path[i:])
		}
	}
	if n.paramChild != nil {
		return n.paramChild.find(method, path[i:])
	}
	return nil
}

func (n *node) Serve(ctx *Context) {
	// ctx.Logger.Debug("%s", ctx.Request.RequestURI)
	switch n.ntype {
	case static:
		n.serveStatic(ctx)
	case param:
		n.serveParam(ctx)
	}
}

func (n *node) serveParam(ctx *Context) {
	path := ctx.path
	i, max := 0, len(path)
	for i < max && path[i] != '/' {
		i++
	}
	if i == max {
		ctx.Params()[n.segment[1:len(n.segment)-1]] = path[:i]
		n.doServe(ctx)
		return
	}
	c := path[i]
	for index, ind := range n.indices {
		if ind == rune(c) {
			ctx.path = ctx.path[i:]
			ctx.Params()[n.segment[1:len(n.segment)-1]] = path[:i]
			n.children[index].Serve(ctx)
			return
		}
	}
	if n.paramChild != nil {
		ctx.path = ctx.path[1:]
		ctx.Params()[n.segment[1:len(n.segment)-1]] = path[:i]
		n.paramChild.Serve(ctx)
		return
	}
	return
}

func (n *node) serveStatic(ctx *Context) {
	path := ctx.path
	if len(path) < len(n.segment) {
		if n.paramChild != nil {
			n.paramChild.Serve(ctx)
			return
		}
		ctx.OnError(http.StatusNotFound)
		return
	}
	if path == n.segment {
		n.doServe(ctx)
		return
	}
	if path[:len(n.segment)] != n.segment {
		ctx.OnError(http.StatusNotFound)
		return
	}
	c := path[len(n.segment)]
	for i, ind := range n.indices {
		if ind == rune(c) {
			ctx.path = ctx.path[len(n.segment):]
			n.children[i].Serve(ctx)
			return
		}
	}
	if n.paramChild != nil {
		ctx.path = ctx.path[len(n.segment):]
		n.paramChild.Serve(ctx)
		return
	}
	ctx.OnError(http.StatusNotFound)
}

func (n *node) doServe(ctx *Context) {
	// 404 not found
	if len(n.leaves) == 0 {
		ctx.OnError(http.StatusNotFound)
		return
	}
	// method matches
	if l, ok := n.leaves[Method(ctx.Request.Method)]; ok {
		l.Serve(ctx)
		return
	}
	// 405 method not allowed
	methods := make([]Method, len(n.leaves))
	i := 0
	for m := range n.leaves {
		methods[i] = m
		i++
	}
	ctx.OnError(http.StatusMethodNotAllowed, methods)
}

func (n *node) travel(path string) {
	path += n.segment
	for m, _ := range n.leaves {
		fmt.Printf("%s %s\n", m, path)
	}

	for _, child := range n.children {
		child.travel(path)
	}
	if n.paramChild != nil {
		n.paramChild.travel(path)
	}
}
<commit_msg>Enhanced static routing speed<commit_after>/*
 * Copyright 2015 Xuyuan Pang
 * Author: Xuyuan Pang
 *
 * 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 hador

import (
	"fmt"
	"net/http"
)

type nodeType int

const (
	static nodeType = iota
	param
	matchAll
)

type node struct {
	segment    string
	indices    string
	children   []*node
	paramChild *node
	ntype      nodeType
	leaves     map[Method]*Leaf
}

func (n *node) AddRoute(method Method, pattern string, handler interface{}, filters ...Filter) *Leaf {
	if len(pattern) == 0 || pattern[0] != '/' {
		panic("pattern should start with '/', pattern: " + pattern)
	}
	if len(pattern) > 1 && pattern[len(pattern)-1] == '/' {
		pattern = pattern[:len(pattern)-1]
	}
	if handler == nil {
		panic("handler should NOT be nil")
	}
	for _, m := range Methods {
		if m == method {
			return n.addRoute(method, pattern, parseHandler(handler), filters...)
		}
	}
	panic("unknown method: " + method)
}

func min(first, second int) int {
	if first < second {
		return first
	}
	return second
}

func (n *node) addRoute(method Method, pattern string, handler Handler, filters ...Filter) *Leaf {
	if len(n.segment) == 0 {
		return n.init(method, pattern, handler, filters...)
	}

	if n.ntype == static {
		// find longest matched prefix
		max := min(len(n.segment), len(pattern))
		i := 0
		for i < max && pattern[i] == n.segment[i] {
			i++
		}
		n.splitAt(i)
		return n.insertChild(method, pattern[i:], handler, filters...)
	}

	if n.ntype == param {
		i, max := 0, len(pattern)
		for i < max && pattern[i] != '}' {
			i++
		}
		if i == max {
			panic("missing '}'")
		}
		if n.segment != pattern[:i+1] {
			panic("conflict param node")
		}
		if i < max-1 && pattern[i+1] != '/' {
			panic("'}' should be before '/'")
		}
		return n.insertChild(method, pattern[i+1:], handler, filters...)
	}
	return nil
}

func (n *node) splitAt(index int) {
	if index >= len(n.segment) {
		return
	}
	next := &node{
		segment:    n.segment[index:],
		indices:    n.indices,
		children:   n.children,
		leaves:     n.leaves,
		ntype:      n.ntype,
		paramChild: n.paramChild,
	}
	n.indices = n.segment[index : index+1]
	n.segment = n.segment[:index]
	n.children = []*node{next}
	n.paramChild = nil
	n.leaves = nil
}

func (n *node) insertChild(method Method, pattern string, handler Handler, filters ...Filter) *Leaf {
	if len(pattern) == 0 {
		return n.handle(method, handler, filters...)
	}
	if pattern[0] == '{' {
		return n.insertParamChild(method, pattern, handler, filters...)
	}
	return n.insertStaticChild(method, pattern, handler, filters...)
}

func (n *node) insertStaticChild(method Method, pattern string, handler Handler, filters ...Filter) *Leaf {
	for i, ind := range n.indices {
		if ind == rune(pattern[0]) {
			return n.children[i].addRoute(method, pattern, handler, filters...)
		}
	}
	n.indices += pattern[:1]
	child := &node{}
	n.children = append(n.children, child)
	return child.addRoute(method, pattern, handler, filters...)
}

func (n *node) insertParamChild(method Method, pattern string, handler Handler, filters ...Filter) *Leaf {
	if n.paramChild == nil {
		n.paramChild = &node{}
	}
	return n.paramChild.addRoute(method, pattern, handler, filters...)
}

func (n *node) init(method Method, pattern string, handler Handler, filters ...Filter) *Leaf {
	if pattern[0] == '{' {
		return n.initParam(method, pattern, handler, filters...)
	}
	return n.initStatic(method, pattern, handler, filters...)
}

func (n *node) initStatic(method Method, pattern string, handler Handler, filters ...Filter) *Leaf {
	i, max := 0, len(pattern)
	for i < max && pattern[i] != '{' {
		i++
	}
	if i < max && i > 0 && pattern[i-1] != '/' {
		panic("'{' should be after '/'")
	}

	n.segment = pattern[:i]
	n.ntype = static
	n.indices = ""
	n.children = nil
	n.leaves = nil
	return n.insertChild(method, pattern[i:], handler, filters...)
}

func (n *node) initParam(method Method, pattern string, handler Handler, filters ...Filter) *Leaf {
	i, max := 0, len(pattern)
	for i < max && pattern[i] != '}' {
		i++
	}
	if i == max {
		panic("missing '}'")
	}
	if i < max-1 && pattern[i+1] != '/' {
		panic("'}' should be before '/'")
	}
	n.ntype = param
	n.segment = pattern[:i+1]
	n.indices = ""
	n.children = nil
	n.leaves = nil
	return n.insertChild(method, pattern[i+1:], handler, filters...)
}

func (n *node) handle(method Method, handler Handler, filters ...Filter) *Leaf {
	if _, ok := n.leaves[method]; ok {
		panic("route has been registered")
	}
	l := NewLeaf(n, method, handler)
	if n.leaves == nil {
		n.leaves = make(map[Method]*Leaf)
	}
	n.leaves[method] = l
	l.AddFilters(filters...)
	return l
}

func (n *node) find(method Method, path string) *Leaf {
	switch n.ntype {
	case static:
		return n.findStatic(method, path)
	case param:
		return n.findParam(method, path)
	}
	return nil
}

func (n *node) findStatic(method Method, path string) *Leaf {
	if len(path) < len(n.segment) {
		return nil
	}
	if path == n.segment {
		if n.leaves != nil {
			return n.leaves[method]
		}
		return nil
	}
	if path[:len(n.segment)] != n.segment {
		return nil
	}
	c := path[len(n.segment)]
	for i, ind := range n.indices {
		if ind == rune(c) {
			return n.children[i].find(method, path[len(n.segment):])
		}
	}
	if n.paramChild != nil {
		return n.paramChild.find(method, path[len(n.segment):])
	}
	return nil
}

func (n *node) findParam(method Method, path string) *Leaf {
	i, max := 0, len(path)
	for i < max && path[i] != '/' {
		i++
	}
	if i == max {
		if n.leaves != nil {
			return n.leaves[method]
		}
		return nil
	}
	c := path[i]
	for index, ind := range n.indices {
		if ind == rune(c) {
			return n.children[index].find(method, path[i:])
		}
	}
	if n.paramChild != nil {
		return n.paramChild.find(method, path[i:])
	}
	return nil
}

func (n *node) Serve(ctx *Context) {
	// ctx.Logger.Debug("%s", ctx.Request.RequestURI)
	switch n.ntype {
	case static:
		n.serveStatic(ctx)
	case param:
		n.serveParam(ctx)
	}
}

func (n *node) serveParam(ctx *Context) {
	path := ctx.path
	i, max := 0, len(path)
	for i < max && path[i] != '/' {
		i++
	}
	if i == max {
		ctx.Params()[n.segment[1:len(n.segment)-1]] = path[:i]
		n.doServe(ctx)
		return
	}
	c := path[i]
	for index, ind := range n.indices {
		if ind == rune(c) {
			ctx.path = ctx.path[i:]
			ctx.Params()[n.segment[1:len(n.segment)-1]] = path[:i]
			n.children[index].Serve(ctx)
			return
		}
	}
	if n.paramChild != nil {
		ctx.path = ctx.path[1:]
		ctx.Params()[n.segment[1:len(n.segment)-1]] = path[:i]
		n.paramChild.Serve(ctx)
		return
	}
	return
}

func (n *node) serveStatic(ctx *Context) {
	path := ctx.path
	if len(path) < len(n.segment) {
		ctx.OnError(http.StatusNotFound)
		return
	}
	i, seglen := 0, len(n.segment)
	for i < seglen && n.segment[i] == path[i] {
		i++
	}
	if i < seglen {
		ctx.OnError(http.StatusNotFound)
		return
	}
	if i == len(path) {
		n.doServe(ctx)
		return
	}
	c := path[seglen]
	for index, ind := range n.indices {
		if ind == rune(c) {
			ctx.path = ctx.path[seglen:]
			n.children[index].Serve(ctx)
			return
		}
	}
	if n.paramChild != nil {
		ctx.path = ctx.path[len(n.segment):]
		n.paramChild.Serve(ctx)
		return
	}
	ctx.OnError(http.StatusNotFound)
}

func (n *node) doServe(ctx *Context) {
	// 404 not found
	if len(n.leaves) == 0 {
		ctx.OnError(http.StatusNotFound)
		return
	}
	// method matches
	if l, ok := n.leaves[Method(ctx.Request.Method)]; ok {
		l.Serve(ctx)
		return
	}
	// 405 method not allowed
	methods := make([]Method, len(n.leaves))
	i := 0
	for m := range n.leaves {
		methods[i] = m
		i++
	}
	ctx.OnError(http.StatusMethodNotAllowed, methods)
}

func (n *node) travel(path string) {
	path += n.segment
	for m, _ := range n.leaves {
		fmt.Printf("%s %s\n", m, path)
	}

	for _, child := range n.children {
		child.travel(path)
	}
	if n.paramChild != nil {
		n.paramChild.travel(path)
	}
}
<|endoftext|>


<commit_before>package riakpbc

import (
	"bytes"
	"code.google.com/p/goprotobuf/proto"
	"encoding/binary"
	"io"
	"net"
	"sync"
	"time"
)

type Node struct {
	addr         string
	tcpAddr      *net.TCPAddr
	conn         *net.TCPConn
	readTimeout  time.Duration
	writeTimeout time.Duration
	errorRate    *Decaying
	ok           bool
	oklock       *sync.Mutex
	sync.Mutex
}

// Returns a new Node.
func NewNode(addr string, readTimeout, writeTimeout time.Duration) (*Node, error) {
	tcpaddr, err := net.ResolveTCPAddr("tcp", addr)
	if err != nil {
		return nil, err
	}

	node := &Node{
		addr:         addr,
		tcpAddr:      tcpaddr,
		readTimeout:  readTimeout,
		writeTimeout: writeTimeout,
		errorRate:    NewDecaying(),
		ok:           true,
		oklock:       &sync.Mutex{},
	}

	return node, nil
}

// Dial connects to a single riak node.
func (node *Node) Dial() (err error) {
	node.conn, err = net.DialTCP("tcp", nil, node.tcpAddr)
	if err != nil {
		return err
	}

	node.conn.SetKeepAlive(true)

	return nil
}

// ErrorRate safely returns the current Node's error rate.
func (node *Node) ErrorRate() float64 {
	return node.errorRate.Value()
}

// RecordError increments the current error value - see decaying.go
func (node *Node) RecordError(amount float64) {
	node.SetOk(false)
	node.errorRate.Add(amount)
}

func (node *Node) GetOk() bool {
	var out bool
	node.oklock.Lock()
	out = node.ok
	node.oklock.Unlock()
	return out
}

func (node *Node) SetOk(ok bool) {
	node.oklock.Lock()
	node.ok = ok
	node.oklock.Unlock()
}

func (node *Node) IsConnected() bool {
	return node.conn != nil
}

func (node *Node) ReqResp(reqstruct interface{}, structname string, raw bool) (response interface{}, err error) {
	node.Lock()
	defer node.Unlock()
	if node.IsConnected() != true {
		err = node.Dial()
		if err != nil {
			return nil, err
		}
	}
	if raw == true {
		err = node.rawRequest(reqstruct.([]byte), structname)
	} else {
		err = node.request(reqstruct, structname)
	}

	if err != nil {
		node.Close()
		return nil, err
	}

	response, err = node.response()
	if err != nil {
		node.Close()
		return nil, err
	}

	return
}

func (node *Node) ReqMultiResp(reqstruct interface{}, structname string) (response interface{}, err error) {
	response, err = node.ReqResp(reqstruct, structname, false)
	if err != nil {
		return nil, err
	}

	if structname == "RpbListKeysReq" {
		keys := response.(*RpbListKeysResp).GetKeys()
		done := response.(*RpbListKeysResp).GetDone()
		for done != true {
			response, err := node.response()
			if err != nil {
				return nil, err
			}
			keys = append(keys, response.(*RpbListKeysResp).GetKeys()...)
			done = response.(*RpbListKeysResp).GetDone()
		}
		return keys, nil
	} else if structname == "RpbMapRedReq" {
		mapResponse := response.(*RpbMapRedResp).GetResponse()
		done := response.(*RpbMapRedResp).GetDone()
		for done != true {
			response, err := node.response()
			if err != nil {
				return nil, err
			}
			mapResponse = append(mapResponse, response.(*RpbMapRedResp).GetResponse()...)
			done = response.(*RpbMapRedResp).GetDone()
		}
		return mapResponse, nil
	}
	return nil, nil
}

func (node *Node) Ping() bool {
	resp, err := node.ReqResp([]byte{}, "RpbPingReq", true)
	if err != nil {
		return false
	}
	if resp == nil || string(resp.([]byte)) != "Pong" {
		return false
	}
	return true
}

// Close the connection
func (node *Node) Close() {
	node.conn.Close()
	node.conn = nil
}

func (node *Node) read() (respraw []byte, err error) {
	node.conn.SetReadDeadline(time.Now().Add(node.readTimeout))

	buf := make([]byte, 4)
	var size int32

	// First 4 bytes are always size of message.
	n, err := io.ReadFull(node.conn, buf)
	if err != nil {
		node.RecordError(1.0)
		return nil, err
	}

	if n == 4 {
		sbuf := bytes.NewBuffer(buf)
		binary.Read(sbuf, binary.BigEndian, &size)
		data := make([]byte, size)
		// read rest of message
		m, err := io.ReadFull(node.conn, data)
		if err != nil {
			node.RecordError(1.0)
			return nil, err
		}
		if m == int(size) {
			return data, nil // return message
		}
	}

	node.RecordError(1.0)
	return nil, nil
}

func (node *Node) response() (response interface{}, err error) {
	rawresp, err := node.read()
	if err != nil {
		return nil, err
	}

	err = validateResponseHeader(rawresp)
	if err != nil {
		node.RecordError(1.0)
		return nil, err
	}

	response, err = unmarshalResponse(rawresp)
	if response == nil || err != nil {
		if err.Error() == "object not found" {
			return nil, err
		}
		return nil, err
	}

	return response, nil
}

func (node *Node) write(formattedRequest []byte) (err error) {
	node.conn.SetWriteDeadline(time.Now().Add(node.writeTimeout))

	_, err = node.conn.Write(formattedRequest)
	if err != nil {
		node.RecordError(1.0)
		return err
	}

	return nil
}

func (node *Node) request(reqstruct interface{}, structname string) (err error) {
	marshaledRequest, err := proto.Marshal(reqstruct.(proto.Message))
	if err != nil {
		return err
	}

	err = node.rawRequest(marshaledRequest, structname)
	if err != nil {
		return err
	}

	return
}

func (node *Node) rawRequest(marshaledRequest []byte, structname string) (err error) {
	formattedRequest, err := prependRequestHeader(structname, marshaledRequest)
	if err != nil {
		return err
	}

	err = node.write(formattedRequest)
	if err != nil {
		return err
	}
	return
}
<commit_msg>Fix null pointer dereference when server goes away<commit_after>package riakpbc

import (
	"bytes"
	"code.google.com/p/goprotobuf/proto"
	"encoding/binary"
	"io"
	"net"
	"sync"
	"time"
)

type Node struct {
	addr         string
	tcpAddr      *net.TCPAddr
	conn         *net.TCPConn
	readTimeout  time.Duration
	writeTimeout time.Duration
	errorRate    *Decaying
	ok           bool
	oklock       *sync.Mutex
	sync.Mutex
}

// Returns a new Node.
func NewNode(addr string, readTimeout, writeTimeout time.Duration) (*Node, error) {
	tcpaddr, err := net.ResolveTCPAddr("tcp", addr)
	if err != nil {
		return nil, err
	}

	node := &Node{
		addr:         addr,
		tcpAddr:      tcpaddr,
		readTimeout:  readTimeout,
		writeTimeout: writeTimeout,
		errorRate:    NewDecaying(),
		ok:           true,
		oklock:       &sync.Mutex{},
	}

	return node, nil
}

// Dial connects to a single riak node.
func (node *Node) Dial() (err error) {
	node.conn, err = net.DialTCP("tcp", nil, node.tcpAddr)
	if err != nil {
		return err
	}

	node.conn.SetKeepAlive(true)

	return nil
}

// ErrorRate safely returns the current Node's error rate.
func (node *Node) ErrorRate() float64 {
	return node.errorRate.Value()
}

// RecordError increments the current error value - see decaying.go
func (node *Node) RecordError(amount float64) {
	node.SetOk(false)
	node.errorRate.Add(amount)
}

func (node *Node) GetOk() bool {
	var out bool
	node.oklock.Lock()
	out = node.ok
	node.oklock.Unlock()
	return out
}

func (node *Node) SetOk(ok bool) {
	node.oklock.Lock()
	node.ok = ok
	node.oklock.Unlock()
}

func (node *Node) IsConnected() bool {
	return node.conn != nil
}

func (node *Node) ReqResp(reqstruct interface{}, structname string, raw bool) (response interface{}, err error) {
	node.Lock()
	defer node.Unlock()
	if node.IsConnected() != true {
		err = node.Dial()
		if err != nil {
			return nil, err
		}
	}
	if raw == true {
		err = node.rawRequest(reqstruct.([]byte), structname)
	} else {
		err = node.request(reqstruct, structname)
	}

	if err != nil {
		node.Close()
		return nil, err
	}

	response, err = node.response()
	if err != nil {
		node.Close()
		return nil, err
	}

	return
}

func (node *Node) ReqMultiResp(reqstruct interface{}, structname string) (response interface{}, err error) {
	response, err = node.ReqResp(reqstruct, structname, false)
	if err != nil {
		return nil, err
	}

	if structname == "RpbListKeysReq" {
		keys := response.(*RpbListKeysResp).GetKeys()
		done := response.(*RpbListKeysResp).GetDone()
		for done != true {
			response, err := node.response()
			if err != nil {
				return nil, err
			}
			keys = append(keys, response.(*RpbListKeysResp).GetKeys()...)
			done = response.(*RpbListKeysResp).GetDone()
		}
		return keys, nil
	} else if structname == "RpbMapRedReq" {
		mapResponse := response.(*RpbMapRedResp).GetResponse()
		done := response.(*RpbMapRedResp).GetDone()
		for done != true {
			response, err := node.response()
			if err != nil {
				return nil, err
			}
			mapResponse = append(mapResponse, response.(*RpbMapRedResp).GetResponse()...)
			done = response.(*RpbMapRedResp).GetDone()
		}
		return mapResponse, nil
	}
	return nil, nil
}

func (node *Node) Ping() bool {
	resp, err := node.ReqResp([]byte{}, "RpbPingReq", true)
	if err != nil {
		return false
	}
	if resp == nil || string(resp.([]byte)) != "Pong" {
		return false
	}
	return true
}

// Close the connection
func (node *Node) Close() {
	if node.conn != nil {
		node.conn.Close()
	}

	node.conn = nil
}

func (node *Node) read() (respraw []byte, err error) {
	node.conn.SetReadDeadline(time.Now().Add(node.readTimeout))

	buf := make([]byte, 4)
	var size int32

	// First 4 bytes are always size of message.
	n, err := io.ReadFull(node.conn, buf)
	if err != nil {
		node.RecordError(1.0)
		return nil, err
	}

	if n == 4 {
		sbuf := bytes.NewBuffer(buf)
		binary.Read(sbuf, binary.BigEndian, &size)
		data := make([]byte, size)
		// read rest of message
		m, err := io.ReadFull(node.conn, data)
		if err != nil {
			node.RecordError(1.0)
			return nil, err
		}
		if m == int(size) {
			return data, nil // return message
		}
	}

	node.RecordError(1.0)
	return nil, nil
}

func (node *Node) response() (response interface{}, err error) {
	rawresp, err := node.read()
	if err != nil {
		return nil, err
	}

	err = validateResponseHeader(rawresp)
	if err != nil {
		node.RecordError(1.0)
		return nil, err
	}

	response, err = unmarshalResponse(rawresp)
	if response == nil || err != nil {
		if err.Error() == "object not found" {
			return nil, err
		}
		return nil, err
	}

	return response, nil
}

func (node *Node) write(formattedRequest []byte) (err error) {
	node.conn.SetWriteDeadline(time.Now().Add(node.writeTimeout))

	_, err = node.conn.Write(formattedRequest)
	if err != nil {
		node.RecordError(1.0)
		return err
	}

	return nil
}

func (node *Node) request(reqstruct interface{}, structname string) (err error) {
	marshaledRequest, err := proto.Marshal(reqstruct.(proto.Message))
	if err != nil {
		return err
	}

	err = node.rawRequest(marshaledRequest, structname)
	if err != nil {
		return err
	}

	return
}

func (node *Node) rawRequest(marshaledRequest []byte, structname string) (err error) {
	formattedRequest, err := prependRequestHeader(structname, marshaledRequest)
	if err != nil {
		return err
	}

	err = node.write(formattedRequest)
	if err != nil {
		return err
	}
	return
}
<|endoftext|>


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

package flowcontrol

import (
	"bytes"
	"crypto/rand"
	"fmt"
	"io"
	"net"
	"sync"
	"testing"
	"time"

	"v.io/v23/context"
	"v.io/v23/verror"
	"v.io/x/ref/test"
)

var testdata = make([]byte, 1<<20)

func init() {
	test.Init()
	_, err := io.ReadFull(rand.Reader, testdata)
	if err != nil {
		panic(err)
	}
}

func TestFlowControl(t *testing.T) {
	const (
		workers  = 10
		messages = 10
	)

	msgs := make(map[int][]byte)
	fc := New(256, 64)

	ctx, cancel := context.RootContext()
	defer cancel()

	var wg sync.WaitGroup
	wg.Add(workers)
	for i := 0; i < workers; i++ {
		go func(idx int) {
			el := fc.NewWorker(fmt.Sprintf("%d", idx), 0)
			go el.Release(ctx, messages*5) // Try to make races happen
			j := 0
			el.Run(ctx, func(tokens int) (used int, done bool, err error) {
				msgs[idx] = append(msgs[idx], []byte(fmt.Sprintf("%d-%d,", idx, j))...)
				j++
				return 3, j >= messages, nil
			})
			wg.Done()
		}(i)
	}
	wg.Wait()

	for i := 0; i < workers; i++ {
		buf := &bytes.Buffer{}
		for j := 0; j < messages; j++ {
			fmt.Fprintf(buf, "%d-%d,", i, j)
		}
		if want, got := buf.String(), string(msgs[i]); want != got {
			t.Errorf("Got %s, want %s for %d", got, want, i)
		}
	}
}

func expect(t *testing.T, work chan interface{}, values ...interface{}) {
	for i, w := range values {
		if got := <-work; got != w {
			t.Errorf("expected %p in pos %d got %p", w, i, got)
		}
	}
}

func TestOrdering(t *testing.T) {
	const mtu = 10

	ctx, cancel := context.RootContext()
	defer cancel()
	fc := New(0, mtu)

	work := make(chan interface{})
	worker := func(p int) *Worker {
		w := fc.NewWorker(fmt.Sprintf("%d", p), p)
		go w.Run(ctx, func(t int) (int, bool, error) {
			work <- w
			return t, false, nil
		})
		w.Release(ctx, mtu)
		<-work
		return w
	}

	w0 := worker(0)
	w1a := worker(1)
	w1b := worker(1)
	w1c := worker(1)
	w2 := worker(2)

	// Release to all the flows at once and ensure the writes
	// happen in the correct order.
	fc.Release(ctx, []Release{{w0, 2 * mtu}, {w1a, 2 * mtu}, {w1b, 3 * mtu}, {w1c, 0}, {w2, mtu}})
	expect(t, work, w0, w0, w1a, w1b, w1a, w1b, w1b, w2)
}

func TestSharedCounters(t *testing.T) {
	const (
		mtu    = 10
		shared = 2 * mtu
	)

	ctx, cancel := context.RootContext()
	defer cancel()

	fc := New(shared, mtu)

	work := make(chan interface{})

	worker := func(p int) *Worker {
		w := fc.NewWorker(fmt.Sprintf("%d", p), p)
		go w.Run(ctx, func(t int) (int, bool, error) {
			work <- w
			return t, false, nil
		})
		return w
	}

	// w0 should run twice on shared counters.
	w0 := worker(0)
	expect(t, work, w0, w0)

	w1 := worker(1)
	// Now Release to w0 which shouldn't allow it to run since it's just repaying, but
	// should allow w1 to run on the returned shared counters.
	w0.Release(ctx, 2*mtu)
	expect(t, work, w1, w1)

	// Releasing again will allow w0 to run.
	w0.Release(ctx, mtu)
	expect(t, work, w0)
}

func TestConcurrentRun(t *testing.T) {
	ctx, cancel := context.RootContext()
	defer cancel()
	const mtu = 10
	fc := New(mtu, mtu)

	ready, wait := make(chan struct{}), make(chan struct{})
	w := fc.NewWorker("", 0)
	go w.Run(ctx, func(t int) (int, bool, error) {
		close(ready)
		<-wait
		return t, true, nil
	})
	<-ready
	if err := w.Run(ctx, nil); verror.ErrorID(err) != ErrConcurrentRun.ID {
		t.Errorf("expected concurrent run error got: %v", err)
	}
	close(wait)
}

func TestNonFlowControlledRun(t *testing.T) {
	ctx, cancel := context.RootContext()
	defer cancel()
	const mtu = 10
	fc := New(0, mtu)

	work := make(chan interface{})
	ready, wait := make(chan struct{}), make(chan struct{})
	// Start one worker running
	go fc.Run(ctx, "0", 0, func(t int) (int, bool, error) {
		close(ready)
		<-wait
		return t, true, nil
	})
	<-ready
	// Now queue up sever workers and make sure they execute in order.
	go fc.Run(ctx, "2", 2, func(t int) (int, bool, error) {
		work <- "c"
		return t, true, nil
	})
	go fc.Run(ctx, "1", 1, func(t int) (int, bool, error) {
		work <- "b"
		return t, true, nil
	})
	go fc.Run(ctx, "0", 0, func(t int) (int, bool, error) {
		work <- "a"
		return t, true, nil
	})
	for fc.numActive() < 4 {
		time.Sleep(time.Millisecond)
	}
	close(wait)
	expect(t, work, "a", "b", "c")
}

func newNullConn(mtu int) net.Conn {
	ln, err := net.Listen("tcp", ":0")
	if err != nil {
		panic(err)
	}
	addr := ln.Addr()

	go func() {
		conn, err := ln.Accept()
		if err != nil {
			panic(err)
		}
		ln.Close()
		buf := make([]byte, mtu)
		for {
			_, err := conn.Read(buf)
			if err == io.EOF {
				break
			}
			if err != nil {
				panic(err)
			}
		}
		conn.Close()
	}()

	conn, err := net.Dial(addr.Network(), addr.String())
	if err != nil {
		panic(err)
	}
	return conn
}

func BenchmarkWithFlowControl(b *testing.B) {
	const (
		mtu     = 1 << 16
		shared  = 1 << 20
		workers = 100
	)
	ctx, cancel := context.RootContext()
	defer cancel()
	s := newNullConn(mtu)

	for n := 0; n < b.N; n++ {
		fc := New(shared, mtu)
		var wg sync.WaitGroup
		wg.Add(workers)
		for i := 0; i < workers; i++ {
			go func(idx int) {
				w := fc.NewWorker(fmt.Sprintf("%d", idx), 0)
				w.Release(ctx, len(testdata))
				t := testdata
				err := w.Run(ctx, func(tokens int) (used int, done bool, err error) {
					towrite := min(tokens, len(t))
					written, err := s.Write(t[:min(tokens, len(t))])
					t = t[written:]
					return towrite, len(t) == 0, err
				})
				if err != nil {
					panic(err)
				}
				wg.Done()
			}(i)
		}
		wg.Wait()
	}
	if err := s.Close(); err != nil {
		panic(err)
	}
}

func BenchmarkWithoutFlowControl(b *testing.B) {
	const (
		workers = 100
		mtu     = 1 << 16
	)
	s := newNullConn(mtu)
	for n := 0; n < b.N; n++ {
		for cursor := 0; cursor < len(testdata); cursor += mtu {
			for i := 0; i < workers; i++ {
				_, err := s.Write(testdata[cursor : cursor+mtu])
				if err != nil {
					panic(err)
				}
			}
		}
	}
	if err := s.Close(); err != nil {
		panic(err)
	}
}
<commit_msg>TBR: runtime/internal/flow/flowcontrol: Fix go bench.<commit_after>// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package flowcontrol

import (
	"bytes"
	"crypto/rand"
	"fmt"
	"io"
	"net"
	"sync"
	"testing"
	"time"

	"v.io/v23/context"
	"v.io/v23/verror"
	"v.io/x/ref/test"
)

var testdata = make([]byte, 1<<20)

func init() {
	test.Init()
	_, err := io.ReadFull(rand.Reader, testdata)
	if err != nil {
		panic(err)
	}
}

func TestFlowControl(t *testing.T) {
	const (
		workers  = 10
		messages = 10
	)

	msgs := make(map[int][]byte)
	fc := New(256, 64)

	ctx, cancel := context.RootContext()
	defer cancel()

	var wg sync.WaitGroup
	wg.Add(workers)
	for i := 0; i < workers; i++ {
		go func(idx int) {
			el := fc.NewWorker(fmt.Sprintf("%d", idx), 0)
			go el.Release(ctx, messages*5) // Try to make races happen
			j := 0
			el.Run(ctx, func(tokens int) (used int, done bool, err error) {
				msgs[idx] = append(msgs[idx], []byte(fmt.Sprintf("%d-%d,", idx, j))...)
				j++
				return 3, j >= messages, nil
			})
			wg.Done()
		}(i)
	}
	wg.Wait()

	for i := 0; i < workers; i++ {
		buf := &bytes.Buffer{}
		for j := 0; j < messages; j++ {
			fmt.Fprintf(buf, "%d-%d,", i, j)
		}
		if want, got := buf.String(), string(msgs[i]); want != got {
			t.Errorf("Got %s, want %s for %d", got, want, i)
		}
	}
}

func expect(t *testing.T, work chan interface{}, values ...interface{}) {
	for i, w := range values {
		if got := <-work; got != w {
			t.Errorf("expected %p in pos %d got %p", w, i, got)
		}
	}
}

func TestOrdering(t *testing.T) {
	const mtu = 10

	ctx, cancel := context.RootContext()
	defer cancel()
	fc := New(0, mtu)

	work := make(chan interface{})
	worker := func(p int) *Worker {
		w := fc.NewWorker(fmt.Sprintf("%d", p), p)
		go w.Run(ctx, func(t int) (int, bool, error) {
			work <- w
			return t, false, nil
		})
		w.Release(ctx, mtu)
		<-work
		return w
	}

	w0 := worker(0)
	w1a := worker(1)
	w1b := worker(1)
	w1c := worker(1)
	w2 := worker(2)

	// Release to all the flows at once and ensure the writes
	// happen in the correct order.
	fc.Release(ctx, []Release{{w0, 2 * mtu}, {w1a, 2 * mtu}, {w1b, 3 * mtu}, {w1c, 0}, {w2, mtu}})
	expect(t, work, w0, w0, w1a, w1b, w1a, w1b, w1b, w2)
}

func TestSharedCounters(t *testing.T) {
	const (
		mtu    = 10
		shared = 2 * mtu
	)

	ctx, cancel := context.RootContext()
	defer cancel()

	fc := New(shared, mtu)

	work := make(chan interface{})

	worker := func(p int) *Worker {
		w := fc.NewWorker(fmt.Sprintf("%d", p), p)
		go w.Run(ctx, func(t int) (int, bool, error) {
			work <- w
			return t, false, nil
		})
		return w
	}

	// w0 should run twice on shared counters.
	w0 := worker(0)
	expect(t, work, w0, w0)

	w1 := worker(1)
	// Now Release to w0 which shouldn't allow it to run since it's just repaying, but
	// should allow w1 to run on the returned shared counters.
	w0.Release(ctx, 2*mtu)
	expect(t, work, w1, w1)

	// Releasing again will allow w0 to run.
	w0.Release(ctx, mtu)
	expect(t, work, w0)
}

func TestConcurrentRun(t *testing.T) {
	ctx, cancel := context.RootContext()
	defer cancel()
	const mtu = 10
	fc := New(mtu, mtu)

	ready, wait := make(chan struct{}), make(chan struct{})
	w := fc.NewWorker("", 0)
	go w.Run(ctx, func(t int) (int, bool, error) {
		close(ready)
		<-wait
		return t, true, nil
	})
	<-ready
	if err := w.Run(ctx, nil); verror.ErrorID(err) != ErrConcurrentRun.ID {
		t.Errorf("expected concurrent run error got: %v", err)
	}
	close(wait)
}

func TestNonFlowControlledRun(t *testing.T) {
	ctx, cancel := context.RootContext()
	defer cancel()
	const mtu = 10
	fc := New(0, mtu)

	work := make(chan interface{})
	ready, wait := make(chan struct{}), make(chan struct{})
	// Start one worker running
	go fc.Run(ctx, "0", 0, func(t int) (int, bool, error) {
		close(ready)
		<-wait
		return t, true, nil
	})
	<-ready
	// Now queue up sever workers and make sure they execute in order.
	go fc.Run(ctx, "2", 2, func(t int) (int, bool, error) {
		work <- "c"
		return t, true, nil
	})
	go fc.Run(ctx, "1", 1, func(t int) (int, bool, error) {
		work <- "b"
		return t, true, nil
	})
	go fc.Run(ctx, "0", 0, func(t int) (int, bool, error) {
		work <- "a"
		return t, true, nil
	})
	for fc.numActive() < 4 {
		time.Sleep(time.Millisecond)
	}
	close(wait)
	expect(t, work, "a", "b", "c")
}

func newNullConn(mtu int) net.Conn {
	ln, err := net.Listen("tcp", "127.0.0.1:0")
	if err != nil {
		panic(err)
	}
	addr := ln.Addr()

	go func() {
		conn, err := ln.Accept()
		if err != nil {
			panic(err)
		}
		ln.Close()
		buf := make([]byte, mtu)
		for {
			_, err := conn.Read(buf)
			if err == io.EOF {
				break
			}
			if err != nil {
				panic(err)
			}
		}
		conn.Close()
	}()

	conn, err := net.Dial(addr.Network(), addr.String())
	if err != nil {
		panic(err)
	}
	return conn
}

func BenchmarkWithFlowControl(b *testing.B) {
	const (
		mtu     = 1 << 16
		shared  = 1 << 20
		workers = 100
	)
	ctx, cancel := context.RootContext()
	defer cancel()
	s := newNullConn(mtu)

	for n := 0; n < b.N; n++ {
		fc := New(shared, mtu)
		var wg sync.WaitGroup
		wg.Add(workers)
		for i := 0; i < workers; i++ {
			go func(idx int) {
				w := fc.NewWorker(fmt.Sprintf("%d", idx), 0)
				w.Release(ctx, len(testdata))
				t := testdata
				err := w.Run(ctx, func(tokens int) (used int, done bool, err error) {
					towrite := min(tokens, len(t))
					written, err := s.Write(t[:min(tokens, len(t))])
					t = t[written:]
					return towrite, len(t) == 0, err
				})
				if err != nil {
					panic(err)
				}
				wg.Done()
			}(i)
		}
		wg.Wait()
	}
	if err := s.Close(); err != nil {
		panic(err)
	}
}

func BenchmarkWithoutFlowControl(b *testing.B) {
	const (
		workers = 100
		mtu     = 1 << 16
	)
	s := newNullConn(mtu)
	for n := 0; n < b.N; n++ {
		for cursor := 0; cursor < len(testdata); cursor += mtu {
			for i := 0; i < workers; i++ {
				_, err := s.Write(testdata[cursor : cursor+mtu])
				if err != nil {
					panic(err)
				}
			}
		}
	}
	if err := s.Close(); err != nil {
		panic(err)
	}
}
<|endoftext|>


<commit_before>package gubled

import (
	"github.com/smancke/guble/client"
	"github.com/smancke/guble/guble"
	"github.com/smancke/guble/server"

	assert "github.com/stretchr/testify/assert"
	"testing"

	"encoding/json"
	"time"
)

func TestSimplePingPong(t *testing.T) {
	_, client1, client2, tearDown := initServerAndClients(t)
	defer tearDown()

	client1.Subscribe("/foo")
	//expectStatusMessage(t, client1, guble.SUCCESS_SUBSCRIBED_TO, "/foo")

	time.Sleep(time.Millisecond * 10)
	client2.Send("/foo 42", "Hallo", `{"key": "value"}`)
	expectStatusMessage(t, client2, guble.SUCCESS_SEND, "42")

	select {
	case msg := <-client1.Messages():
		assert.Equal(t, "Hallo", msg.BodyAsString())
		assert.Equal(t, "user2", msg.PublisherUserId)
		assert.Equal(t, `{"key": "value"}`, msg.HeaderJson)
		assert.Equal(t, uint64(1), msg.Id)
	case msg := <-client1.Errors():
		t.Logf("received error: %v", msg)
		t.FailNow()
	case <-time.After(time.Millisecond * 100):
		t.Log("no message received")
		t.FailNow()
	}
}

func initServerAndClients(t *testing.T) (*server.Service, *client.Client, *client.Client, func()) {
	service := StartupService(Args{Listen: "localhost:0", KVBackend: "memory"})

	time.Sleep(time.Millisecond * 100)

	var err error
	client1, err := client.Open("ws://"+service.GetWebServer().GetAddr()+"/stream/user/user1", "http://localhost", 1, false)
	assert.NoError(t, err)

	checkConnectedNotificationJson(t, "user1",
		expectStatusMessage(t, client1, guble.SUCCESS_CONNECTED, "You are connected to the server."),
	)

	client2, err := client.Open("ws://"+service.GetWebServer().GetAddr()+"/stream/user/user2", "http://localhost", 1, false)
	assert.NoError(t, err)
	checkConnectedNotificationJson(t, "user2",
		expectStatusMessage(t, client2, guble.SUCCESS_CONNECTED, "You are connected to the server."),
	)

	return service, client1, client2, func() {
		service.Stop()

		if client1 != nil {
			client1.Close()
		}
		if client2 != nil {
			client2.Close()
		}
	}
}

func expectStatusMessage(t *testing.T, client *client.Client, name string, arg string) string {
	select {
	case notify := <-client.StatusMessages():
		assert.Equal(t, name, notify.Name)
		assert.Equal(t, arg, notify.Arg)
		return notify.Json
	case <-time.After(time.Second * 1):
		t.Logf("no notification of type %s after 1 second", name)
		t.Fail()
		return ""
	}
}

func checkConnectedNotificationJson(t *testing.T, user string, connectedJson string) {
	m := make(map[string]string)
	err := json.Unmarshal([]byte(connectedJson), &m)
	assert.NoError(t, err)
	assert.Equal(t, user, m["UserId"])
	assert.True(t, len(m["ApplicationId"]) > 0)
	_, e := time.Parse(time.RFC3339, m["Time"])
	assert.NoError(t, e)
}
<commit_msg>Increase timeout for pingpong test<commit_after>package gubled

import (
	"github.com/smancke/guble/client"
	"github.com/smancke/guble/guble"
	"github.com/smancke/guble/server"

	assert "github.com/stretchr/testify/assert"
	"testing"

	"encoding/json"
	"time"
)

func TestSimplePingPong(t *testing.T) {
	_, client1, client2, tearDown := initServerAndClients(t)
	defer tearDown()

	client1.Subscribe("/foo")
	//expectStatusMessage(t, client1, guble.SUCCESS_SUBSCRIBED_TO, "/foo")

	time.Sleep(time.Millisecond * 10)
	client2.Send("/foo 42", "Hallo", `{"key": "value"}`)
	expectStatusMessage(t, client2, guble.SUCCESS_SEND, "42")

	select {
	case msg := <-client1.Messages():
		assert.Equal(t, "Hallo", msg.BodyAsString())
		assert.Equal(t, "user2", msg.PublisherUserId)
		assert.Equal(t, `{"key": "value"}`, msg.HeaderJson)
		assert.Equal(t, uint64(1), msg.Id)
	case msg := <-client1.Errors():
		t.Logf("received error: %v", msg)
		t.FailNow()
	case <-time.After(time.Millisecond * 100):
		t.Log("no message received")
		t.FailNow()
	}
}

func initServerAndClients(t *testing.T) (*server.Service, *client.Client, *client.Client, func()) {
	service := StartupService(Args{Listen: "localhost:0", KVBackend: "memory"})

	time.Sleep(time.Millisecond * 100)

	var err error
	client1, err := client.Open("ws://"+service.GetWebServer().GetAddr()+"/stream/user/user1", "http://localhost", 1, false)
	assert.NoError(t, err)

	checkConnectedNotificationJson(t, "user1",
		expectStatusMessage(t, client1, guble.SUCCESS_CONNECTED, "You are connected to the server."),
	)

	client2, err := client.Open("ws://"+service.GetWebServer().GetAddr()+"/stream/user/user2", "http://localhost", 1, false)
	assert.NoError(t, err)
	checkConnectedNotificationJson(t, "user2",
		expectStatusMessage(t, client2, guble.SUCCESS_CONNECTED, "You are connected to the server."),
	)

	return service, client1, client2, func() {
		service.Stop()

		if client1 != nil {
			client1.Close()
		}
		if client2 != nil {
			client2.Close()
		}
	}
}

func expectStatusMessage(t *testing.T, client *client.Client, name string, arg string) string {
	select {
	case notify := <-client.StatusMessages():
		assert.Equal(t, name, notify.Name)
		assert.Equal(t, arg, notify.Arg)
		return notify.Json
	case <-time.After(time.Second * 2):
		t.Logf("no notification of type %s after 2 second", name)
		t.Fail()
		return ""
	}
}

func checkConnectedNotificationJson(t *testing.T, user string, connectedJson string) {
	m := make(map[string]string)
	err := json.Unmarshal([]byte(connectedJson), &m)
	assert.NoError(t, err)
	assert.Equal(t, user, m["UserId"])
	assert.True(t, len(m["ApplicationId"]) > 0)
	_, e := time.Parse(time.RFC3339, m["Time"])
	assert.NoError(t, e)
}
<|endoftext|>