diff --git a/third_party/bitbucket.org/kardianos/osext/osext_sysctl.go b/third_party/bitbucket.org/kardianos/osext/osext_sysctl.go index d76464628..e4d228ed1 100644 --- a/third_party/bitbucket.org/kardianos/osext/osext_sysctl.go +++ b/third_party/bitbucket.org/kardianos/osext/osext_sysctl.go @@ -8,6 +8,7 @@ package osext import ( "os" + "path/filepath" "runtime" "syscall" "unsafe" @@ -47,18 +48,35 @@ func executable() (string, error) { break } } + var strpath string if buf[0] != '/' { - if getwdError != nil { - return string(buf), getwdError - } else { - if buf[0] == '.' { - buf = buf[1:] - } - if startUpcwd[len(startUpcwd)-1] != '/' { - return startUpcwd + "/" + string(buf), nil - } - return startUpcwd + string(buf), nil + var e error + if strpath, e = getAbs(buf); e != nil { + return strpath, e + } + } else { + strpath = string(buf) + } + // darwin KERN_PROCARGS may return the path to a symlink rather than the + // actual executable + if runtime.GOOS == "darwin" { + if strpath, err := filepath.EvalSymlinks(strpath); err != nil { + return strpath, err } } - return string(buf), nil + return strpath, nil +} + +func getAbs(buf []byte) (string, error) { + if getwdError != nil { + return string(buf), getwdError + } else { + if buf[0] == '.' { + buf = buf[1:] + } + if startUpcwd[len(startUpcwd)-1] != '/' && buf[0] != '/' { + return startUpcwd + "/" + string(buf), nil + } + return startUpcwd + string(buf), nil + } } diff --git a/third_party/code.google.com/p/go.net/ipv4/gen.go b/third_party/code.google.com/p/go.net/ipv4/gen.go index d2ed17d7d..9a2af1e68 100644 --- a/third_party/code.google.com/p/go.net/ipv4/gen.go +++ b/third_party/code.google.com/p/go.net/ipv4/gen.go @@ -97,20 +97,16 @@ func parseICMPv4Parameters(w io.Writer, r io.Reader) error { } type icmpv4Parameters struct { - XMLName xml.Name `xml:"registry"` - Title string `xml:"title"` - Updated string `xml:"updated"` - Registries []icmpv4ParamRegistry `xml:"registry"` -} - -type icmpv4ParamRegistry struct { - Title string `xml:"title"` - Records []icmpv4ParamRecord `xml:"record"` -} - -type icmpv4ParamRecord struct { - Value string `xml:"value"` - Descr string `xml:"description"` + XMLName xml.Name `xml:"registry"` + Title string `xml:"title"` + Updated string `xml:"updated"` + Registries []struct { + Title string `xml:"title"` + Records []struct { + Value string `xml:"value"` + Descr string `xml:"description"` + } `xml:"record"` + } `xml:"registry"` } type canonICMPv4ParamRecord struct { @@ -193,18 +189,16 @@ func parseProtocolNumbers(w io.Writer, r io.Reader) error { } type protocolNumbers struct { - XMLName xml.Name `xml:"registry"` - Title string `xml:"title"` - Updated string `xml:"updated"` - RegTitle string `xml:"registry>title"` - Note string `xml:"registry>note"` - Records []protocolRecord `xml:"registry>record"` -} - -type protocolRecord struct { - Value string `xml:"value"` - Name string `xml:"name"` - Descr string `xml:"description"` + XMLName xml.Name `xml:"registry"` + Title string `xml:"title"` + Updated string `xml:"updated"` + RegTitle string `xml:"registry>title"` + Note string `xml:"registry>note"` + Records []struct { + Value string `xml:"value"` + Name string `xml:"name"` + Descr string `xml:"description"` + } `xml:"registry>record"` } type canonProtocolRecord struct { diff --git a/third_party/code.google.com/p/go.net/ipv4/gentest.go b/third_party/code.google.com/p/go.net/ipv4/gentest.go index cc35225cc..3b21d7a6b 100644 --- a/third_party/code.google.com/p/go.net/ipv4/gentest.go +++ b/third_party/code.google.com/p/go.net/ipv4/gentest.go @@ -39,7 +39,7 @@ var registries = []struct { func main() { var bb bytes.Buffer - fmt.Fprintf(&bb, "// go run gentv.go\n") + fmt.Fprintf(&bb, "// go run gentest.go\n") fmt.Fprintf(&bb, "// GENERATED BY THE COMMAND ABOVE; DO NOT EDIT\n\n") fmt.Fprintf(&bb, "package ipv4_test\n\n") for _, r := range registries { @@ -85,18 +85,19 @@ func parseDSCPRegistry(w io.Writer, r io.Reader) error { } type dscpRegistry struct { - XMLName xml.Name `xml:"registry"` - Title string `xml:"title"` - Updated string `xml:"updated"` - Note string `xml:"note"` - RegTitle string `xml:"registry>title"` - PoolRecords []dscpRecord `xml:"registry>record"` - Records []dscpRecord `xml:"registry>registry>record"` -} - -type dscpRecord struct { - Name string `xml:"name"` - Space string `xml:"space"` + XMLName xml.Name `xml:"registry"` + Title string `xml:"title"` + Updated string `xml:"updated"` + Note string `xml:"note"` + RegTitle string `xml:"registry>title"` + PoolRecords []struct { + Name string `xml:"name"` + Space string `xml:"space"` + } `xml:"registry>record"` + Records []struct { + Name string `xml:"name"` + Space string `xml:"space"` + } `xml:"registry>registry>record"` } type canonDSCPRecord struct { @@ -145,17 +146,15 @@ func parseTOSTCByte(w io.Writer, r io.Reader) error { } type tosTCByte struct { - XMLName xml.Name `xml:"registry"` - Title string `xml:"title"` - Updated string `xml:"updated"` - Note string `xml:"note"` - RegTitle string `xml:"registry>title"` - Records []tosTCByteRecord `xml:"registry>record"` -} - -type tosTCByteRecord struct { - Binary string `xml:"binary"` - Keyword string `xml:"keyword"` + XMLName xml.Name `xml:"registry"` + Title string `xml:"title"` + Updated string `xml:"updated"` + Note string `xml:"note"` + RegTitle string `xml:"registry>title"` + Records []struct { + Binary string `xml:"binary"` + Keyword string `xml:"keyword"` + } `xml:"registry>record"` } type canonTOSTCByteRecord struct { diff --git a/third_party/code.google.com/p/go.net/ipv4/header.go b/third_party/code.google.com/p/go.net/ipv4/header.go index 45bd27a17..e15db01d5 100644 --- a/third_party/code.google.com/p/go.net/ipv4/header.go +++ b/third_party/code.google.com/p/go.net/ipv4/header.go @@ -36,41 +36,47 @@ const ( maxHeaderLen = 60 // sensible default, revisit if later RFCs define new usage of version and header length fields ) -type headerField int +const ( + posTOS = 1 // type-of-service + posTotalLen = 2 // packet total length + posID = 4 // identification + posFragOff = 6 // fragment offset + posTTL = 8 // time-to-live + posProtocol = 9 // next protocol + posChecksum = 10 // checksum + posSrc = 12 // source address + posDst = 16 // destination address +) + +type HeaderFlags int const ( - posTOS headerField = 1 // type-of-service - posTotalLen = 2 // packet total length - posID = 4 // identification - posFragOff = 6 // fragment offset - posTTL = 8 // time-to-live - posProtocol = 9 // next protocol - posChecksum = 10 // checksum - posSrc = 12 // source address - posDst = 16 // destination address + MoreFragments HeaderFlags = 1 << iota // more fragments flag + DontFragment // don't fragment flag ) // A Header represents an IPv4 header. type Header struct { - Version int // protocol version - Len int // header length - TOS int // type-of-service - TotalLen int // packet total length - ID int // identification - FragOff int // fragment offset - TTL int // time-to-live - Protocol int // next protocol - Checksum int // checksum - Src net.IP // source address - Dst net.IP // destination address - Options []byte // options, extension headers + Version int // protocol version + Len int // header length + TOS int // type-of-service + TotalLen int // packet total length + ID int // identification + Flags HeaderFlags // flags + FragOff int // fragment offset + TTL int // time-to-live + Protocol int // next protocol + Checksum int // checksum + Src net.IP // source address + Dst net.IP // destination address + Options []byte // options, extension headers } func (h *Header) String() string { if h == nil { return "" } - return fmt.Sprintf("ver: %v, hdrlen: %v, tos: %#x, totallen: %v, id: %#x, fragoff: %#x, ttl: %v, proto: %v, cksum: %#x, src: %v, dst: %v", h.Version, h.Len, h.TOS, h.TotalLen, h.ID, h.FragOff, h.TTL, h.Protocol, h.Checksum, h.Src, h.Dst) + return fmt.Sprintf("ver: %v, hdrlen: %v, tos: %#x, totallen: %v, id: %#x, flags: %#x, fragoff: %#x, ttl: %v, proto: %v, cksum: %#x, src: %v, dst: %v", h.Version, h.Len, h.TOS, h.TotalLen, h.ID, h.Flags, h.FragOff, h.TTL, h.Protocol, h.Checksum, h.Src, h.Dst) } // Please refer to the online manual; IP(4) on Darwin, FreeBSD and @@ -89,12 +95,13 @@ func (h *Header) Marshal() ([]byte, error) { b := make([]byte, hdrlen) b[0] = byte(Version<<4 | (hdrlen >> 2 & 0x0f)) b[posTOS] = byte(h.TOS) + flagsAndFragOff := (h.FragOff & 0x1fff) | int(h.Flags<<13) if supportsNewIPInput { b[posTotalLen], b[posTotalLen+1] = byte(h.TotalLen>>8), byte(h.TotalLen) - b[posFragOff], b[posFragOff+1] = byte(h.FragOff>>8), byte(h.FragOff) + b[posFragOff], b[posFragOff+1] = byte(flagsAndFragOff>>8), byte(flagsAndFragOff) } else { *(*uint16)(unsafe.Pointer(&b[posTotalLen : posTotalLen+1][0])) = uint16(h.TotalLen) - *(*uint16)(unsafe.Pointer(&b[posFragOff : posFragOff+1][0])) = uint16(h.FragOff) + *(*uint16)(unsafe.Pointer(&b[posFragOff : posFragOff+1][0])) = uint16(flagsAndFragOff) } b[posID], b[posID+1] = byte(h.ID>>8), byte(h.ID) b[posTTL] = byte(h.TTL) @@ -135,6 +142,8 @@ func ParseHeader(b []byte) (*Header, error) { h.TotalLen += hdrlen h.FragOff = int(*(*uint16)(unsafe.Pointer(&b[posFragOff : posFragOff+1][0]))) } + h.Flags = HeaderFlags(h.FragOff&0xe000) >> 13 + h.FragOff = h.FragOff & 0x1fff h.ID = int(b[posID])<<8 | int(b[posID+1]) h.TTL = int(b[posTTL]) h.Protocol = int(b[posProtocol]) diff --git a/third_party/code.google.com/p/go.net/ipv4/header_test.go b/third_party/code.google.com/p/go.net/ipv4/header_test.go index cc2fd8e09..121d1f20d 100644 --- a/third_party/code.google.com/p/go.net/ipv4/header_test.go +++ b/third_party/code.google.com/p/go.net/ipv4/header_test.go @@ -16,28 +16,28 @@ import ( var ( wireHeaderFromKernel = [ipv4.HeaderLen]byte{ 0x45, 0x01, 0xbe, 0xef, - 0xca, 0xfe, 0x05, 0xdc, + 0xca, 0xfe, 0x45, 0xdc, 0xff, 0x01, 0xde, 0xad, 172, 16, 254, 254, 192, 168, 0, 1, } wireHeaderToKernel = [ipv4.HeaderLen]byte{ 0x45, 0x01, 0xbe, 0xef, - 0xca, 0xfe, 0x05, 0xdc, + 0xca, 0xfe, 0x45, 0xdc, 0xff, 0x01, 0xde, 0xad, 172, 16, 254, 254, 192, 168, 0, 1, } wireHeaderFromTradBSDKernel = [ipv4.HeaderLen]byte{ 0x45, 0x01, 0xdb, 0xbe, - 0xca, 0xfe, 0xdc, 0x05, + 0xca, 0xfe, 0xdc, 0x45, 0xff, 0x01, 0xde, 0xad, 172, 16, 254, 254, 192, 168, 0, 1, } wireHeaderToTradBSDKernel = [ipv4.HeaderLen]byte{ 0x45, 0x01, 0xef, 0xbe, - 0xca, 0xfe, 0xdc, 0x05, + 0xca, 0xfe, 0xdc, 0x45, 0xff, 0x01, 0xde, 0xad, 172, 16, 254, 254, 192, 168, 0, 1, @@ -51,6 +51,7 @@ var ( TOS: 1, TotalLen: 0xbeef, ID: 0xcafe, + Flags: ipv4.DontFragment, FragOff: 1500, TTL: 255, Protocol: 1, diff --git a/third_party/code.google.com/p/go.net/ipv4/iana_test.go b/third_party/code.google.com/p/go.net/ipv4/iana_test.go index 276230d62..8f9e7bae8 100644 --- a/third_party/code.google.com/p/go.net/ipv4/iana_test.go +++ b/third_party/code.google.com/p/go.net/ipv4/iana_test.go @@ -1,9 +1,9 @@ -// go run gentv.go +// go run gentest.go // GENERATED BY THE COMMAND ABOVE; DO NOT EDIT package ipv4_test -// Differentiated Services Field Codepoints, Updated: 2010-05-11 +// Differentiated Services Field Codepoints (DSCP), Updated: 2013-06-25 const ( DiffServCS0 = 0x0 // CS0 DiffServCS1 = 0x20 // CS1 diff --git a/third_party/code.google.com/p/go.net/ipv6/gen.go b/third_party/code.google.com/p/go.net/ipv6/gen.go index 36517b246..5680bac76 100644 --- a/third_party/code.google.com/p/go.net/ipv6/gen.go +++ b/third_party/code.google.com/p/go.net/ipv6/gen.go @@ -97,20 +97,16 @@ func parseICMPv6Parameters(w io.Writer, r io.Reader) error { } type icmpv6Parameters struct { - XMLName xml.Name `xml:"registry"` - Title string `xml:"title"` - Updated string `xml:"updated"` - Registries []icmpv6ParamRegistry `xml:"registry"` -} - -type icmpv6ParamRegistry struct { - Title string `xml:"title"` - Records []icmpv6ParamRecord `xml:"record"` -} - -type icmpv6ParamRecord struct { - Value string `xml:"value"` - Name string `xml:"name"` + XMLName xml.Name `xml:"registry"` + Title string `xml:"title"` + Updated string `xml:"updated"` + Registries []struct { + Title string `xml:"title"` + Records []struct { + Value string `xml:"value"` + Name string `xml:"name"` + } `xml:"record"` + } `xml:"registry"` } type canonICMPv6ParamRecord struct { @@ -188,18 +184,16 @@ func parseProtocolNumbers(w io.Writer, r io.Reader) error { } type protocolNumbers struct { - XMLName xml.Name `xml:"registry"` - Title string `xml:"title"` - Updated string `xml:"updated"` - RegTitle string `xml:"registry>title"` - Note string `xml:"registry>note"` - Records []protocolRecord `xml:"registry>record"` -} - -type protocolRecord struct { - Value string `xml:"value"` - Name string `xml:"name"` - Descr string `xml:"description"` + XMLName xml.Name `xml:"registry"` + Title string `xml:"title"` + Updated string `xml:"updated"` + RegTitle string `xml:"registry>title"` + Note string `xml:"registry>note"` + Records []struct { + Value string `xml:"value"` + Name string `xml:"name"` + Descr string `xml:"description"` + } `xml:"registry>record"` } type canonProtocolRecord struct { diff --git a/third_party/code.google.com/p/go.net/ipv6/gentest.go b/third_party/code.google.com/p/go.net/ipv6/gentest.go index fddbfd1ef..606930f63 100644 --- a/third_party/code.google.com/p/go.net/ipv6/gentest.go +++ b/third_party/code.google.com/p/go.net/ipv6/gentest.go @@ -39,7 +39,7 @@ var registries = []struct { func main() { var bb bytes.Buffer - fmt.Fprintf(&bb, "// go run gentv.go\n") + fmt.Fprintf(&bb, "// go run gentest.go\n") fmt.Fprintf(&bb, "// GENERATED BY THE COMMAND ABOVE; DO NOT EDIT\n\n") fmt.Fprintf(&bb, "package ipv6_test\n\n") for _, r := range registries { @@ -85,18 +85,19 @@ func parseDSCPRegistry(w io.Writer, r io.Reader) error { } type dscpRegistry struct { - XMLName xml.Name `xml:"registry"` - Title string `xml:"title"` - Updated string `xml:"updated"` - Note string `xml:"note"` - RegTitle string `xml:"registry>title"` - PoolRecords []dscpRecord `xml:"registry>record"` - Records []dscpRecord `xml:"registry>registry>record"` -} - -type dscpRecord struct { - Name string `xml:"name"` - Space string `xml:"space"` + XMLName xml.Name `xml:"registry"` + Title string `xml:"title"` + Updated string `xml:"updated"` + Note string `xml:"note"` + RegTitle string `xml:"registry>title"` + PoolRecords []struct { + Name string `xml:"name"` + Space string `xml:"space"` + } `xml:"registry>record"` + Records []struct { + Name string `xml:"name"` + Space string `xml:"space"` + } `xml:"registry>registry>record"` } type canonDSCPRecord struct { @@ -145,17 +146,15 @@ func parseTOSTCByte(w io.Writer, r io.Reader) error { } type tosTCByte struct { - XMLName xml.Name `xml:"registry"` - Title string `xml:"title"` - Updated string `xml:"updated"` - Note string `xml:"note"` - RegTitle string `xml:"registry>title"` - Records []tosTCByteRecord `xml:"registry>record"` -} - -type tosTCByteRecord struct { - Binary string `xml:"binary"` - Keyword string `xml:"keyword"` + XMLName xml.Name `xml:"registry"` + Title string `xml:"title"` + Updated string `xml:"updated"` + Note string `xml:"note"` + RegTitle string `xml:"registry>title"` + Records []struct { + Binary string `xml:"binary"` + Keyword string `xml:"keyword"` + } `xml:"registry>record"` } type canonTOSTCByteRecord struct { diff --git a/third_party/code.google.com/p/go.net/ipv6/iana.go b/third_party/code.google.com/p/go.net/ipv6/iana.go index c888cf256..429087c5f 100644 --- a/third_party/code.google.com/p/go.net/ipv6/iana.go +++ b/third_party/code.google.com/p/go.net/ipv6/iana.go @@ -3,7 +3,7 @@ package ipv6 -// Internet Control Message Protocol version 6 (ICMPv6) Parameters, Updated: 2012-11-12 +// Internet Control Message Protocol version 6 (ICMPv6) Parameters, Updated: 2013-07-03 const ( ICMPTypeDestinationUnreachable ICMPType = 1 // Destination Unreachable ICMPTypePacketTooBig ICMPType = 2 // Packet Too Big @@ -41,7 +41,7 @@ const ( ICMPTypeDuplicateAddressConfirmation ICMPType = 158 // Duplicate Address Confirmation ) -// Internet Control Message Protocol version 6 (ICMPv6) Parameters, Updated: 2012-11-12 +// Internet Control Message Protocol version 6 (ICMPv6) Parameters, Updated: 2013-07-03 var icmpTypes = map[ICMPType]string{ 1: "destination unreachable", 2: "packet too big", diff --git a/third_party/code.google.com/p/go.net/ipv6/iana_test.go b/third_party/code.google.com/p/go.net/ipv6/iana_test.go index 7b6bb85ef..03e8bfe5a 100644 --- a/third_party/code.google.com/p/go.net/ipv6/iana_test.go +++ b/third_party/code.google.com/p/go.net/ipv6/iana_test.go @@ -1,9 +1,9 @@ -// go run gentv.go +// go run gentest.go // GENERATED BY THE COMMAND ABOVE; DO NOT EDIT package ipv6_test -// Differentiated Services Field Codepoints, Updated: 2010-05-11 +// Differentiated Services Field Codepoints (DSCP), Updated: 2013-06-25 const ( DiffServCS0 = 0x0 // CS0 DiffServCS1 = 0x20 // CS1 diff --git a/third_party/code.google.com/p/go.net/websocket/client.go b/third_party/code.google.com/p/go.net/websocket/client.go index df54a6881..a861bb92c 100644 --- a/third_party/code.google.com/p/go.net/websocket/client.go +++ b/third_party/code.google.com/p/go.net/websocket/client.go @@ -43,26 +43,12 @@ func NewConfig(server, origin string) (config *Config, err error) { func NewClient(config *Config, rwc io.ReadWriteCloser) (ws *Conn, err error) { br := bufio.NewReader(rwc) bw := bufio.NewWriter(rwc) - switch config.Version { - case ProtocolVersionHixie75: - err = hixie75ClientHandshake(config, br, bw) - case ProtocolVersionHixie76, ProtocolVersionHybi00: - err = hixie76ClientHandshake(config, br, bw) - case ProtocolVersionHybi08, ProtocolVersionHybi13: - err = hybiClientHandshake(config, br, bw) - default: - err = ErrBadProtocolVersion - } + err = hybiClientHandshake(config, br, bw) if err != nil { return } buf := bufio.NewReadWriter(br, bw) - switch config.Version { - case ProtocolVersionHixie75, ProtocolVersionHixie76, ProtocolVersionHybi00: - ws = newHixieClientConn(config, buf, rwc) - case ProtocolVersionHybi08, ProtocolVersionHybi13: - ws = newHybiClientConn(config, buf, rwc) - } + ws = newHybiClientConn(config, buf, rwc) return } diff --git a/third_party/code.google.com/p/go.net/websocket/hybi.go b/third_party/code.google.com/p/go.net/websocket/hybi.go index 90f5d9ca0..f8c0b2e29 100644 --- a/third_party/code.google.com/p/go.net/websocket/hybi.go +++ b/third_party/code.google.com/p/go.net/websocket/hybi.go @@ -385,21 +385,8 @@ func getNonceAccept(nonce []byte) (expected []byte, err error) { return } -func isHybiVersion(version int) bool { - switch version { - case ProtocolVersionHybi08, ProtocolVersionHybi13: - return true - default: - } - return false -} - // Client handshake described in draft-ietf-hybi-thewebsocket-protocol-17 func hybiClientHandshake(config *Config, br *bufio.Reader, bw *bufio.Writer) (err error) { - if !isHybiVersion(config.Version) { - panic("wrong protocol version.") - } - bw.WriteString("GET " + config.Location.RequestURI() + " HTTP/1.1\r\n") bw.WriteString("Host: " + config.Location.Host + "\r\n") @@ -410,11 +397,12 @@ func hybiClientHandshake(config *Config, br *bufio.Reader, bw *bufio.Writer) (er nonce = []byte(config.handshakeData["key"]) } bw.WriteString("Sec-WebSocket-Key: " + string(nonce) + "\r\n") - if config.Version == ProtocolVersionHybi13 { - bw.WriteString("Origin: " + strings.ToLower(config.Origin.String()) + "\r\n") - } else if config.Version == ProtocolVersionHybi08 { - bw.WriteString("Sec-WebSocket-Origin: " + strings.ToLower(config.Origin.String()) + "\r\n") + bw.WriteString("Origin: " + strings.ToLower(config.Origin.String()) + "\r\n") + + if config.Version != ProtocolVersionHybi13 { + return ErrBadProtocolVersion } + bw.WriteString("Sec-WebSocket-Version: " + fmt.Sprintf("%d", config.Version) + "\r\n") if len(config.Protocol) > 0 { bw.WriteString("Sec-WebSocket-Protocol: " + strings.Join(config.Protocol, ", ") + "\r\n") @@ -500,8 +488,6 @@ func (c *hybiServerHandshaker) ReadHandshake(buf *bufio.Reader, req *http.Reques switch version { case "13": c.Version = ProtocolVersionHybi13 - case "8": - c.Version = ProtocolVersionHybi08 default: return http.StatusBadRequest, ErrBadWebSocketVersion } @@ -536,8 +522,6 @@ func Origin(config *Config, req *http.Request) (*url.URL, error) { switch config.Version { case ProtocolVersionHybi13: origin = req.Header.Get("Origin") - case ProtocolVersionHybi08: - origin = req.Header.Get("Sec-Websocket-Origin") } if origin == "null" { return nil, nil diff --git a/third_party/code.google.com/p/go.net/websocket/hybi_test.go b/third_party/code.google.com/p/go.net/websocket/hybi_test.go index 9db0ef97b..d6a19108a 100644 --- a/third_party/code.google.com/p/go.net/websocket/hybi_test.go +++ b/third_party/code.google.com/p/go.net/websocket/hybi_test.go @@ -157,68 +157,6 @@ Sec-WebSocket-Protocol: chat } } -func TestHybiClientHandshakeHybi08(t *testing.T) { - b := bytes.NewBuffer([]byte{}) - bw := bufio.NewWriter(b) - br := bufio.NewReader(strings.NewReader(`HTTP/1.1 101 Switching Protocols -Upgrade: websocket -Connection: Upgrade -Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo= -Sec-WebSocket-Protocol: chat - -`)) - var err error - config := new(Config) - config.Location, err = url.ParseRequestURI("ws://server.example.com/chat") - if err != nil { - t.Fatal("location url", err) - } - config.Origin, err = url.ParseRequestURI("http://example.com") - if err != nil { - t.Fatal("origin url", err) - } - config.Protocol = append(config.Protocol, "chat") - config.Protocol = append(config.Protocol, "superchat") - config.Version = ProtocolVersionHybi08 - - config.handshakeData = map[string]string{ - "key": "dGhlIHNhbXBsZSBub25jZQ==", - } - err = hybiClientHandshake(config, br, bw) - if err != nil { - t.Errorf("handshake failed: %v", err) - } - req, err := http.ReadRequest(bufio.NewReader(b)) - if err != nil { - t.Fatalf("read request: %v", err) - } - if req.Method != "GET" { - t.Errorf("request method expected GET, but got %q", req.Method) - } - if req.URL.Path != "/chat" { - t.Errorf("request path expected /demo, but got %q", req.URL.Path) - } - if req.Proto != "HTTP/1.1" { - t.Errorf("request proto expected HTTP/1.1, but got %q", req.Proto) - } - if req.Host != "server.example.com" { - t.Errorf("request Host expected example.com, but got %v", req.Host) - } - var expectedHeader = map[string]string{ - "Connection": "Upgrade", - "Upgrade": "websocket", - "Sec-Websocket-Key": config.handshakeData["key"], - "Sec-Websocket-Origin": config.Origin.String(), - "Sec-Websocket-Protocol": "chat, superchat", - "Sec-Websocket-Version": fmt.Sprintf("%d", ProtocolVersionHybi08), - } - for k, v := range expectedHeader { - if req.Header.Get(k) != v { - t.Errorf(fmt.Sprintf("%s expected %q but got %q", k, v, req.Header.Get(k))) - } - } -} - func TestHybiServerHandshake(t *testing.T) { config := new(Config) handshaker := &hybiServerHandshaker{Config: config} @@ -314,52 +252,6 @@ Sec-WebSocket-Version: 13 } } -func TestHybiServerHandshakeHybi08(t *testing.T) { - config := new(Config) - handshaker := &hybiServerHandshaker{Config: config} - br := bufio.NewReader(strings.NewReader(`GET /chat HTTP/1.1 -Host: server.example.com -Upgrade: websocket -Connection: Upgrade -Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== -Sec-WebSocket-Origin: http://example.com -Sec-WebSocket-Protocol: chat, superchat -Sec-WebSocket-Version: 8 - -`)) - req, err := http.ReadRequest(br) - if err != nil { - t.Fatal("request", err) - } - code, err := handshaker.ReadHandshake(br, req) - if err != nil { - t.Errorf("handshake failed: %v", err) - } - if code != http.StatusSwitchingProtocols { - t.Errorf("status expected %q but got %q", http.StatusSwitchingProtocols, code) - } - b := bytes.NewBuffer([]byte{}) - bw := bufio.NewWriter(b) - - config.Protocol = []string{"chat"} - - err = handshaker.AcceptHandshake(bw) - if err != nil { - t.Errorf("handshake response failed: %v", err) - } - expectedResponse := strings.Join([]string{ - "HTTP/1.1 101 Switching Protocols", - "Upgrade: websocket", - "Connection: Upgrade", - "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=", - "Sec-WebSocket-Protocol: chat", - "", ""}, "\r\n") - - if b.String() != expectedResponse { - t.Errorf("handshake expected %q but got %q", expectedResponse, b.String()) - } -} - func TestHybiServerHandshakeHybiBadVersion(t *testing.T) { config := new(Config) handshaker := &hybiServerHandshaker{Config: config} diff --git a/third_party/code.google.com/p/go.net/websocket/server.go b/third_party/code.google.com/p/go.net/websocket/server.go index 54e05b430..70322133c 100644 --- a/third_party/code.google.com/p/go.net/websocket/server.go +++ b/third_party/code.google.com/p/go.net/websocket/server.go @@ -22,14 +22,6 @@ func newServerConn(rwc io.ReadWriteCloser, buf *bufio.ReadWriter, req *http.Requ buf.Flush() return } - if err != nil { - hs = &hixie76ServerHandshaker{Config: config} - code, err = hs.ReadHandshake(buf.Reader, req) - } - if err != nil { - hs = &hixie75ServerHandshaker{Config: config} - code, err = hs.ReadHandshake(buf.Reader, req) - } if err != nil { fmt.Fprintf(buf, "HTTP/1.1 %03d %s\r\n", code, http.StatusText(code)) buf.WriteString("\r\n") diff --git a/third_party/code.google.com/p/go.net/websocket/websocket.go b/third_party/code.google.com/p/go.net/websocket/websocket.go index 861b3c68f..067f5b268 100644 --- a/third_party/code.google.com/p/go.net/websocket/websocket.go +++ b/third_party/code.google.com/p/go.net/websocket/websocket.go @@ -21,13 +21,9 @@ import ( ) const ( - ProtocolVersionHixie75 = -75 - ProtocolVersionHixie76 = -76 - ProtocolVersionHybi00 = 0 - ProtocolVersionHybi08 = 8 ProtocolVersionHybi13 = 13 ProtocolVersionHybi = ProtocolVersionHybi13 - SupportedProtocolVersion = "13, 8" + SupportedProtocolVersion = "13" ContinuationFrame = 0 TextFrame = 1 diff --git a/third_party/code.google.com/p/go.net/websocket/websocket_test.go b/third_party/code.google.com/p/go.net/websocket/websocket_test.go index 53e445be3..add89bce0 100644 --- a/third_party/code.google.com/p/go.net/websocket/websocket_test.go +++ b/third_party/code.google.com/p/go.net/websocket/websocket_test.go @@ -286,6 +286,20 @@ func TestTrailingSpaces(t *testing.T) { } } +func TestDialConfigBadVersion(t *testing.T) { + once.Do(startServer) + config := newConfig(t, "/echo") + config.Version = 1234 + + _, err := DialConfig(config) + + if dialerr, ok := err.(*DialError); ok { + if dialerr.Err != ErrBadProtocolVersion { + t.Errorf("dial expected err %q but got %q", ErrBadProtocolVersion, dialerr.Err) + } + } +} + func TestSmallBuffer(t *testing.T) { // http://code.google.com/p/go/issues/detail?id=1145 // Read should be able to handle reading a fragment of a frame. diff --git a/third_party/github.com/coreos/go-etcd/etcd/client.go b/third_party/github.com/coreos/go-etcd/etcd/client.go index cbbd7ad9c..31d3c2a3a 100644 --- a/third_party/github.com/coreos/go-etcd/etcd/client.go +++ b/third_party/github.com/coreos/go-etcd/etcd/client.go @@ -36,12 +36,16 @@ type Client struct { } // Setup a basic conf and cluster -func NewClient() *Client { +func NewClient(machines []string) *Client { + // if an empty slice was sent in then just assume localhost + if len(machines) == 0 { + machines = []string{"http://127.0.0.1:4001"} + } // default leader and machines cluster := Cluster{ - Leader: "http://127.0.0.1:4001", - Machines: []string{"http://127.0.0.1:4001"}, + Leader: machines[0], + Machines: machines, } config := Config{ @@ -107,6 +111,10 @@ func (c *Client) SetCluster(machines []string) bool { return success } +func (c *Client) GetCluster() []string { + return c.cluster.Machines +} + // sycn cluster information using the existing machine list func (c *Client) SyncCluster() bool { success := c.internalSyncCluster(c.cluster.Machines) @@ -128,14 +136,16 @@ func (c *Client) internalSyncCluster(machines []string) bool { // try another machine in the cluster continue } + // update Machines List - c.cluster.Machines = strings.Split(string(b), ",") + c.cluster.Machines = strings.Split(string(b), ", ") // update leader // the first one in the machine list is the leader logger.Debugf("update.leader[%s,%s]", c.cluster.Leader, c.cluster.Machines[0]) c.cluster.Leader = c.cluster.Machines[0] + logger.Debug("sync.machines ", c.cluster.Machines) return true } } @@ -146,6 +156,9 @@ func (c *Client) internalSyncCluster(machines []string) bool { func (c *Client) createHttpPath(serverName string, _path string) string { u, _ := url.Parse(serverName) u.Path = path.Join(u.Path, "/", _path) + if u.Scheme == "" { + u.Scheme = "http" + } return u.String() } diff --git a/third_party/github.com/coreos/go-etcd/etcd/client_test.go b/third_party/github.com/coreos/go-etcd/etcd/client_test.go index 45a99e96c..29f138113 100644 --- a/third_party/github.com/coreos/go-etcd/etcd/client_test.go +++ b/third_party/github.com/coreos/go-etcd/etcd/client_test.go @@ -3,6 +3,8 @@ package etcd import ( "fmt" "testing" + "net/url" + "net" ) // To pass this test, we need to create a cluster of 3 machines @@ -10,13 +12,31 @@ import ( func TestSync(t *testing.T) { fmt.Println("Make sure there are three nodes at 0.0.0.0:4001-4003") - c := NewClient() + c := NewClient(nil) success := c.SyncCluster() if !success { t.Fatal("cannot sync machines") } + for _, m := range(c.GetCluster()) { + u, err := url.Parse(m) + if err != nil { + t.Fatal(err) + } + if u.Scheme != "http" { + t.Fatal("scheme must be http") + } + + host, _, err := net.SplitHostPort(u.Host) + if err != nil { + t.Fatal(err) + } + if host != "127.0.0.1" { + t.Fatal("Host must be 127.0.0.1") + } + } + badMachines := []string{"abc", "edef"} success = c.SetCluster(badMachines) diff --git a/third_party/github.com/coreos/go-etcd/etcd/delete_test.go b/third_party/github.com/coreos/go-etcd/etcd/delete_test.go index a5f980167..52756d09f 100644 --- a/third_party/github.com/coreos/go-etcd/etcd/delete_test.go +++ b/third_party/github.com/coreos/go-etcd/etcd/delete_test.go @@ -6,7 +6,7 @@ import ( func TestDelete(t *testing.T) { - c := NewClient() + c := NewClient(nil) c.Set("foo", "bar", 100) result, err := c.Delete("foo") diff --git a/third_party/github.com/coreos/go-etcd/etcd/get_test.go b/third_party/github.com/coreos/go-etcd/etcd/get_test.go index 8e3852c9f..ff8137400 100644 --- a/third_party/github.com/coreos/go-etcd/etcd/get_test.go +++ b/third_party/github.com/coreos/go-etcd/etcd/get_test.go @@ -7,7 +7,7 @@ import ( func TestGet(t *testing.T) { - c := NewClient() + c := NewClient(nil) c.Set("foo", "bar", 100) diff --git a/third_party/github.com/coreos/go-etcd/etcd/list_test.go b/third_party/github.com/coreos/go-etcd/etcd/list_test.go index 1e98e7645..382bb356d 100644 --- a/third_party/github.com/coreos/go-etcd/etcd/list_test.go +++ b/third_party/github.com/coreos/go-etcd/etcd/list_test.go @@ -6,7 +6,7 @@ import ( ) func TestList(t *testing.T) { - c := NewClient() + c := NewClient(nil) c.Set("foo_list/foo", "bar", 100) c.Set("foo_list/fooo", "barbar", 100) diff --git a/third_party/github.com/coreos/go-etcd/etcd/set_test.go b/third_party/github.com/coreos/go-etcd/etcd/set_test.go index dc46608d7..3809ee952 100644 --- a/third_party/github.com/coreos/go-etcd/etcd/set_test.go +++ b/third_party/github.com/coreos/go-etcd/etcd/set_test.go @@ -6,7 +6,7 @@ import ( ) func TestSet(t *testing.T) { - c := NewClient() + c := NewClient(nil) result, err := c.Set("foo", "bar", 100) diff --git a/third_party/github.com/coreos/go-etcd/etcd/testAndSet_test.go b/third_party/github.com/coreos/go-etcd/etcd/testAndSet_test.go index ba6d0e8f5..5dbd854b5 100644 --- a/third_party/github.com/coreos/go-etcd/etcd/testAndSet_test.go +++ b/third_party/github.com/coreos/go-etcd/etcd/testAndSet_test.go @@ -6,7 +6,7 @@ import ( ) func TestTestAndSet(t *testing.T) { - c := NewClient() + c := NewClient(nil) c.Set("foo_testAndSet", "bar", 100) diff --git a/third_party/github.com/coreos/go-etcd/etcd/watch.go b/third_party/github.com/coreos/go-etcd/etcd/watch.go index 5da5565c6..7f59ed065 100644 --- a/third_party/github.com/coreos/go-etcd/etcd/watch.go +++ b/third_party/github.com/coreos/go-etcd/etcd/watch.go @@ -16,6 +16,11 @@ type respAndErr struct { err error } +// Errors introduced by the Watch command. +var ( + ErrWatchStoppedByUser = errors.New("Watch stopped by the user via stop channel") +) + // Watch any change under the given prefix. // When a sinceIndex is given, watch will try to scan from that index to the last index // and will return any changes under the given prefix during the history @@ -66,7 +71,7 @@ func (c *Client) watchOnce(key string, sinceIndex uint64, stop chan bool) (*stor resp, err = res.resp, res.err case <-stop: - resp, err = nil, errors.New("User stoped watch") + resp, err = nil, ErrWatchStoppedByUser } } else { resp, err = c.sendWatchRequest(key, sinceIndex) diff --git a/third_party/github.com/coreos/go-etcd/etcd/watch_test.go b/third_party/github.com/coreos/go-etcd/etcd/watch_test.go index 5e18a2b29..0d9348518 100644 --- a/third_party/github.com/coreos/go-etcd/etcd/watch_test.go +++ b/third_party/github.com/coreos/go-etcd/etcd/watch_test.go @@ -8,7 +8,7 @@ import ( ) func TestWatch(t *testing.T) { - c := NewClient() + c := NewClient(nil) go setHelper("bar", c) @@ -35,9 +35,12 @@ func TestWatch(t *testing.T) { go setLoop("bar", c) - go reciver(ch, stop) + go receiver(ch, stop) - c.Watch("watch_foo", 0, ch, stop) + _, err = c.Watch("watch_foo", 0, ch, stop) + if err != ErrWatchStoppedByUser { + t.Fatalf("Watch returned a non-user stop error") + } } func setHelper(value string, c *Client) { @@ -54,7 +57,7 @@ func setLoop(value string, c *Client) { } } -func reciver(c chan *store.Response, stop chan bool) { +func receiver(c chan *store.Response, stop chan bool) { for i := 0; i < 10; i++ { <-c } diff --git a/third_party/github.com/coreos/go-etcd/examples/sync-cluster/README.md b/third_party/github.com/coreos/go-etcd/examples/sync-cluster/README.md new file mode 100644 index 000000000..145744feb --- /dev/null +++ b/third_party/github.com/coreos/go-etcd/examples/sync-cluster/README.md @@ -0,0 +1,3 @@ +Example script from the sync-cluster bug https://github.com/coreos/go-etcd/issues/27 + +TODO: turn this into a test case diff --git a/third_party/github.com/coreos/go-etcd/examples/sync-cluster/sync-cluster.go b/third_party/github.com/coreos/go-etcd/examples/sync-cluster/sync-cluster.go new file mode 100644 index 000000000..8249b4bdc --- /dev/null +++ b/third_party/github.com/coreos/go-etcd/examples/sync-cluster/sync-cluster.go @@ -0,0 +1,51 @@ + +package main + +import ( + "fmt" + "github.com/coreos/go-etcd/etcd" + "strconv" + "time" +) + +func main() { + fmt.Println("etcd-client started") + c := etcd.NewClient(nil) + c.SetCluster([]string{ + "http://127.0.0.1:4001", + "http://127.0.0.1:4002", + "http://127.0.0.1:4003", + }) + + ticker := time.NewTicker(time.Second * 3) + + for { + select { + case d := <-ticker.C: + n := d.Second() + if n <= 0 { + n = 60 + } + + for ok := c.SyncCluster(); ok == false; { + fmt.Println("SyncCluster failed, trying again") + time.Sleep(100 * time.Millisecond) + } + + result, err := c.Set("foo", "exp_"+strconv.Itoa(n), 0) + if err != nil { + fmt.Println("set error", err) + } else { + fmt.Printf("set %+v\n", result) + } + + ss, err := c.Get("foo") + if err != nil { + fmt.Println("get error", err) + } else { + fmt.Println(len(ss)) + } + + } + } +} diff --git a/third_party/github.com/coreos/go-log/log/commands.go b/third_party/github.com/coreos/go-log/log/commands.go index 9c661272d..94dc9e152 100644 --- a/third_party/github.com/coreos/go-log/log/commands.go +++ b/third_party/github.com/coreos/go-log/log/commands.go @@ -1,6 +1,5 @@ package log - -// Copyright 2013, David Fisher. All rights reserved. +// Copyright 2013, CoreOS, Inc. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -43,6 +42,7 @@ func (logger *Logger) Logf(priority Priority, format string, v ...interface{}) { logger.Log(priority, fmt.Sprintf(format, v...)) } + func (logger *Logger) Emergency(v ...interface{}) { logger.Log(PriEmerg, v...) } @@ -99,6 +99,7 @@ func (logger *Logger) Debugf(format string, v ...interface{}) { logger.Log(PriDebug, fmt.Sprintf(format, v...)) } + func Emergency(v ...interface{}) { defaultLogger.Log(PriEmerg, v...) } @@ -157,56 +158,57 @@ func Debugf(format string, v ...interface{}) { // Standard library log functions -func (logger *Logger) Fatalln(v ...interface{}) { +func (logger *Logger)Fatalln (v ...interface{}) { logger.Log(PriCrit, v...) os.Exit(1) } -func (logger *Logger) Fatalf(format string, v ...interface{}) { +func (logger *Logger)Fatalf (format string, v ...interface{}) { logger.Logf(PriCrit, format, v...) os.Exit(1) } -func (logger *Logger) Panicln(v ...interface{}) { +func (logger *Logger)Panicln (v ...interface{}) { s := fmt.Sprint(v...) logger.Log(PriErr, s) panic(s) } -func (logger *Logger) Panicf(format string, v ...interface{}) { +func (logger *Logger)Panicf (format string, v ...interface{}) { s := fmt.Sprintf(format, v...) logger.Log(PriErr, s) panic(s) } -func (logger *Logger) Println(v ...interface{}) { +func (logger *Logger)Println (v ...interface{}) { logger.Log(PriInfo, v...) } -func (logger *Logger) Printf(format string, v ...interface{}) { +func (logger *Logger)Printf (format string, v ...interface{}) { logger.Logf(PriInfo, format, v...) } -func Fatalln(v ...interface{}) { + +func Fatalln (v ...interface{}) { defaultLogger.Log(PriCrit, v...) os.Exit(1) } -func Fatalf(format string, v ...interface{}) { +func Fatalf (format string, v ...interface{}) { defaultLogger.Logf(PriCrit, format, v...) os.Exit(1) } -func Panicln(v ...interface{}) { +func Panicln (v ...interface{}) { s := fmt.Sprint(v...) defaultLogger.Log(PriErr, s) panic(s) } -func Panicf(format string, v ...interface{}) { +func Panicf (format string, v ...interface{}) { s := fmt.Sprintf(format, v...) defaultLogger.Log(PriErr, s) panic(s) } -func Println(v ...interface{}) { +func Println (v ...interface{}) { defaultLogger.Log(PriInfo, v...) } -func Printf(format string, v ...interface{}) { +func Printf (format string, v ...interface{}) { defaultLogger.Logf(PriInfo, format, v...) } diff --git a/third_party/github.com/coreos/go-log/log/fields.go b/third_party/github.com/coreos/go-log/log/fields.go index 547d941d3..e8d9698a0 100644 --- a/third_party/github.com/coreos/go-log/log/fields.go +++ b/third_party/github.com/coreos/go-log/log/fields.go @@ -1,6 +1,5 @@ package log - -// Copyright 2013, David Fisher. All rights reserved. +// Copyright 2013, CoreOS, Inc. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/third_party/github.com/coreos/go-log/log/logger.go b/third_party/github.com/coreos/go-log/log/logger.go index 59ecdabcb..2089a11f8 100644 --- a/third_party/github.com/coreos/go-log/log/logger.go +++ b/third_party/github.com/coreos/go-log/log/logger.go @@ -1,6 +1,5 @@ package log - -// Copyright 2013, David Fisher. All rights reserved. +// Copyright 2013, CoreOS, Inc. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/third_party/github.com/coreos/go-log/log/priority.go b/third_party/github.com/coreos/go-log/log/priority.go index 931838877..ac73fc8a4 100644 --- a/third_party/github.com/coreos/go-log/log/priority.go +++ b/third_party/github.com/coreos/go-log/log/priority.go @@ -1,6 +1,5 @@ package log - -// Copyright 2013, David Fisher. All rights reserved. +// Copyright 2013, CoreOS, Inc. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/third_party/github.com/coreos/go-log/log/sinks.go b/third_party/github.com/coreos/go-log/log/sinks.go index 5cda993da..a41f3365d 100644 --- a/third_party/github.com/coreos/go-log/log/sinks.go +++ b/third_party/github.com/coreos/go-log/log/sinks.go @@ -1,6 +1,5 @@ package log - -// Copyright 2013, David Fisher. All rights reserved. +// Copyright 2013, CoreOS, Inc. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/third_party/github.com/coreos/go-raft/server.go b/third_party/github.com/coreos/go-raft/server.go index e42e3ad62..b9b00e697 100644 --- a/third_party/github.com/coreos/go-raft/server.go +++ b/third_party/github.com/coreos/go-raft/server.go @@ -854,7 +854,7 @@ func (s *Server) processAppendEntriesResponse(resp *AppendEntriesResponse) { for _, peer := range s.peers { indices = append(indices, peer.getPrevLogIndex()) } - sort.Sort(uint64Slice(indices)) + sort.Sort(sort.Reverse(uint64Slice(indices))) // We can commit up to the index which the majority of the members have appended. commitIndex := indices[s.QuorumSize()-1] diff --git a/third_party/github.com/coreos/go-systemd/activation/files.go b/third_party/github.com/coreos/go-systemd/activation/files.go index eb60e77df..4b8542370 100644 --- a/third_party/github.com/coreos/go-systemd/activation/files.go +++ b/third_party/github.com/coreos/go-systemd/activation/files.go @@ -1,3 +1,4 @@ +// Package activation implements primitives for systemd socket activation. package activation import ( @@ -23,7 +24,7 @@ func Files() []*os.File { files := []*os.File(nil) for fd := listenFdsStart; fd < listenFdsStart+nfds; fd++ { syscall.CloseOnExec(fd) - files = append(files, os.NewFile(uintptr(fd), "LISTEN_FD_"+strconv.Itoa(fd))) + files = append(files, os.NewFile(uintptr(fd), "LISTEN_FD_" + strconv.Itoa(fd))) } return files } diff --git a/third_party/github.com/coreos/go-systemd/dbus/dbus.go b/third_party/github.com/coreos/go-systemd/dbus/dbus.go new file mode 100644 index 000000000..317f36552 --- /dev/null +++ b/third_party/github.com/coreos/go-systemd/dbus/dbus.go @@ -0,0 +1,100 @@ +// Integration with the systemd D-Bus API. See http://www.freedesktop.org/wiki/Software/systemd/dbus/ +package dbus + +import ( + "github.com/guelfey/go.dbus" + "sync" +) + +const signalBuffer = 100 + +type Conn struct { + sysconn *dbus.Conn + sysobj *dbus.Object + jobListener struct { + jobs map[dbus.ObjectPath]chan string + sync.Mutex + } + subscriber struct { + updateCh chan<- *SubStateUpdate + errCh chan<- error + sync.Mutex + ignore map[dbus.ObjectPath]int64 + cleanIgnore int64 + } + dispatch map[string]func(dbus.Signal) +} + +func New() *Conn { + c := new(Conn) + c.initConnection() + c.initJobs() + c.initSubscription() + c.initDispatch() + return c +} + +func (c *Conn) initConnection() { + var err error + c.sysconn, err = dbus.SystemBusPrivate() + if err != nil { + return + } + + err = c.sysconn.Auth(nil) + if err != nil { + c.sysconn.Close() + return + } + + err = c.sysconn.Hello() + if err != nil { + c.sysconn.Close() + return + } + + c.sysobj = c.sysconn.Object("org.freedesktop.systemd1", dbus.ObjectPath("/org/freedesktop/systemd1")) + + c.sysconn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0, + "type='signal',interface='org.freedesktop.systemd1.Manager',member='JobRemoved'") + c.sysconn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0, + "type='signal',interface='org.freedesktop.systemd1.Manager',member='UnitNew'") + c.sysconn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0, + "type='signal',interface='org.freedesktop.DBus.Properties',member='PropertiesChanged'") + + err = c.sysobj.Call("org.freedesktop.systemd1.Manager.Subscribe", 0).Store() + if err != nil { + c.sysconn.Close() + return + } +} + +func (c *Conn) initDispatch() { + ch := make(chan *dbus.Signal, signalBuffer) + + c.sysconn.Signal(ch) + + go func() { + for { + signal := <-ch + switch signal.Name { + case "org.freedesktop.systemd1.Manager.JobRemoved": + c.jobComplete(signal) + + unitName := signal.Body[2].(string) + var unitPath dbus.ObjectPath + c.sysobj.Call("GetUnit", 0, unitName).Store(&unitPath) + if unitPath != dbus.ObjectPath("") { + c.sendSubStateUpdate(unitPath) + } + case "org.freedesktop.systemd1.Manager.UnitNew": + c.sendSubStateUpdate(signal.Body[1].(dbus.ObjectPath)) + case "org.freedesktop.DBus.Properties.PropertiesChanged": + if signal.Body[0].(string) == "org.freedesktop.systemd1.Unit" { + // we only care about SubState updates, which are a Unit property + c.sendSubStateUpdate(signal.Path) + } + } + } + }() +} diff --git a/third_party/github.com/coreos/go-systemd/dbus/methods.go b/third_party/github.com/coreos/go-systemd/dbus/methods.go new file mode 100644 index 000000000..0e99cf5a7 --- /dev/null +++ b/third_party/github.com/coreos/go-systemd/dbus/methods.go @@ -0,0 +1,166 @@ +package dbus + +import ( + "github.com/guelfey/go.dbus" +) + +func (c *Conn) initJobs() { + c.jobListener.jobs = make(map[dbus.ObjectPath]chan string) +} + +func (c *Conn) jobComplete(signal *dbus.Signal) { + var id uint32 + var job dbus.ObjectPath + var unit string + var result string + dbus.Store(signal.Body, &id, &job, &unit, &result) + c.jobListener.Lock() + out, ok := c.jobListener.jobs[job] + if ok { + out <- result + } + c.jobListener.Unlock() +} + +func (c *Conn) startJob(job string, args ...interface{}) (<-chan string, error) { + c.jobListener.Lock() + defer c.jobListener.Unlock() + + ch := make(chan string, 1) + var path dbus.ObjectPath + err := c.sysobj.Call(job, 0, args...).Store(&path) + if err != nil { + return nil, err + } + c.jobListener.jobs[path] = ch + return ch, nil +} + +func (c *Conn) runJob(job string, args ...interface{}) (string, error) { + respCh, err := c.startJob(job, args...) + if err != nil { + return "", err + } + return <-respCh, nil +} + +// StartUnit enqeues a start job and depending jobs, if any (unless otherwise +// specified by the mode string). +// +// Takes the unit to activate, plus a mode string. The mode needs to be one of +// replace, fail, isolate, ignore-dependencies, ignore-requirements. If +// "replace" the call will start the unit and its dependencies, possibly +// replacing already queued jobs that conflict with this. If "fail" the call +// will start the unit and its dependencies, but will fail if this would change +// an already queued job. If "isolate" the call will start the unit in question +// and terminate all units that aren't dependencies of it. If +// "ignore-dependencies" it will start a unit but ignore all its dependencies. +// If "ignore-requirements" it will start a unit but only ignore the +// requirement dependencies. It is not recommended to make use of the latter +// two options. +// +// Result string: one of done, canceled, timeout, failed, dependency, skipped. +// done indicates successful execution of a job. canceled indicates that a job +// has been canceled before it finished execution. timeout indicates that the +// job timeout was reached. failed indicates that the job failed. dependency +// indicates that a job this job has been depending on failed and the job hence +// has been removed too. skipped indicates that a job was skipped because it +// didn't apply to the units current state. +func (c *Conn) StartUnit(name string, mode string) (string, error) { + return c.runJob("StartUnit", name, mode) +} + +// StopUnit is similar to StartUnit but stops the specified unit rather +// than starting it. +func (c *Conn) StopUnit(name string, mode string) (string, error) { + return c.runJob("StopUnit", name, mode) +} + +// ReloadUnit reloads a unit. Reloading is done only if the unit is already running and fails otherwise. +func (c *Conn) ReloadUnit(name string, mode string) (string, error) { + return c.runJob("ReloadUnit", name, mode) +} + +// RestartUnit restarts a service. If a service is restarted that isn't +// running it will be started. +func (c *Conn) RestartUnit(name string, mode string) (string, error) { + return c.runJob("RestartUnit", name, mode) +} + +// TryRestartUnit is like RestartUnit, except that a service that isn't running +// is not affected by the restart. +func (c *Conn) TryRestartUnit(name string, mode string) (string, error) { + return c.runJob("TryRestartUnit", name, mode) +} + +// ReloadOrRestart attempts a reload if the unit supports it and use a restart +// otherwise. +func (c *Conn) ReloadOrRestartUnit(name string, mode string) (string, error) { + return c.runJob("ReloadOrRestartUnit", name, mode) +} + +// ReloadOrTryRestart attempts a reload if the unit supports it and use a "Try" +// flavored restart otherwise. +func (c *Conn) ReloadOrTryRestartUnit(name string, mode string) (string, error) { + return c.runJob("ReloadOrTryRestartUnit", name, mode) +} + +// StartTransientUnit() may be used to create and start a transient unit, which +// will be released as soon as it is not running or referenced anymore or the +// system is rebooted. name is the unit name including suffix, and must be +// unique. mode is the same as in StartUnit(), properties contains properties +// of the unit. +func (c *Conn) StartTransientUnit(name string, mode string, properties ...Property) (string, error) { + // the dbus interface for this method does not use the last argument and + // should simply be given an empty list. We use a concrete type here + // (instead of the more appropriate interface{}) to satisfy the dbus library. + return c.runJob("StartTransientUnit", name, mode, properties, make([]string, 0)) +} + +// KillUnit takes the unit name and a UNIX signal number to send. All of the unit's +// processes are killed. +func (c *Conn) KillUnit(name string, signal int32) { + c.sysobj.Call("KillUnit", 0, name, "all", signal).Store() +} + +// ListUnits returns an array with all currently loaded units. Note that +// units may be known by multiple names at the same time, and hence there might +// be more unit names loaded than actual units behind them. +func (c *Conn) ListUnits() ([]UnitStatus, error) { + result := make([][]interface{}, 0) + err := c.sysobj.Call("ListUnits", 0).Store(&result) + if err != nil { + return nil, err + } + + resultInterface := make([]interface{}, len(result)) + for i := range result { + resultInterface[i] = result[i] + } + + status := make([]UnitStatus, len(result)) + statusInterface := make([]interface{}, len(status)) + for i := range status { + statusInterface[i] = &status[i] + } + + err = dbus.Store(resultInterface, statusInterface...) + if err != nil { + return nil, err + } + + return status, nil +} + +type UnitStatus struct { + Name string // The primary unit name as string + Description string // The human readable description string + LoadState string // The load state (i.e. whether the unit file has been loaded successfully) + ActiveState string // The active state (i.e. whether the unit is currently started or not) + SubState string // The sub state (a more fine-grained version of the active state that is specific to the unit type, which the active state is not) + Followed string // A unit that is being followed in its state by this unit, if there is any, otherwise the empty string. + Path dbus.ObjectPath // The unit object path + JobId uint32 // If there is a job queued for the job unit the numeric job id, 0 otherwise + JobType string // The job type as string + JobPath dbus.ObjectPath // The job object path +} diff --git a/third_party/github.com/coreos/go-systemd/dbus/properties.go b/third_party/github.com/coreos/go-systemd/dbus/properties.go new file mode 100644 index 000000000..36acf8660 --- /dev/null +++ b/third_party/github.com/coreos/go-systemd/dbus/properties.go @@ -0,0 +1,193 @@ +package dbus + +import ( + "github.com/guelfey/go.dbus" +) + +// From the systemd docs: +// +// The properties array of StartTransientUnit() may take many of the settings +// that may also be configured in unit files. Not all parameters are currently +// accepted though, but we plan to cover more properties with future release. +// Currently you may set the Description, Slice and all dependency types of +// units, as well as RemainAfterExit, ExecStart for service units, +// TimeoutStopUSec and PIDs for scope units, and CPUAccounting, CPUShares, +// BlockIOAccounting, BlockIOWeight, BlockIOReadBandwidth, +// BlockIOWriteBandwidth, BlockIODeviceWeight, MemoryAccounting, MemoryLimit, +// DevicePolicy, DeviceAllow for services/scopes/slices. These fields map +// directly to their counterparts in unit files and as normal D-Bus object +// properties. The exception here is the PIDs field of scope units which is +// used for construction of the scope only and specifies the initial PIDs to +// add to the scope object. + +type Property property + +type property struct { + Name string + Value dbus.Variant +} + +type execStart struct { + Path string // the binary path to execute + Args []string // an array with all arguments to pass to the executed command, starting with argument 0 + UncleanIsFailure bool // a boolean whether it should be considered a failure if the process exits uncleanly +} + +// PropExecStart sets the ExecStart service property. The first argument is a +// slice with the binary path to execute followed by the arguments to pass to +// the executed command. See +// http://www.freedesktop.org/software/systemd/man/systemd.service.html#ExecStart= +func PropExecStart(command []string, uncleanIsFailure bool) Property { + return Property( + property{ + Name: "ExecStart", + Value: dbus.MakeVariant( + []execStart{ + execStart{ + Path: command[0], + Args: command, + UncleanIsFailure: uncleanIsFailure, + }})}) +} + +// PropRemainAfterExit sets the RemainAfterExit service property. See +// http://www.freedesktop.org/software/systemd/man/systemd.service.html#RemainAfterExit= +func PropRemainAfterExit(b bool) Property { + return Property( + property{ + Name: "RemainAfterExit", + Value: dbus.MakeVariant(b), + }) +} + +// PropDescription sets the Description unit property. See +// http://www.freedesktop.org/software/systemd/man/systemd.unit#Description= +func PropDescription(desc string) Property { + return Property( + property{ + Name: "Description", + Value: dbus.MakeVariant(desc), + }) +} + +func propDependency(name string, units []string) Property { + return Property( + property{ + Name: name, + Value: dbus.MakeVariant(units), + }) +} + +// PropRequires sets the Requires unit property. See +// http://www.freedesktop.org/software/systemd/main/systemd.unit.html#Requires= +func PropRequires(units ...string) Property { + return propDependency("Requires", units) +} + +// PropRequiresOverridable sets the RequiresOverridable unit property. See +// http://www.freedesktop.org/software/systemd/main/systemd.unit.html#RequiresOverridable= +func PropRequiresOverridable(units ...string) Property { + return propDependency("RequiresOverridable", units) +} + +// PropRequisite sets the Requisite unit property. See +// http://www.freedesktop.org/software/systemd/main/systemd.unit.html#Requisite= +func PropRequisite(units ...string) Property { + return propDependency("Requisite", units) +} + +// PropRequisiteOverridable sets the RequisiteOverridable unit property. See +// http://www.freedesktop.org/software/systemd/main/systemd.unit.html#RequisiteOverridable= +func PropRequisiteOverridable(units ...string) Property { + return propDependency("RequisiteOverridable", units) +} + +// PropWants sets the Wants unit property. See +// http://www.freedesktop.org/software/systemd/main/systemd.unit.html#Wants= +func PropWants(units ...string) Property { + return propDependency("Wants", units) +} + +// PropBindsTo sets the BindsTo unit property. See +// http://www.freedesktop.org/software/systemd/main/systemd.unit.html#BindsTo= +func PropBindsTo(units ...string) Property { + return propDependency("BindsTo", units) +} + +// PropRequiredBy sets the RequiredBy unit property. See +// http://www.freedesktop.org/software/systemd/main/systemd.unit.html#RequiredBy= +func PropRequiredBy(units ...string) Property { + return propDependency("RequiredBy", units) +} + +// PropRequiredByOverridable sets the RequiredByOverridable unit property. See +// http://www.freedesktop.org/software/systemd/main/systemd.unit.html#RequiredByOverridable= +func PropRequiredByOverridable(units ...string) Property { + return propDependency("RequiredByOverridable", units) +} + +// PropWantedBy sets the WantedBy unit property. See +// http://www.freedesktop.org/software/systemd/main/systemd.unit.html#WantedBy= +func PropWantedBy(units ...string) Property { + return propDependency("WantedBy", units) +} + +// PropBoundBy sets the BoundBy unit property. See +// http://www.freedesktop.org/software/systemd/main/systemd.unit.html#BoundBy= +func PropBoundBy(units ...string) Property { + return propDependency("BoundBy", units) +} + +// PropConflicts sets the Conflicts unit property. See +// http://www.freedesktop.org/software/systemd/main/systemd.unit.html#Conflicts= +func PropConflicts(units ...string) Property { + return propDependency("Conflicts", units) +} + +// PropConflictedBy sets the ConflictedBy unit property. See +// http://www.freedesktop.org/software/systemd/main/systemd.unit.html#ConflictedBy= +func PropConflictedBy(units ...string) Property { + return propDependency("ConflictedBy", units) +} + +// PropBefore sets the Before unit property. See +// http://www.freedesktop.org/software/systemd/main/systemd.unit.html#Before= +func PropBefore(units ...string) Property { + return propDependency("Before", units) +} + +// PropAfter sets the After unit property. See +// http://www.freedesktop.org/software/systemd/main/systemd.unit.html#After= +func PropAfter(units ...string) Property { + return propDependency("After", units) +} + +// PropOnFailure sets the OnFailure unit property. See +// http://www.freedesktop.org/software/systemd/main/systemd.unit.html#OnFailure= +func PropOnFailure(units ...string) Property { + return propDependency("OnFailure", units) +} + +// PropTriggers sets the Triggers unit property. See +// http://www.freedesktop.org/software/systemd/main/systemd.unit.html#Triggers= +func PropTriggers(units ...string) Property { + return propDependency("Triggers", units) +} + +// PropTriggeredBy sets the TriggeredBy unit property. See +// http://www.freedesktop.org/software/systemd/main/systemd.unit.html#TriggeredBy= +func PropTriggeredBy(units ...string) Property { + return propDependency("TriggeredBy", units) +} + +// PropPropagatesReloadTo sets the PropagatesReloadTo unit property. See +// http://www.freedesktop.org/software/systemd/main/systemd.unit.html#PropagatesReloadTo= +func PropPropagatesReloadTo(units ...string) Property { + return propDependency("PropagatesReloadTo", units) +} + +// PropRequiresMountsFor sets the RequiresMountsFor unit property. See +// http://www.freedesktop.org/software/systemd/main/systemd.unit.html#RequiresMountsFor= +func PropRequiresMountsFor(units ...string) Property { + return propDependency("RequiresMountsFor", units) +} diff --git a/third_party/github.com/coreos/go-systemd/dbus/subscription.go b/third_party/github.com/coreos/go-systemd/dbus/subscription.go new file mode 100644 index 000000000..606a5736d --- /dev/null +++ b/third_party/github.com/coreos/go-systemd/dbus/subscription.go @@ -0,0 +1,182 @@ +package dbus + +import ( + "github.com/guelfey/go.dbus" + "time" +) + +const ( + cleanIgnoreInterval = int64(10 * time.Second) + ignoreInterval = int64(30 * time.Millisecond) +) + +func (c *Conn) initSubscription() { + c.subscriber.ignore = make(map[dbus.ObjectPath]int64) +} + +// Returns two unbuffered channels which will receive all changed units every +// @interval@ seconds. Deleted units are sent as nil. +func (c *Conn) SubscribeUnits(interval time.Duration) (<-chan map[string]*UnitStatus, <-chan error) { + return c.SubscribeUnitsCustom(interval, 0, func(u1, u2 *UnitStatus) bool { return *u1 != *u2 }) +} + +// SubscribeUnitsCustom is like SubscribeUnits but lets you specify the buffer +// size of the channels and the comparison function for detecting changes. +func (c *Conn) SubscribeUnitsCustom(interval time.Duration, buffer int, isChanged func(*UnitStatus, *UnitStatus) bool) (<-chan map[string]*UnitStatus, <-chan error) { + old := make(map[string]*UnitStatus) + statusChan := make(chan map[string]*UnitStatus, buffer) + errChan := make(chan error, buffer) + + go func() { + for { + timerChan := time.After(interval) + + units, err := c.ListUnits() + if err == nil { + cur := make(map[string]*UnitStatus) + for i := range units { + cur[units[i].Name] = &units[i] + } + + // add all new or changed units + changed := make(map[string]*UnitStatus) + for n, u := range cur { + if oldU, ok := old[n]; !ok || isChanged(oldU, u) { + changed[n] = u + } + delete(old, n) + } + + // add all deleted units + for oldN := range old { + changed[oldN] = nil + } + + old = cur + + statusChan <- changed + } else { + errChan <- err + } + + <-timerChan + } + }() + + return statusChan, errChan +} + +type SubStateUpdate struct { + UnitName string + SubState string +} + +type Error string + +func (e Error) Error() string { + return string(e) +} + +// SetSubStateSubscriber writes to updateCh when any unit's substate changes. +// Althrough this writes to updateCh on every state change, the reported state +// may be more recent than the change that generated it (due to an unavoidable +// race in the systemd dbus interface). That is, this method provides a good +// way to keep a current view of all units' states, but is not guaranteed to +// show every state transition they go through. Furthermore, state changes +// will only be written to the channel with non-blocking writes. If updateCh +// is full, it attempts to write an error to errCh; if errCh is full, the error +// passes silently. +func (c *Conn) SetSubStateSubscriber(updateCh chan<- *SubStateUpdate, errCh chan<- error) { + c.subscriber.Lock() + defer c.subscriber.Unlock() + c.subscriber.updateCh = updateCh + c.subscriber.errCh = errCh +} + +func (c *Conn) sendSubStateUpdate(path dbus.ObjectPath) { + c.subscriber.Lock() + defer c.subscriber.Unlock() + if c.subscriber.updateCh == nil { + return + } + + if c.shouldIgnore(path) { + return + } + + info, err := c.getUnitInfo(path) + if err != nil { + select { + case c.subscriber.errCh <- err: + default: + } + } + + name := info["Id"].Value().(string) + substate := info["SubState"].Value().(string) + + update := &SubStateUpdate{name, substate} + select { + case c.subscriber.updateCh <- update: + default: + select { + case c.subscriber.errCh <- Error("update channel full!"): + default: + } + } + + c.updateIgnore(path, info) +} + +func (c *Conn) getUnitInfo(path dbus.ObjectPath) (map[string]dbus.Variant, error) { + var err error + var props map[string]dbus.Variant + obj := c.sysconn.Object("org.freedesktop.systemd1", path) + err = obj.Call("GetAll", 0, "org.freedesktop.systemd1.Unit").Store(&props) + if err != nil { + return nil, err + } + return props, nil +} + +// The ignore functions work around a wart in the systemd dbus interface. +// Requesting the properties of an unloaded unit will cause systemd to send a +// pair of UnitNew/UnitRemoved signals. Because we need to get a unit's +// properties on UnitNew (as that's the only indication of a new unit coming up +// for the first time), we would enter an infinite loop if we did not attempt +// to detect and ignore these spurious signals. The signal themselves are +// indistinguishable from relevant ones, so we (somewhat hackishly) ignore an +// unloaded unit's signals for a short time after requesting its properties. +// This means that we will miss e.g. a transient unit being restarted +// *immediately* upon failure and also a transient unit being started +// immediately after requesting its status (with systemctl status, for example, +// because this causes a UnitNew signal to be sent which then causes us to fetch +// the properties). + +func (c *Conn) shouldIgnore(path dbus.ObjectPath) bool { + t, ok := c.subscriber.ignore[path] + return ok && t >= time.Now().UnixNano() +} + +func (c *Conn) updateIgnore(path dbus.ObjectPath, info map[string]dbus.Variant) { + c.cleanIgnore() + + // unit is unloaded - it will trigger bad systemd dbus behavior + if info["LoadState"].Value().(string) == "not-found" { + c.subscriber.ignore[path] = time.Now().UnixNano() + ignoreInterval + } +} + +// without this, ignore would grow unboundedly over time +func (c *Conn) cleanIgnore() { + now := time.Now().UnixNano() + if c.subscriber.cleanIgnore < now { + c.subscriber.cleanIgnore = now + cleanIgnoreInterval + + for p, t := range c.subscriber.ignore { + if t < now { + delete(c.subscriber.ignore, p) + } + } + } +} diff --git a/third_party/github.com/coreos/go-systemd/journal/send.go b/third_party/github.com/coreos/go-systemd/journal/send.go index 89bcab164..e288bb039 100644 --- a/third_party/github.com/coreos/go-systemd/journal/send.go +++ b/third_party/github.com/coreos/go-systemd/journal/send.go @@ -32,7 +32,11 @@ const ( var conn net.Conn func init() { - conn, _ = net.Dial("unixgram", "/run/systemd/journal/socket") + var err error + conn, err = net.Dial("unixgram", "/run/systemd/journal/socket") + if err != nil { + conn = nil + } } // Enabled returns true iff the systemd journal is available for logging