Update vendoring (#1105)
* Update vendor github.com/sirupsen/logrus@v1.1.1 * Update vendor github.com/coreos/go-systemd/dbus@v17 * Update vendor github.com/golang/protobuf/proto@v1.2.0 * Update vendor github.com/konsorten/go-windows-terminal-sequences@v1.0.1 * Update vendor github.com/mdlayher/... * Update vendor github.com/prometheus/procfs/... * Update vendor golang.org/x/... Signed-off-by: Ben Kochie <superq@gmail.com>pull/1110/head
parent
f0d2a06b11
commit
9cf508e673
|
@ -313,6 +313,7 @@ func (c *Conn) ListUnitsByPatterns(states []string, patterns []string) ([]UnitSt
|
|||
// names and returns an UnitStatus array. Comparing to ListUnitsByPatterns
|
||||
// method, this method returns statuses even for inactive or non-existing
|
||||
// units. Input array should contain exact unit names, but not patterns.
|
||||
// Note: Requires systemd v230 or higher
|
||||
func (c *Conn) ListUnitsByNames(units []string) ([]UnitStatus, error) {
|
||||
return c.listUnitsInternal(c.sysobj.Call("org.freedesktop.systemd1.Manager.ListUnitsByNames", 0, units).Store)
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ func (s *set) Length() int {
|
|||
}
|
||||
|
||||
func (s *set) Values() (values []string) {
|
||||
for val, _ := range s.data {
|
||||
for val := range s.data {
|
||||
values = append(values, val)
|
||||
}
|
||||
return
|
||||
|
|
|
@ -37,22 +37,12 @@ func (c *Conn) Subscribe() error {
|
|||
c.sigconn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0,
|
||||
"type='signal',interface='org.freedesktop.DBus.Properties',member='PropertiesChanged'")
|
||||
|
||||
err := c.sigobj.Call("org.freedesktop.systemd1.Manager.Subscribe", 0).Store()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
return c.sigobj.Call("org.freedesktop.systemd1.Manager.Subscribe", 0).Store()
|
||||
}
|
||||
|
||||
// Unsubscribe this connection from systemd dbus events.
|
||||
func (c *Conn) Unsubscribe() error {
|
||||
err := c.sigobj.Call("org.freedesktop.systemd1.Manager.Unsubscribe", 0).Store()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
return c.sigobj.Call("org.freedesktop.systemd1.Manager.Unsubscribe", 0).Store()
|
||||
}
|
||||
|
||||
func (c *Conn) dispatch() {
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
Go support for Protocol Buffers - Google's data interchange format
|
||||
|
||||
Copyright 2010 The Go Authors. All rights reserved.
|
||||
https://github.com/golang/protobuf
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
|
|
|
@ -1,43 +0,0 @@
|
|||
# Go support for Protocol Buffers - Google's data interchange format
|
||||
#
|
||||
# Copyright 2010 The Go Authors. All rights reserved.
|
||||
# https://github.com/golang/protobuf
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following disclaimer
|
||||
# in the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
# * Neither the name of Google Inc. nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from
|
||||
# this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
install:
|
||||
go install
|
||||
|
||||
test: install generate-test-pbs
|
||||
go test
|
||||
|
||||
|
||||
generate-test-pbs:
|
||||
make install
|
||||
make -C testdata
|
||||
protoc --go_out=Mtestdata/test.proto=github.com/golang/protobuf/proto/testdata,Mgoogle/protobuf/any.proto=github.com/golang/protobuf/ptypes/any:. proto3_proto/proto3.proto
|
||||
make
|
|
@ -35,22 +35,39 @@
|
|||
package proto
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Clone returns a deep copy of a protocol buffer.
|
||||
func Clone(pb Message) Message {
|
||||
in := reflect.ValueOf(pb)
|
||||
func Clone(src Message) Message {
|
||||
in := reflect.ValueOf(src)
|
||||
if in.IsNil() {
|
||||
return pb
|
||||
return src
|
||||
}
|
||||
|
||||
out := reflect.New(in.Type().Elem())
|
||||
// out is empty so a merge is a deep copy.
|
||||
mergeStruct(out.Elem(), in.Elem())
|
||||
return out.Interface().(Message)
|
||||
dst := out.Interface().(Message)
|
||||
Merge(dst, src)
|
||||
return dst
|
||||
}
|
||||
|
||||
// Merger is the interface representing objects that can merge messages of the same type.
|
||||
type Merger interface {
|
||||
// Merge merges src into this message.
|
||||
// Required and optional fields that are set in src will be set to that value in dst.
|
||||
// Elements of repeated fields will be appended.
|
||||
//
|
||||
// Merge may panic if called with a different argument type than the receiver.
|
||||
Merge(src Message)
|
||||
}
|
||||
|
||||
// generatedMerger is the custom merge method that generated protos will have.
|
||||
// We must add this method since a generate Merge method will conflict with
|
||||
// many existing protos that have a Merge data field already defined.
|
||||
type generatedMerger interface {
|
||||
XXX_Merge(src Message)
|
||||
}
|
||||
|
||||
// Merge merges src into dst.
|
||||
|
@ -58,17 +75,24 @@ func Clone(pb Message) Message {
|
|||
// Elements of repeated fields will be appended.
|
||||
// Merge panics if src and dst are not the same type, or if dst is nil.
|
||||
func Merge(dst, src Message) {
|
||||
if m, ok := dst.(Merger); ok {
|
||||
m.Merge(src)
|
||||
return
|
||||
}
|
||||
|
||||
in := reflect.ValueOf(src)
|
||||
out := reflect.ValueOf(dst)
|
||||
if out.IsNil() {
|
||||
panic("proto: nil destination")
|
||||
}
|
||||
if in.Type() != out.Type() {
|
||||
// Explicit test prior to mergeStruct so that mistyped nils will fail
|
||||
panic("proto: type mismatch")
|
||||
panic(fmt.Sprintf("proto.Merge(%T, %T) type mismatch", dst, src))
|
||||
}
|
||||
if in.IsNil() {
|
||||
// Merging nil into non-nil is a quiet no-op
|
||||
return // Merge from nil src is a noop
|
||||
}
|
||||
if m, ok := dst.(generatedMerger); ok {
|
||||
m.XXX_Merge(src)
|
||||
return
|
||||
}
|
||||
mergeStruct(out.Elem(), in.Elem())
|
||||
|
@ -84,7 +108,7 @@ func mergeStruct(out, in reflect.Value) {
|
|||
mergeAny(out.Field(i), in.Field(i), false, sprop.Prop[i])
|
||||
}
|
||||
|
||||
if emIn, ok := extendable(in.Addr().Interface()); ok {
|
||||
if emIn, err := extendable(in.Addr().Interface()); err == nil {
|
||||
emOut, _ := extendable(out.Addr().Interface())
|
||||
mIn, muIn := emIn.extensionsRead()
|
||||
if mIn != nil {
|
||||
|
|
|
@ -39,8 +39,6 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// errOverflow is returned when an integer is too large to be represented.
|
||||
|
@ -50,10 +48,6 @@ var errOverflow = errors.New("proto: integer overflow")
|
|||
// wire type is encountered. It does not get returned to user code.
|
||||
var ErrInternalBadWireType = errors.New("proto: internal error: bad wiretype for oneof")
|
||||
|
||||
// The fundamental decoders that interpret bytes on the wire.
|
||||
// Those that take integer types all return uint64 and are
|
||||
// therefore of type valueDecoder.
|
||||
|
||||
// DecodeVarint reads a varint-encoded integer from the slice.
|
||||
// It returns the integer and the number of bytes consumed, or
|
||||
// zero if there is not enough.
|
||||
|
@ -267,9 +261,6 @@ func (p *Buffer) DecodeZigzag32() (x uint64, err error) {
|
|||
return
|
||||
}
|
||||
|
||||
// These are not ValueDecoders: they produce an array of bytes or a string.
|
||||
// bytes, embedded messages
|
||||
|
||||
// DecodeRawBytes reads a count-delimited byte buffer from the Buffer.
|
||||
// This is the format used for the bytes protocol buffer
|
||||
// type and for embedded messages.
|
||||
|
@ -311,81 +302,29 @@ func (p *Buffer) DecodeStringBytes() (s string, err error) {
|
|||
return string(buf), nil
|
||||
}
|
||||
|
||||
// Skip the next item in the buffer. Its wire type is decoded and presented as an argument.
|
||||
// If the protocol buffer has extensions, and the field matches, add it as an extension.
|
||||
// Otherwise, if the XXX_unrecognized field exists, append the skipped data there.
|
||||
func (o *Buffer) skipAndSave(t reflect.Type, tag, wire int, base structPointer, unrecField field) error {
|
||||
oi := o.index
|
||||
|
||||
err := o.skip(t, tag, wire)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !unrecField.IsValid() {
|
||||
return nil
|
||||
}
|
||||
|
||||
ptr := structPointer_Bytes(base, unrecField)
|
||||
|
||||
// Add the skipped field to struct field
|
||||
obuf := o.buf
|
||||
|
||||
o.buf = *ptr
|
||||
o.EncodeVarint(uint64(tag<<3 | wire))
|
||||
*ptr = append(o.buf, obuf[oi:o.index]...)
|
||||
|
||||
o.buf = obuf
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Skip the next item in the buffer. Its wire type is decoded and presented as an argument.
|
||||
func (o *Buffer) skip(t reflect.Type, tag, wire int) error {
|
||||
|
||||
var u uint64
|
||||
var err error
|
||||
|
||||
switch wire {
|
||||
case WireVarint:
|
||||
_, err = o.DecodeVarint()
|
||||
case WireFixed64:
|
||||
_, err = o.DecodeFixed64()
|
||||
case WireBytes:
|
||||
_, err = o.DecodeRawBytes(false)
|
||||
case WireFixed32:
|
||||
_, err = o.DecodeFixed32()
|
||||
case WireStartGroup:
|
||||
for {
|
||||
u, err = o.DecodeVarint()
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
fwire := int(u & 0x7)
|
||||
if fwire == WireEndGroup {
|
||||
break
|
||||
}
|
||||
ftag := int(u >> 3)
|
||||
err = o.skip(t, ftag, fwire)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
default:
|
||||
err = fmt.Errorf("proto: can't skip unknown wire type %d for %s", wire, t)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Unmarshaler is the interface representing objects that can
|
||||
// unmarshal themselves. The method should reset the receiver before
|
||||
// decoding starts. The argument points to data that may be
|
||||
// unmarshal themselves. The argument points to data that may be
|
||||
// overwritten, so implementations should not keep references to the
|
||||
// buffer.
|
||||
// Unmarshal implementations should not clear the receiver.
|
||||
// Any unmarshaled data should be merged into the receiver.
|
||||
// Callers of Unmarshal that do not want to retain existing data
|
||||
// should Reset the receiver before calling Unmarshal.
|
||||
type Unmarshaler interface {
|
||||
Unmarshal([]byte) error
|
||||
}
|
||||
|
||||
// newUnmarshaler is the interface representing objects that can
|
||||
// unmarshal themselves. The semantics are identical to Unmarshaler.
|
||||
//
|
||||
// This exists to support protoc-gen-go generated messages.
|
||||
// The proto package will stop type-asserting to this interface in the future.
|
||||
//
|
||||
// DO NOT DEPEND ON THIS.
|
||||
type newUnmarshaler interface {
|
||||
XXX_Unmarshal([]byte) error
|
||||
}
|
||||
|
||||
// Unmarshal parses the protocol buffer representation in buf and places the
|
||||
// decoded result in pb. If the struct underlying pb does not match
|
||||
// the data in buf, the results can be unpredictable.
|
||||
|
@ -395,7 +334,13 @@ type Unmarshaler interface {
|
|||
// to preserve and append to existing data.
|
||||
func Unmarshal(buf []byte, pb Message) error {
|
||||
pb.Reset()
|
||||
return UnmarshalMerge(buf, pb)
|
||||
if u, ok := pb.(newUnmarshaler); ok {
|
||||
return u.XXX_Unmarshal(buf)
|
||||
}
|
||||
if u, ok := pb.(Unmarshaler); ok {
|
||||
return u.Unmarshal(buf)
|
||||
}
|
||||
return NewBuffer(buf).Unmarshal(pb)
|
||||
}
|
||||
|
||||
// UnmarshalMerge parses the protocol buffer representation in buf and
|
||||
|
@ -405,8 +350,16 @@ func Unmarshal(buf []byte, pb Message) error {
|
|||
// UnmarshalMerge merges into existing data in pb.
|
||||
// Most code should use Unmarshal instead.
|
||||
func UnmarshalMerge(buf []byte, pb Message) error {
|
||||
// If the object can unmarshal itself, let it.
|
||||
if u, ok := pb.(newUnmarshaler); ok {
|
||||
return u.XXX_Unmarshal(buf)
|
||||
}
|
||||
if u, ok := pb.(Unmarshaler); ok {
|
||||
// NOTE: The history of proto have unfortunately been inconsistent
|
||||
// whether Unmarshaler should or should not implicitly clear itself.
|
||||
// Some implementations do, most do not.
|
||||
// Thus, calling this here may or may not do what people want.
|
||||
//
|
||||
// See https://github.com/golang/protobuf/issues/424
|
||||
return u.Unmarshal(buf)
|
||||
}
|
||||
return NewBuffer(buf).Unmarshal(pb)
|
||||
|
@ -422,12 +375,17 @@ func (p *Buffer) DecodeMessage(pb Message) error {
|
|||
}
|
||||
|
||||
// DecodeGroup reads a tag-delimited group from the Buffer.
|
||||
// StartGroup tag is already consumed. This function consumes
|
||||
// EndGroup tag.
|
||||
func (p *Buffer) DecodeGroup(pb Message) error {
|
||||
typ, base, err := getbase(pb)
|
||||
if err != nil {
|
||||
return err
|
||||
b := p.buf[p.index:]
|
||||
x, y := findEndGroup(b)
|
||||
if x < 0 {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
return p.unmarshalType(typ.Elem(), GetProperties(typ.Elem()), true, base)
|
||||
err := Unmarshal(b[:x], pb)
|
||||
p.index += y
|
||||
return err
|
||||
}
|
||||
|
||||
// Unmarshal parses the protocol buffer representation in the
|
||||
|
@ -438,533 +396,33 @@ func (p *Buffer) DecodeGroup(pb Message) error {
|
|||
// Unlike proto.Unmarshal, this does not reset pb before starting to unmarshal.
|
||||
func (p *Buffer) Unmarshal(pb Message) error {
|
||||
// If the object can unmarshal itself, let it.
|
||||
if u, ok := pb.(newUnmarshaler); ok {
|
||||
err := u.XXX_Unmarshal(p.buf[p.index:])
|
||||
p.index = len(p.buf)
|
||||
return err
|
||||
}
|
||||
if u, ok := pb.(Unmarshaler); ok {
|
||||
// NOTE: The history of proto have unfortunately been inconsistent
|
||||
// whether Unmarshaler should or should not implicitly clear itself.
|
||||
// Some implementations do, most do not.
|
||||
// Thus, calling this here may or may not do what people want.
|
||||
//
|
||||
// See https://github.com/golang/protobuf/issues/424
|
||||
err := u.Unmarshal(p.buf[p.index:])
|
||||
p.index = len(p.buf)
|
||||
return err
|
||||
}
|
||||
|
||||
typ, base, err := getbase(pb)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = p.unmarshalType(typ.Elem(), GetProperties(typ.Elem()), false, base)
|
||||
|
||||
if collectStats {
|
||||
stats.Decode++
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// unmarshalType does the work of unmarshaling a structure.
|
||||
func (o *Buffer) unmarshalType(st reflect.Type, prop *StructProperties, is_group bool, base structPointer) error {
|
||||
var state errorState
|
||||
required, reqFields := prop.reqCount, uint64(0)
|
||||
|
||||
var err error
|
||||
for err == nil && o.index < len(o.buf) {
|
||||
oi := o.index
|
||||
var u uint64
|
||||
u, err = o.DecodeVarint()
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
wire := int(u & 0x7)
|
||||
if wire == WireEndGroup {
|
||||
if is_group {
|
||||
if required > 0 {
|
||||
// Not enough information to determine the exact field.
|
||||
// (See below.)
|
||||
return &RequiredNotSetError{"{Unknown}"}
|
||||
}
|
||||
return nil // input is satisfied
|
||||
}
|
||||
return fmt.Errorf("proto: %s: wiretype end group for non-group", st)
|
||||
}
|
||||
tag := int(u >> 3)
|
||||
if tag <= 0 {
|
||||
return fmt.Errorf("proto: %s: illegal tag %d (wire type %d)", st, tag, wire)
|
||||
}
|
||||
fieldnum, ok := prop.decoderTags.get(tag)
|
||||
if !ok {
|
||||
// Maybe it's an extension?
|
||||
if prop.extendable {
|
||||
if e, _ := extendable(structPointer_Interface(base, st)); isExtensionField(e, int32(tag)) {
|
||||
if err = o.skip(st, tag, wire); err == nil {
|
||||
extmap := e.extensionsWrite()
|
||||
ext := extmap[int32(tag)] // may be missing
|
||||
ext.enc = append(ext.enc, o.buf[oi:o.index]...)
|
||||
extmap[int32(tag)] = ext
|
||||
}
|
||||
continue
|
||||
}
|
||||
}
|
||||
// Maybe it's a oneof?
|
||||
if prop.oneofUnmarshaler != nil {
|
||||
m := structPointer_Interface(base, st).(Message)
|
||||
// First return value indicates whether tag is a oneof field.
|
||||
ok, err = prop.oneofUnmarshaler(m, tag, wire, o)
|
||||
if err == ErrInternalBadWireType {
|
||||
// Map the error to something more descriptive.
|
||||
// Do the formatting here to save generated code space.
|
||||
err = fmt.Errorf("bad wiretype for oneof field in %T", m)
|
||||
}
|
||||
if ok {
|
||||
continue
|
||||
}
|
||||
}
|
||||
err = o.skipAndSave(st, tag, wire, base, prop.unrecField)
|
||||
continue
|
||||
}
|
||||
p := prop.Prop[fieldnum]
|
||||
|
||||
if p.dec == nil {
|
||||
fmt.Fprintf(os.Stderr, "proto: no protobuf decoder for %s.%s\n", st, st.Field(fieldnum).Name)
|
||||
continue
|
||||
}
|
||||
dec := p.dec
|
||||
if wire != WireStartGroup && wire != p.WireType {
|
||||
if wire == WireBytes && p.packedDec != nil {
|
||||
// a packable field
|
||||
dec = p.packedDec
|
||||
} else {
|
||||
err = fmt.Errorf("proto: bad wiretype for field %s.%s: got wiretype %d, want %d", st, st.Field(fieldnum).Name, wire, p.WireType)
|
||||
continue
|
||||
}
|
||||
}
|
||||
decErr := dec(o, p, base)
|
||||
if decErr != nil && !state.shouldContinue(decErr, p) {
|
||||
err = decErr
|
||||
}
|
||||
if err == nil && p.Required {
|
||||
// Successfully decoded a required field.
|
||||
if tag <= 64 {
|
||||
// use bitmap for fields 1-64 to catch field reuse.
|
||||
var mask uint64 = 1 << uint64(tag-1)
|
||||
if reqFields&mask == 0 {
|
||||
// new required field
|
||||
reqFields |= mask
|
||||
required--
|
||||
}
|
||||
} else {
|
||||
// This is imprecise. It can be fooled by a required field
|
||||
// with a tag > 64 that is encoded twice; that's very rare.
|
||||
// A fully correct implementation would require allocating
|
||||
// a data structure, which we would like to avoid.
|
||||
required--
|
||||
}
|
||||
}
|
||||
}
|
||||
if err == nil {
|
||||
if is_group {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
if state.err != nil {
|
||||
return state.err
|
||||
}
|
||||
if required > 0 {
|
||||
// Not enough information to determine the exact field. If we use extra
|
||||
// CPU, we could determine the field only if the missing required field
|
||||
// has a tag <= 64 and we check reqFields.
|
||||
return &RequiredNotSetError{"{Unknown}"}
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Individual type decoders
|
||||
// For each,
|
||||
// u is the decoded value,
|
||||
// v is a pointer to the field (pointer) in the struct
|
||||
|
||||
// Sizes of the pools to allocate inside the Buffer.
|
||||
// The goal is modest amortization and allocation
|
||||
// on at least 16-byte boundaries.
|
||||
const (
|
||||
boolPoolSize = 16
|
||||
uint32PoolSize = 8
|
||||
uint64PoolSize = 4
|
||||
)
|
||||
|
||||
// Decode a bool.
|
||||
func (o *Buffer) dec_bool(p *Properties, base structPointer) error {
|
||||
u, err := p.valDec(o)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(o.bools) == 0 {
|
||||
o.bools = make([]bool, boolPoolSize)
|
||||
}
|
||||
o.bools[0] = u != 0
|
||||
*structPointer_Bool(base, p.field) = &o.bools[0]
|
||||
o.bools = o.bools[1:]
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *Buffer) dec_proto3_bool(p *Properties, base structPointer) error {
|
||||
u, err := p.valDec(o)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*structPointer_BoolVal(base, p.field) = u != 0
|
||||
return nil
|
||||
}
|
||||
|
||||
// Decode an int32.
|
||||
func (o *Buffer) dec_int32(p *Properties, base structPointer) error {
|
||||
u, err := p.valDec(o)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
word32_Set(structPointer_Word32(base, p.field), o, uint32(u))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *Buffer) dec_proto3_int32(p *Properties, base structPointer) error {
|
||||
u, err := p.valDec(o)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
word32Val_Set(structPointer_Word32Val(base, p.field), uint32(u))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Decode an int64.
|
||||
func (o *Buffer) dec_int64(p *Properties, base structPointer) error {
|
||||
u, err := p.valDec(o)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
word64_Set(structPointer_Word64(base, p.field), o, u)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *Buffer) dec_proto3_int64(p *Properties, base structPointer) error {
|
||||
u, err := p.valDec(o)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
word64Val_Set(structPointer_Word64Val(base, p.field), o, u)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Decode a string.
|
||||
func (o *Buffer) dec_string(p *Properties, base structPointer) error {
|
||||
s, err := o.DecodeStringBytes()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*structPointer_String(base, p.field) = &s
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *Buffer) dec_proto3_string(p *Properties, base structPointer) error {
|
||||
s, err := o.DecodeStringBytes()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*structPointer_StringVal(base, p.field) = s
|
||||
return nil
|
||||
}
|
||||
|
||||
// Decode a slice of bytes ([]byte).
|
||||
func (o *Buffer) dec_slice_byte(p *Properties, base structPointer) error {
|
||||
b, err := o.DecodeRawBytes(true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*structPointer_Bytes(base, p.field) = b
|
||||
return nil
|
||||
}
|
||||
|
||||
// Decode a slice of bools ([]bool).
|
||||
func (o *Buffer) dec_slice_bool(p *Properties, base structPointer) error {
|
||||
u, err := p.valDec(o)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
v := structPointer_BoolSlice(base, p.field)
|
||||
*v = append(*v, u != 0)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Decode a slice of bools ([]bool) in packed format.
|
||||
func (o *Buffer) dec_slice_packed_bool(p *Properties, base structPointer) error {
|
||||
v := structPointer_BoolSlice(base, p.field)
|
||||
|
||||
nn, err := o.DecodeVarint()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
nb := int(nn) // number of bytes of encoded bools
|
||||
fin := o.index + nb
|
||||
if fin < o.index {
|
||||
return errOverflow
|
||||
}
|
||||
|
||||
y := *v
|
||||
for o.index < fin {
|
||||
u, err := p.valDec(o)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
y = append(y, u != 0)
|
||||
}
|
||||
|
||||
*v = y
|
||||
return nil
|
||||
}
|
||||
|
||||
// Decode a slice of int32s ([]int32).
|
||||
func (o *Buffer) dec_slice_int32(p *Properties, base structPointer) error {
|
||||
u, err := p.valDec(o)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
structPointer_Word32Slice(base, p.field).Append(uint32(u))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Decode a slice of int32s ([]int32) in packed format.
|
||||
func (o *Buffer) dec_slice_packed_int32(p *Properties, base structPointer) error {
|
||||
v := structPointer_Word32Slice(base, p.field)
|
||||
|
||||
nn, err := o.DecodeVarint()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
nb := int(nn) // number of bytes of encoded int32s
|
||||
|
||||
fin := o.index + nb
|
||||
if fin < o.index {
|
||||
return errOverflow
|
||||
}
|
||||
for o.index < fin {
|
||||
u, err := p.valDec(o)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
v.Append(uint32(u))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Decode a slice of int64s ([]int64).
|
||||
func (o *Buffer) dec_slice_int64(p *Properties, base structPointer) error {
|
||||
u, err := p.valDec(o)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
structPointer_Word64Slice(base, p.field).Append(u)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Decode a slice of int64s ([]int64) in packed format.
|
||||
func (o *Buffer) dec_slice_packed_int64(p *Properties, base structPointer) error {
|
||||
v := structPointer_Word64Slice(base, p.field)
|
||||
|
||||
nn, err := o.DecodeVarint()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
nb := int(nn) // number of bytes of encoded int64s
|
||||
|
||||
fin := o.index + nb
|
||||
if fin < o.index {
|
||||
return errOverflow
|
||||
}
|
||||
for o.index < fin {
|
||||
u, err := p.valDec(o)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
v.Append(u)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Decode a slice of strings ([]string).
|
||||
func (o *Buffer) dec_slice_string(p *Properties, base structPointer) error {
|
||||
s, err := o.DecodeStringBytes()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
v := structPointer_StringSlice(base, p.field)
|
||||
*v = append(*v, s)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Decode a slice of slice of bytes ([][]byte).
|
||||
func (o *Buffer) dec_slice_slice_byte(p *Properties, base structPointer) error {
|
||||
b, err := o.DecodeRawBytes(true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
v := structPointer_BytesSlice(base, p.field)
|
||||
*v = append(*v, b)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Decode a map field.
|
||||
func (o *Buffer) dec_new_map(p *Properties, base structPointer) error {
|
||||
raw, err := o.DecodeRawBytes(false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
oi := o.index // index at the end of this map entry
|
||||
o.index -= len(raw) // move buffer back to start of map entry
|
||||
|
||||
mptr := structPointer_NewAt(base, p.field, p.mtype) // *map[K]V
|
||||
if mptr.Elem().IsNil() {
|
||||
mptr.Elem().Set(reflect.MakeMap(mptr.Type().Elem()))
|
||||
}
|
||||
v := mptr.Elem() // map[K]V
|
||||
|
||||
// Prepare addressable doubly-indirect placeholders for the key and value types.
|
||||
// See enc_new_map for why.
|
||||
keyptr := reflect.New(reflect.PtrTo(p.mtype.Key())).Elem() // addressable *K
|
||||
keybase := toStructPointer(keyptr.Addr()) // **K
|
||||
|
||||
var valbase structPointer
|
||||
var valptr reflect.Value
|
||||
switch p.mtype.Elem().Kind() {
|
||||
case reflect.Slice:
|
||||
// []byte
|
||||
var dummy []byte
|
||||
valptr = reflect.ValueOf(&dummy) // *[]byte
|
||||
valbase = toStructPointer(valptr) // *[]byte
|
||||
case reflect.Ptr:
|
||||
// message; valptr is **Msg; need to allocate the intermediate pointer
|
||||
valptr = reflect.New(reflect.PtrTo(p.mtype.Elem())).Elem() // addressable *V
|
||||
valptr.Set(reflect.New(valptr.Type().Elem()))
|
||||
valbase = toStructPointer(valptr)
|
||||
default:
|
||||
// everything else
|
||||
valptr = reflect.New(reflect.PtrTo(p.mtype.Elem())).Elem() // addressable *V
|
||||
valbase = toStructPointer(valptr.Addr()) // **V
|
||||
}
|
||||
|
||||
// Decode.
|
||||
// This parses a restricted wire format, namely the encoding of a message
|
||||
// with two fields. See enc_new_map for the format.
|
||||
for o.index < oi {
|
||||
// tagcode for key and value properties are always a single byte
|
||||
// because they have tags 1 and 2.
|
||||
tagcode := o.buf[o.index]
|
||||
o.index++
|
||||
switch tagcode {
|
||||
case p.mkeyprop.tagcode[0]:
|
||||
if err := p.mkeyprop.dec(o, p.mkeyprop, keybase); err != nil {
|
||||
return err
|
||||
}
|
||||
case p.mvalprop.tagcode[0]:
|
||||
if err := p.mvalprop.dec(o, p.mvalprop, valbase); err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
// TODO: Should we silently skip this instead?
|
||||
return fmt.Errorf("proto: bad map data tag %d", raw[0])
|
||||
}
|
||||
}
|
||||
keyelem, valelem := keyptr.Elem(), valptr.Elem()
|
||||
if !keyelem.IsValid() {
|
||||
keyelem = reflect.Zero(p.mtype.Key())
|
||||
}
|
||||
if !valelem.IsValid() {
|
||||
valelem = reflect.Zero(p.mtype.Elem())
|
||||
}
|
||||
|
||||
v.SetMapIndex(keyelem, valelem)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Decode a group.
|
||||
func (o *Buffer) dec_struct_group(p *Properties, base structPointer) error {
|
||||
bas := structPointer_GetStructPointer(base, p.field)
|
||||
if structPointer_IsNil(bas) {
|
||||
// allocate new nested message
|
||||
bas = toStructPointer(reflect.New(p.stype))
|
||||
structPointer_SetStructPointer(base, p.field, bas)
|
||||
}
|
||||
return o.unmarshalType(p.stype, p.sprop, true, bas)
|
||||
}
|
||||
|
||||
// Decode an embedded message.
|
||||
func (o *Buffer) dec_struct_message(p *Properties, base structPointer) (err error) {
|
||||
raw, e := o.DecodeRawBytes(false)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
|
||||
bas := structPointer_GetStructPointer(base, p.field)
|
||||
if structPointer_IsNil(bas) {
|
||||
// allocate new nested message
|
||||
bas = toStructPointer(reflect.New(p.stype))
|
||||
structPointer_SetStructPointer(base, p.field, bas)
|
||||
}
|
||||
|
||||
// If the object can unmarshal itself, let it.
|
||||
if p.isUnmarshaler {
|
||||
iv := structPointer_Interface(bas, p.stype)
|
||||
return iv.(Unmarshaler).Unmarshal(raw)
|
||||
}
|
||||
|
||||
obuf := o.buf
|
||||
oi := o.index
|
||||
o.buf = raw
|
||||
o.index = 0
|
||||
|
||||
err = o.unmarshalType(p.stype, p.sprop, false, bas)
|
||||
o.buf = obuf
|
||||
o.index = oi
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// Decode a slice of embedded messages.
|
||||
func (o *Buffer) dec_slice_struct_message(p *Properties, base structPointer) error {
|
||||
return o.dec_slice_struct(p, false, base)
|
||||
}
|
||||
|
||||
// Decode a slice of embedded groups.
|
||||
func (o *Buffer) dec_slice_struct_group(p *Properties, base structPointer) error {
|
||||
return o.dec_slice_struct(p, true, base)
|
||||
}
|
||||
|
||||
// Decode a slice of structs ([]*struct).
|
||||
func (o *Buffer) dec_slice_struct(p *Properties, is_group bool, base structPointer) error {
|
||||
v := reflect.New(p.stype)
|
||||
bas := toStructPointer(v)
|
||||
structPointer_StructPointerSlice(base, p.field).Append(bas)
|
||||
|
||||
if is_group {
|
||||
err := o.unmarshalType(p.stype, p.sprop, is_group, bas)
|
||||
return err
|
||||
}
|
||||
|
||||
raw, err := o.DecodeRawBytes(false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// If the object can unmarshal itself, let it.
|
||||
if p.isUnmarshaler {
|
||||
iv := v.Interface()
|
||||
return iv.(Unmarshaler).Unmarshal(raw)
|
||||
}
|
||||
|
||||
obuf := o.buf
|
||||
oi := o.index
|
||||
o.buf = raw
|
||||
o.index = 0
|
||||
|
||||
err = o.unmarshalType(p.stype, p.sprop, is_group, bas)
|
||||
|
||||
o.buf = obuf
|
||||
o.index = oi
|
||||
|
||||
// Slow workaround for messages that aren't Unmarshalers.
|
||||
// This includes some hand-coded .pb.go files and
|
||||
// bootstrap protos.
|
||||
// TODO: fix all of those and then add Unmarshal to
|
||||
// the Message interface. Then:
|
||||
// The cast above and code below can be deleted.
|
||||
// The old unmarshaler can be deleted.
|
||||
// Clients can call Unmarshal directly (can already do that, actually).
|
||||
var info InternalMessageInfo
|
||||
err := info.Unmarshal(pb, p.buf[p.index:])
|
||||
p.index = len(p.buf)
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -35,8 +35,14 @@ import (
|
|||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
type generatedDiscarder interface {
|
||||
XXX_DiscardUnknown()
|
||||
}
|
||||
|
||||
// DiscardUnknown recursively discards all unknown fields from this message
|
||||
// and all embedded messages.
|
||||
//
|
||||
|
@ -49,9 +55,202 @@ import (
|
|||
// For proto2 messages, the unknown fields of message extensions are only
|
||||
// discarded from messages that have been accessed via GetExtension.
|
||||
func DiscardUnknown(m Message) {
|
||||
if m, ok := m.(generatedDiscarder); ok {
|
||||
m.XXX_DiscardUnknown()
|
||||
return
|
||||
}
|
||||
// TODO: Dynamically populate a InternalMessageInfo for legacy messages,
|
||||
// but the master branch has no implementation for InternalMessageInfo,
|
||||
// so it would be more work to replicate that approach.
|
||||
discardLegacy(m)
|
||||
}
|
||||
|
||||
// DiscardUnknown recursively discards all unknown fields.
|
||||
func (a *InternalMessageInfo) DiscardUnknown(m Message) {
|
||||
di := atomicLoadDiscardInfo(&a.discard)
|
||||
if di == nil {
|
||||
di = getDiscardInfo(reflect.TypeOf(m).Elem())
|
||||
atomicStoreDiscardInfo(&a.discard, di)
|
||||
}
|
||||
di.discard(toPointer(&m))
|
||||
}
|
||||
|
||||
type discardInfo struct {
|
||||
typ reflect.Type
|
||||
|
||||
initialized int32 // 0: only typ is valid, 1: everything is valid
|
||||
lock sync.Mutex
|
||||
|
||||
fields []discardFieldInfo
|
||||
unrecognized field
|
||||
}
|
||||
|
||||
type discardFieldInfo struct {
|
||||
field field // Offset of field, guaranteed to be valid
|
||||
discard func(src pointer)
|
||||
}
|
||||
|
||||
var (
|
||||
discardInfoMap = map[reflect.Type]*discardInfo{}
|
||||
discardInfoLock sync.Mutex
|
||||
)
|
||||
|
||||
func getDiscardInfo(t reflect.Type) *discardInfo {
|
||||
discardInfoLock.Lock()
|
||||
defer discardInfoLock.Unlock()
|
||||
di := discardInfoMap[t]
|
||||
if di == nil {
|
||||
di = &discardInfo{typ: t}
|
||||
discardInfoMap[t] = di
|
||||
}
|
||||
return di
|
||||
}
|
||||
|
||||
func (di *discardInfo) discard(src pointer) {
|
||||
if src.isNil() {
|
||||
return // Nothing to do.
|
||||
}
|
||||
|
||||
if atomic.LoadInt32(&di.initialized) == 0 {
|
||||
di.computeDiscardInfo()
|
||||
}
|
||||
|
||||
for _, fi := range di.fields {
|
||||
sfp := src.offset(fi.field)
|
||||
fi.discard(sfp)
|
||||
}
|
||||
|
||||
// For proto2 messages, only discard unknown fields in message extensions
|
||||
// that have been accessed via GetExtension.
|
||||
if em, err := extendable(src.asPointerTo(di.typ).Interface()); err == nil {
|
||||
// Ignore lock since DiscardUnknown is not concurrency safe.
|
||||
emm, _ := em.extensionsRead()
|
||||
for _, mx := range emm {
|
||||
if m, ok := mx.value.(Message); ok {
|
||||
DiscardUnknown(m)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if di.unrecognized.IsValid() {
|
||||
*src.offset(di.unrecognized).toBytes() = nil
|
||||
}
|
||||
}
|
||||
|
||||
func (di *discardInfo) computeDiscardInfo() {
|
||||
di.lock.Lock()
|
||||
defer di.lock.Unlock()
|
||||
if di.initialized != 0 {
|
||||
return
|
||||
}
|
||||
t := di.typ
|
||||
n := t.NumField()
|
||||
|
||||
for i := 0; i < n; i++ {
|
||||
f := t.Field(i)
|
||||
if strings.HasPrefix(f.Name, "XXX_") {
|
||||
continue
|
||||
}
|
||||
|
||||
dfi := discardFieldInfo{field: toField(&f)}
|
||||
tf := f.Type
|
||||
|
||||
// Unwrap tf to get its most basic type.
|
||||
var isPointer, isSlice bool
|
||||
if tf.Kind() == reflect.Slice && tf.Elem().Kind() != reflect.Uint8 {
|
||||
isSlice = true
|
||||
tf = tf.Elem()
|
||||
}
|
||||
if tf.Kind() == reflect.Ptr {
|
||||
isPointer = true
|
||||
tf = tf.Elem()
|
||||
}
|
||||
if isPointer && isSlice && tf.Kind() != reflect.Struct {
|
||||
panic(fmt.Sprintf("%v.%s cannot be a slice of pointers to primitive types", t, f.Name))
|
||||
}
|
||||
|
||||
switch tf.Kind() {
|
||||
case reflect.Struct:
|
||||
switch {
|
||||
case !isPointer:
|
||||
panic(fmt.Sprintf("%v.%s cannot be a direct struct value", t, f.Name))
|
||||
case isSlice: // E.g., []*pb.T
|
||||
di := getDiscardInfo(tf)
|
||||
dfi.discard = func(src pointer) {
|
||||
sps := src.getPointerSlice()
|
||||
for _, sp := range sps {
|
||||
if !sp.isNil() {
|
||||
di.discard(sp)
|
||||
}
|
||||
}
|
||||
}
|
||||
default: // E.g., *pb.T
|
||||
di := getDiscardInfo(tf)
|
||||
dfi.discard = func(src pointer) {
|
||||
sp := src.getPointer()
|
||||
if !sp.isNil() {
|
||||
di.discard(sp)
|
||||
}
|
||||
}
|
||||
}
|
||||
case reflect.Map:
|
||||
switch {
|
||||
case isPointer || isSlice:
|
||||
panic(fmt.Sprintf("%v.%s cannot be a pointer to a map or a slice of map values", t, f.Name))
|
||||
default: // E.g., map[K]V
|
||||
if tf.Elem().Kind() == reflect.Ptr { // Proto struct (e.g., *T)
|
||||
dfi.discard = func(src pointer) {
|
||||
sm := src.asPointerTo(tf).Elem()
|
||||
if sm.Len() == 0 {
|
||||
return
|
||||
}
|
||||
for _, key := range sm.MapKeys() {
|
||||
val := sm.MapIndex(key)
|
||||
DiscardUnknown(val.Interface().(Message))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
dfi.discard = func(pointer) {} // Noop
|
||||
}
|
||||
}
|
||||
case reflect.Interface:
|
||||
// Must be oneof field.
|
||||
switch {
|
||||
case isPointer || isSlice:
|
||||
panic(fmt.Sprintf("%v.%s cannot be a pointer to a interface or a slice of interface values", t, f.Name))
|
||||
default: // E.g., interface{}
|
||||
// TODO: Make this faster?
|
||||
dfi.discard = func(src pointer) {
|
||||
su := src.asPointerTo(tf).Elem()
|
||||
if !su.IsNil() {
|
||||
sv := su.Elem().Elem().Field(0)
|
||||
if sv.Kind() == reflect.Ptr && sv.IsNil() {
|
||||
return
|
||||
}
|
||||
switch sv.Type().Kind() {
|
||||
case reflect.Ptr: // Proto struct (e.g., *T)
|
||||
DiscardUnknown(sv.Interface().(Message))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
default:
|
||||
continue
|
||||
}
|
||||
di.fields = append(di.fields, dfi)
|
||||
}
|
||||
|
||||
di.unrecognized = invalidField
|
||||
if f, ok := t.FieldByName("XXX_unrecognized"); ok {
|
||||
if f.Type != reflect.TypeOf([]byte{}) {
|
||||
panic("expected XXX_unrecognized to be of type []byte")
|
||||
}
|
||||
di.unrecognized = toField(&f)
|
||||
}
|
||||
|
||||
atomic.StoreInt32(&di.initialized, 1)
|
||||
}
|
||||
|
||||
func discardLegacy(m Message) {
|
||||
v := reflect.ValueOf(m)
|
||||
if v.Kind() != reflect.Ptr || v.IsNil() {
|
||||
|
@ -139,7 +338,7 @@ func discardLegacy(m Message) {
|
|||
|
||||
// For proto2 messages, only discard unknown fields in message extensions
|
||||
// that have been accessed via GetExtension.
|
||||
if em, ok := extendable(m); ok {
|
||||
if em, err := extendable(m); err == nil {
|
||||
// Ignore lock since discardLegacy is not concurrency safe.
|
||||
emm, _ := em.extensionsRead()
|
||||
for _, mx := range emm {
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -109,15 +109,6 @@ func equalStruct(v1, v2 reflect.Value) bool {
|
|||
// set/unset mismatch
|
||||
return false
|
||||
}
|
||||
b1, ok := f1.Interface().(raw)
|
||||
if ok {
|
||||
b2 := f2.Interface().(raw)
|
||||
// RawMessage
|
||||
if !bytes.Equal(b1.Bytes(), b2.Bytes()) {
|
||||
return false
|
||||
}
|
||||
continue
|
||||
}
|
||||
f1, f2 = f1.Elem(), f2.Elem()
|
||||
}
|
||||
if !equalAny(f1, f2, sprop.Prop[i]) {
|
||||
|
@ -146,11 +137,7 @@ func equalStruct(v1, v2 reflect.Value) bool {
|
|||
|
||||
u1 := uf.Bytes()
|
||||
u2 := v2.FieldByName("XXX_unrecognized").Bytes()
|
||||
if !bytes.Equal(u1, u2) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
return bytes.Equal(u1, u2)
|
||||
}
|
||||
|
||||
// v1 and v2 are known to have the same type.
|
||||
|
@ -261,6 +248,15 @@ func equalExtMap(base reflect.Type, em1, em2 map[int32]Extension) bool {
|
|||
|
||||
m1, m2 := e1.value, e2.value
|
||||
|
||||
if m1 == nil && m2 == nil {
|
||||
// Both have only encoded form.
|
||||
if bytes.Equal(e1.enc, e2.enc) {
|
||||
continue
|
||||
}
|
||||
// The bytes are different, but the extensions might still be
|
||||
// equal. We need to decode them to compare.
|
||||
}
|
||||
|
||||
if m1 != nil && m2 != nil {
|
||||
// Both are unencoded.
|
||||
if !equalAny(reflect.ValueOf(m1), reflect.ValueOf(m2), nil) {
|
||||
|
@ -276,8 +272,12 @@ func equalExtMap(base reflect.Type, em1, em2 map[int32]Extension) bool {
|
|||
desc = m[extNum]
|
||||
}
|
||||
if desc == nil {
|
||||
// If both have only encoded form and the bytes are the same,
|
||||
// it is handled above. We get here when the bytes are different.
|
||||
// We don't know how to decode it, so just compare them as byte
|
||||
// slices.
|
||||
log.Printf("proto: don't know how to compare extension %d of %v", extNum, base)
|
||||
continue
|
||||
return false
|
||||
}
|
||||
var err error
|
||||
if m1 == nil {
|
||||
|
|
|
@ -38,6 +38,7 @@ package proto
|
|||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"sync"
|
||||
|
@ -91,14 +92,29 @@ func (n notLocker) Unlock() {}
|
|||
// extendable returns the extendableProto interface for the given generated proto message.
|
||||
// If the proto message has the old extension format, it returns a wrapper that implements
|
||||
// the extendableProto interface.
|
||||
func extendable(p interface{}) (extendableProto, bool) {
|
||||
if ep, ok := p.(extendableProto); ok {
|
||||
return ep, ok
|
||||
func extendable(p interface{}) (extendableProto, error) {
|
||||
switch p := p.(type) {
|
||||
case extendableProto:
|
||||
if isNilPtr(p) {
|
||||
return nil, fmt.Errorf("proto: nil %T is not extendable", p)
|
||||
}
|
||||
return p, nil
|
||||
case extendableProtoV1:
|
||||
if isNilPtr(p) {
|
||||
return nil, fmt.Errorf("proto: nil %T is not extendable", p)
|
||||
}
|
||||
return extensionAdapter{p}, nil
|
||||
}
|
||||
if ep, ok := p.(extendableProtoV1); ok {
|
||||
return extensionAdapter{ep}, ok
|
||||
}
|
||||
return nil, false
|
||||
// Don't allocate a specific error containing %T:
|
||||
// this is the hot path for Clone and MarshalText.
|
||||
return nil, errNotExtendable
|
||||
}
|
||||
|
||||
var errNotExtendable = errors.New("proto: not an extendable proto.Message")
|
||||
|
||||
func isNilPtr(x interface{}) bool {
|
||||
v := reflect.ValueOf(x)
|
||||
return v.Kind() == reflect.Ptr && v.IsNil()
|
||||
}
|
||||
|
||||
// XXX_InternalExtensions is an internal representation of proto extensions.
|
||||
|
@ -143,9 +159,6 @@ func (e *XXX_InternalExtensions) extensionsRead() (map[int32]Extension, sync.Loc
|
|||
return e.p.extensionMap, &e.p.mu
|
||||
}
|
||||
|
||||
var extendableProtoType = reflect.TypeOf((*extendableProto)(nil)).Elem()
|
||||
var extendableProtoV1Type = reflect.TypeOf((*extendableProtoV1)(nil)).Elem()
|
||||
|
||||
// ExtensionDesc represents an extension specification.
|
||||
// Used in generated code from the protocol compiler.
|
||||
type ExtensionDesc struct {
|
||||
|
@ -179,8 +192,8 @@ type Extension struct {
|
|||
|
||||
// SetRawExtension is for testing only.
|
||||
func SetRawExtension(base Message, id int32, b []byte) {
|
||||
epb, ok := extendable(base)
|
||||
if !ok {
|
||||
epb, err := extendable(base)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
extmap := epb.extensionsWrite()
|
||||
|
@ -205,7 +218,7 @@ func checkExtensionTypes(pb extendableProto, extension *ExtensionDesc) error {
|
|||
pbi = ea.extendableProtoV1
|
||||
}
|
||||
if a, b := reflect.TypeOf(pbi), reflect.TypeOf(extension.ExtendedType); a != b {
|
||||
return errors.New("proto: bad extended type; " + b.String() + " does not extend " + a.String())
|
||||
return fmt.Errorf("proto: bad extended type; %v does not extend %v", b, a)
|
||||
}
|
||||
// Check the range.
|
||||
if !isExtensionField(pb, extension.Field) {
|
||||
|
@ -250,85 +263,11 @@ func extensionProperties(ed *ExtensionDesc) *Properties {
|
|||
return prop
|
||||
}
|
||||
|
||||
// encode encodes any unmarshaled (unencoded) extensions in e.
|
||||
func encodeExtensions(e *XXX_InternalExtensions) error {
|
||||
m, mu := e.extensionsRead()
|
||||
if m == nil {
|
||||
return nil // fast path
|
||||
}
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
return encodeExtensionsMap(m)
|
||||
}
|
||||
|
||||
// encode encodes any unmarshaled (unencoded) extensions in e.
|
||||
func encodeExtensionsMap(m map[int32]Extension) error {
|
||||
for k, e := range m {
|
||||
if e.value == nil || e.desc == nil {
|
||||
// Extension is only in its encoded form.
|
||||
continue
|
||||
}
|
||||
|
||||
// We don't skip extensions that have an encoded form set,
|
||||
// because the extension value may have been mutated after
|
||||
// the last time this function was called.
|
||||
|
||||
et := reflect.TypeOf(e.desc.ExtensionType)
|
||||
props := extensionProperties(e.desc)
|
||||
|
||||
p := NewBuffer(nil)
|
||||
// If e.value has type T, the encoder expects a *struct{ X T }.
|
||||
// Pass a *T with a zero field and hope it all works out.
|
||||
x := reflect.New(et)
|
||||
x.Elem().Set(reflect.ValueOf(e.value))
|
||||
if err := props.enc(p, props, toStructPointer(x)); err != nil {
|
||||
return err
|
||||
}
|
||||
e.enc = p.buf
|
||||
m[k] = e
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func extensionsSize(e *XXX_InternalExtensions) (n int) {
|
||||
m, mu := e.extensionsRead()
|
||||
if m == nil {
|
||||
return 0
|
||||
}
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
return extensionsMapSize(m)
|
||||
}
|
||||
|
||||
func extensionsMapSize(m map[int32]Extension) (n int) {
|
||||
for _, e := range m {
|
||||
if e.value == nil || e.desc == nil {
|
||||
// Extension is only in its encoded form.
|
||||
n += len(e.enc)
|
||||
continue
|
||||
}
|
||||
|
||||
// We don't skip extensions that have an encoded form set,
|
||||
// because the extension value may have been mutated after
|
||||
// the last time this function was called.
|
||||
|
||||
et := reflect.TypeOf(e.desc.ExtensionType)
|
||||
props := extensionProperties(e.desc)
|
||||
|
||||
// If e.value has type T, the encoder expects a *struct{ X T }.
|
||||
// Pass a *T with a zero field and hope it all works out.
|
||||
x := reflect.New(et)
|
||||
x.Elem().Set(reflect.ValueOf(e.value))
|
||||
n += props.size(props, toStructPointer(x))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// HasExtension returns whether the given extension is present in pb.
|
||||
func HasExtension(pb Message, extension *ExtensionDesc) bool {
|
||||
// TODO: Check types, field numbers, etc.?
|
||||
epb, ok := extendable(pb)
|
||||
if !ok {
|
||||
epb, err := extendable(pb)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
extmap, mu := epb.extensionsRead()
|
||||
|
@ -336,15 +275,15 @@ func HasExtension(pb Message, extension *ExtensionDesc) bool {
|
|||
return false
|
||||
}
|
||||
mu.Lock()
|
||||
_, ok = extmap[extension.Field]
|
||||
_, ok := extmap[extension.Field]
|
||||
mu.Unlock()
|
||||
return ok
|
||||
}
|
||||
|
||||
// ClearExtension removes the given extension from pb.
|
||||
func ClearExtension(pb Message, extension *ExtensionDesc) {
|
||||
epb, ok := extendable(pb)
|
||||
if !ok {
|
||||
epb, err := extendable(pb)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// TODO: Check types, field numbers, etc.?
|
||||
|
@ -352,16 +291,26 @@ func ClearExtension(pb Message, extension *ExtensionDesc) {
|
|||
delete(extmap, extension.Field)
|
||||
}
|
||||
|
||||
// GetExtension parses and returns the given extension of pb.
|
||||
// If the extension is not present and has no default value it returns ErrMissingExtension.
|
||||
// GetExtension retrieves a proto2 extended field from pb.
|
||||
//
|
||||
// If the descriptor is type complete (i.e., ExtensionDesc.ExtensionType is non-nil),
|
||||
// then GetExtension parses the encoded field and returns a Go value of the specified type.
|
||||
// If the field is not present, then the default value is returned (if one is specified),
|
||||
// otherwise ErrMissingExtension is reported.
|
||||
//
|
||||
// If the descriptor is not type complete (i.e., ExtensionDesc.ExtensionType is nil),
|
||||
// then GetExtension returns the raw encoded bytes of the field extension.
|
||||
func GetExtension(pb Message, extension *ExtensionDesc) (interface{}, error) {
|
||||
epb, ok := extendable(pb)
|
||||
if !ok {
|
||||
return nil, errors.New("proto: not an extendable proto")
|
||||
epb, err := extendable(pb)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := checkExtensionTypes(epb, extension); err != nil {
|
||||
return nil, err
|
||||
if extension.ExtendedType != nil {
|
||||
// can only check type if this is a complete descriptor
|
||||
if err := checkExtensionTypes(epb, extension); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
emap, mu := epb.extensionsRead()
|
||||
|
@ -388,6 +337,11 @@ func GetExtension(pb Message, extension *ExtensionDesc) (interface{}, error) {
|
|||
return e.value, nil
|
||||
}
|
||||
|
||||
if extension.ExtensionType == nil {
|
||||
// incomplete descriptor
|
||||
return e.enc, nil
|
||||
}
|
||||
|
||||
v, err := decodeExtension(e.enc, extension)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -405,6 +359,11 @@ func GetExtension(pb Message, extension *ExtensionDesc) (interface{}, error) {
|
|||
// defaultExtensionValue returns the default value for extension.
|
||||
// If no default for an extension is defined ErrMissingExtension is returned.
|
||||
func defaultExtensionValue(extension *ExtensionDesc) (interface{}, error) {
|
||||
if extension.ExtensionType == nil {
|
||||
// incomplete descriptor, so no default
|
||||
return nil, ErrMissingExtension
|
||||
}
|
||||
|
||||
t := reflect.TypeOf(extension.ExtensionType)
|
||||
props := extensionProperties(extension)
|
||||
|
||||
|
@ -439,31 +398,28 @@ func defaultExtensionValue(extension *ExtensionDesc) (interface{}, error) {
|
|||
|
||||
// decodeExtension decodes an extension encoded in b.
|
||||
func decodeExtension(b []byte, extension *ExtensionDesc) (interface{}, error) {
|
||||
o := NewBuffer(b)
|
||||
|
||||
t := reflect.TypeOf(extension.ExtensionType)
|
||||
|
||||
props := extensionProperties(extension)
|
||||
unmarshal := typeUnmarshaler(t, extension.Tag)
|
||||
|
||||
// t is a pointer to a struct, pointer to basic type or a slice.
|
||||
// Allocate a "field" to store the pointer/slice itself; the
|
||||
// pointer/slice will be stored here. We pass
|
||||
// the address of this field to props.dec.
|
||||
// This passes a zero field and a *t and lets props.dec
|
||||
// interpret it as a *struct{ x t }.
|
||||
// Allocate space to store the pointer/slice.
|
||||
value := reflect.New(t).Elem()
|
||||
|
||||
var err error
|
||||
for {
|
||||
// Discard wire type and field number varint. It isn't needed.
|
||||
if _, err := o.DecodeVarint(); err != nil {
|
||||
x, n := decodeVarint(b)
|
||||
if n == 0 {
|
||||
return nil, io.ErrUnexpectedEOF
|
||||
}
|
||||
b = b[n:]
|
||||
wire := int(x) & 7
|
||||
|
||||
b, err = unmarshal(b, valToPointer(value.Addr()), wire)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := props.dec(o, props, toStructPointer(value.Addr())); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if o.index >= len(o.buf) {
|
||||
if len(b) == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
@ -473,9 +429,9 @@ func decodeExtension(b []byte, extension *ExtensionDesc) (interface{}, error) {
|
|||
// GetExtensions returns a slice of the extensions present in pb that are also listed in es.
|
||||
// The returned slice has the same length as es; missing extensions will appear as nil elements.
|
||||
func GetExtensions(pb Message, es []*ExtensionDesc) (extensions []interface{}, err error) {
|
||||
epb, ok := extendable(pb)
|
||||
if !ok {
|
||||
return nil, errors.New("proto: not an extendable proto")
|
||||
epb, err := extendable(pb)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
extensions = make([]interface{}, len(es))
|
||||
for i, e := range es {
|
||||
|
@ -494,9 +450,9 @@ func GetExtensions(pb Message, es []*ExtensionDesc) (extensions []interface{}, e
|
|||
// For non-registered extensions, ExtensionDescs returns an incomplete descriptor containing
|
||||
// just the Field field, which defines the extension's field number.
|
||||
func ExtensionDescs(pb Message) ([]*ExtensionDesc, error) {
|
||||
epb, ok := extendable(pb)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("proto: %T is not an extendable proto.Message", pb)
|
||||
epb, err := extendable(pb)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
registeredExtensions := RegisteredExtensions(pb)
|
||||
|
||||
|
@ -523,9 +479,9 @@ func ExtensionDescs(pb Message) ([]*ExtensionDesc, error) {
|
|||
|
||||
// SetExtension sets the specified extension of pb to the specified value.
|
||||
func SetExtension(pb Message, extension *ExtensionDesc, value interface{}) error {
|
||||
epb, ok := extendable(pb)
|
||||
if !ok {
|
||||
return errors.New("proto: not an extendable proto")
|
||||
epb, err := extendable(pb)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := checkExtensionTypes(epb, extension); err != nil {
|
||||
return err
|
||||
|
@ -550,8 +506,8 @@ func SetExtension(pb Message, extension *ExtensionDesc, value interface{}) error
|
|||
|
||||
// ClearAllExtensions clears all extensions from pb.
|
||||
func ClearAllExtensions(pb Message) {
|
||||
epb, ok := extendable(pb)
|
||||
if !ok {
|
||||
epb, err := extendable(pb)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
m := epb.extensionsWrite()
|
||||
|
|
|
@ -273,6 +273,67 @@ import (
|
|||
"sync"
|
||||
)
|
||||
|
||||
// RequiredNotSetError is an error type returned by either Marshal or Unmarshal.
|
||||
// Marshal reports this when a required field is not initialized.
|
||||
// Unmarshal reports this when a required field is missing from the wire data.
|
||||
type RequiredNotSetError struct{ field string }
|
||||
|
||||
func (e *RequiredNotSetError) Error() string {
|
||||
if e.field == "" {
|
||||
return fmt.Sprintf("proto: required field not set")
|
||||
}
|
||||
return fmt.Sprintf("proto: required field %q not set", e.field)
|
||||
}
|
||||
func (e *RequiredNotSetError) RequiredNotSet() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
type invalidUTF8Error struct{ field string }
|
||||
|
||||
func (e *invalidUTF8Error) Error() string {
|
||||
if e.field == "" {
|
||||
return "proto: invalid UTF-8 detected"
|
||||
}
|
||||
return fmt.Sprintf("proto: field %q contains invalid UTF-8", e.field)
|
||||
}
|
||||
func (e *invalidUTF8Error) InvalidUTF8() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// errInvalidUTF8 is a sentinel error to identify fields with invalid UTF-8.
|
||||
// This error should not be exposed to the external API as such errors should
|
||||
// be recreated with the field information.
|
||||
var errInvalidUTF8 = &invalidUTF8Error{}
|
||||
|
||||
// isNonFatal reports whether the error is either a RequiredNotSet error
|
||||
// or a InvalidUTF8 error.
|
||||
func isNonFatal(err error) bool {
|
||||
if re, ok := err.(interface{ RequiredNotSet() bool }); ok && re.RequiredNotSet() {
|
||||
return true
|
||||
}
|
||||
if re, ok := err.(interface{ InvalidUTF8() bool }); ok && re.InvalidUTF8() {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type nonFatal struct{ E error }
|
||||
|
||||
// Merge merges err into nf and reports whether it was successful.
|
||||
// Otherwise it returns false for any fatal non-nil errors.
|
||||
func (nf *nonFatal) Merge(err error) (ok bool) {
|
||||
if err == nil {
|
||||
return true // not an error
|
||||
}
|
||||
if !isNonFatal(err) {
|
||||
return false // fatal error
|
||||
}
|
||||
if nf.E == nil {
|
||||
nf.E = err // store first instance of non-fatal error
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Message is implemented by generated protocol buffer messages.
|
||||
type Message interface {
|
||||
Reset()
|
||||
|
@ -309,16 +370,7 @@ type Buffer struct {
|
|||
buf []byte // encode/decode byte stream
|
||||
index int // read point
|
||||
|
||||
// pools of basic types to amortize allocation.
|
||||
bools []bool
|
||||
uint32s []uint32
|
||||
uint64s []uint64
|
||||
|
||||
// extra pools, only used with pointer_reflect.go
|
||||
int32s []int32
|
||||
int64s []int64
|
||||
float32s []float32
|
||||
float64s []float64
|
||||
deterministic bool
|
||||
}
|
||||
|
||||
// NewBuffer allocates a new Buffer and initializes its internal data to
|
||||
|
@ -343,6 +395,30 @@ func (p *Buffer) SetBuf(s []byte) {
|
|||
// Bytes returns the contents of the Buffer.
|
||||
func (p *Buffer) Bytes() []byte { return p.buf }
|
||||
|
||||
// SetDeterministic sets whether to use deterministic serialization.
|
||||
//
|
||||
// Deterministic serialization guarantees that for a given binary, equal
|
||||
// messages will always be serialized to the same bytes. This implies:
|
||||
//
|
||||
// - Repeated serialization of a message will return the same bytes.
|
||||
// - Different processes of the same binary (which may be executing on
|
||||
// different machines) will serialize equal messages to the same bytes.
|
||||
//
|
||||
// Note that the deterministic serialization is NOT canonical across
|
||||
// languages. It is not guaranteed to remain stable over time. It is unstable
|
||||
// across different builds with schema changes due to unknown fields.
|
||||
// Users who need canonical serialization (e.g., persistent storage in a
|
||||
// canonical form, fingerprinting, etc.) should define their own
|
||||
// canonicalization specification and implement their own serializer rather
|
||||
// than relying on this API.
|
||||
//
|
||||
// If deterministic serialization is requested, map entries will be sorted
|
||||
// by keys in lexographical order. This is an implementation detail and
|
||||
// subject to change.
|
||||
func (p *Buffer) SetDeterministic(deterministic bool) {
|
||||
p.deterministic = deterministic
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper routines for simplifying the creation of optional fields of basic type.
|
||||
*/
|
||||
|
@ -831,22 +907,12 @@ func fieldDefault(ft reflect.Type, prop *Properties) (sf *scalarField, nestedMes
|
|||
return sf, false, nil
|
||||
}
|
||||
|
||||
// mapKeys returns a sort.Interface to be used for sorting the map keys.
|
||||
// Map fields may have key types of non-float scalars, strings and enums.
|
||||
// The easiest way to sort them in some deterministic order is to use fmt.
|
||||
// If this turns out to be inefficient we can always consider other options,
|
||||
// such as doing a Schwartzian transform.
|
||||
|
||||
func mapKeys(vs []reflect.Value) sort.Interface {
|
||||
s := mapKeySorter{
|
||||
vs: vs,
|
||||
// default Less function: textual comparison
|
||||
less: func(a, b reflect.Value) bool {
|
||||
return fmt.Sprint(a.Interface()) < fmt.Sprint(b.Interface())
|
||||
},
|
||||
}
|
||||
s := mapKeySorter{vs: vs}
|
||||
|
||||
// Type specialization per https://developers.google.com/protocol-buffers/docs/proto#maps;
|
||||
// numeric keys are sorted numerically.
|
||||
// Type specialization per https://developers.google.com/protocol-buffers/docs/proto#maps.
|
||||
if len(vs) == 0 {
|
||||
return s
|
||||
}
|
||||
|
@ -855,6 +921,12 @@ func mapKeys(vs []reflect.Value) sort.Interface {
|
|||
s.less = func(a, b reflect.Value) bool { return a.Int() < b.Int() }
|
||||
case reflect.Uint32, reflect.Uint64:
|
||||
s.less = func(a, b reflect.Value) bool { return a.Uint() < b.Uint() }
|
||||
case reflect.Bool:
|
||||
s.less = func(a, b reflect.Value) bool { return !a.Bool() && b.Bool() } // false < true
|
||||
case reflect.String:
|
||||
s.less = func(a, b reflect.Value) bool { return a.String() < b.String() }
|
||||
default:
|
||||
panic(fmt.Sprintf("unsupported map key type: %v", vs[0].Kind()))
|
||||
}
|
||||
|
||||
return s
|
||||
|
@ -895,3 +967,13 @@ const ProtoPackageIsVersion2 = true
|
|||
// ProtoPackageIsVersion1 is referenced from generated protocol buffer files
|
||||
// to assert that that code is compatible with this version of the proto package.
|
||||
const ProtoPackageIsVersion1 = true
|
||||
|
||||
// InternalMessageInfo is a type used internally by generated .pb.go files.
|
||||
// This type is not intended to be used by non-generated code.
|
||||
// This type is not subject to any compatibility guarantee.
|
||||
type InternalMessageInfo struct {
|
||||
marshal *marshalInfo
|
||||
unmarshal *unmarshalInfo
|
||||
merge *mergeInfo
|
||||
discard *discardInfo
|
||||
}
|
||||
|
|
|
@ -42,6 +42,7 @@ import (
|
|||
"fmt"
|
||||
"reflect"
|
||||
"sort"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// errNoMessageTypeID occurs when a protocol buffer does not have a message type ID.
|
||||
|
@ -94,10 +95,7 @@ func (ms *messageSet) find(pb Message) *_MessageSet_Item {
|
|||
}
|
||||
|
||||
func (ms *messageSet) Has(pb Message) bool {
|
||||
if ms.find(pb) != nil {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
return ms.find(pb) != nil
|
||||
}
|
||||
|
||||
func (ms *messageSet) Unmarshal(pb Message) error {
|
||||
|
@ -150,46 +148,42 @@ func skipVarint(buf []byte) []byte {
|
|||
// MarshalMessageSet encodes the extension map represented by m in the message set wire format.
|
||||
// It is called by generated Marshal methods on protocol buffer messages with the message_set_wire_format option.
|
||||
func MarshalMessageSet(exts interface{}) ([]byte, error) {
|
||||
var m map[int32]Extension
|
||||
return marshalMessageSet(exts, false)
|
||||
}
|
||||
|
||||
// marshaMessageSet implements above function, with the opt to turn on / off deterministic during Marshal.
|
||||
func marshalMessageSet(exts interface{}, deterministic bool) ([]byte, error) {
|
||||
switch exts := exts.(type) {
|
||||
case *XXX_InternalExtensions:
|
||||
if err := encodeExtensions(exts); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
m, _ = exts.extensionsRead()
|
||||
var u marshalInfo
|
||||
siz := u.sizeMessageSet(exts)
|
||||
b := make([]byte, 0, siz)
|
||||
return u.appendMessageSet(b, exts, deterministic)
|
||||
|
||||
case map[int32]Extension:
|
||||
if err := encodeExtensionsMap(exts); err != nil {
|
||||
return nil, err
|
||||
// This is an old-style extension map.
|
||||
// Wrap it in a new-style XXX_InternalExtensions.
|
||||
ie := XXX_InternalExtensions{
|
||||
p: &struct {
|
||||
mu sync.Mutex
|
||||
extensionMap map[int32]Extension
|
||||
}{
|
||||
extensionMap: exts,
|
||||
},
|
||||
}
|
||||
m = exts
|
||||
|
||||
var u marshalInfo
|
||||
siz := u.sizeMessageSet(&ie)
|
||||
b := make([]byte, 0, siz)
|
||||
return u.appendMessageSet(b, &ie, deterministic)
|
||||
|
||||
default:
|
||||
return nil, errors.New("proto: not an extension map")
|
||||
}
|
||||
|
||||
// Sort extension IDs to provide a deterministic encoding.
|
||||
// See also enc_map in encode.go.
|
||||
ids := make([]int, 0, len(m))
|
||||
for id := range m {
|
||||
ids = append(ids, int(id))
|
||||
}
|
||||
sort.Ints(ids)
|
||||
|
||||
ms := &messageSet{Item: make([]*_MessageSet_Item, 0, len(m))}
|
||||
for _, id := range ids {
|
||||
e := m[int32(id)]
|
||||
// Remove the wire type and field number varint, as well as the length varint.
|
||||
msg := skipVarint(skipVarint(e.enc))
|
||||
|
||||
ms.Item = append(ms.Item, &_MessageSet_Item{
|
||||
TypeId: Int32(int32(id)),
|
||||
Message: msg,
|
||||
})
|
||||
}
|
||||
return Marshal(ms)
|
||||
}
|
||||
|
||||
// UnmarshalMessageSet decodes the extension map encoded in buf in the message set wire format.
|
||||
// It is called by generated Unmarshal methods on protocol buffer messages with the message_set_wire_format option.
|
||||
// It is called by Unmarshal methods on protocol buffer messages with the message_set_wire_format option.
|
||||
func UnmarshalMessageSet(buf []byte, exts interface{}) error {
|
||||
var m map[int32]Extension
|
||||
switch exts := exts.(type) {
|
||||
|
@ -235,7 +229,15 @@ func MarshalMessageSetJSON(exts interface{}) ([]byte, error) {
|
|||
var m map[int32]Extension
|
||||
switch exts := exts.(type) {
|
||||
case *XXX_InternalExtensions:
|
||||
m, _ = exts.extensionsRead()
|
||||
var mu sync.Locker
|
||||
m, mu = exts.extensionsRead()
|
||||
if m != nil {
|
||||
// Keep the extensions map locked until we're done marshaling to prevent
|
||||
// races between marshaling and unmarshaling the lazily-{en,de}coded
|
||||
// values.
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
}
|
||||
case map[int32]Extension:
|
||||
m = exts
|
||||
default:
|
||||
|
@ -253,15 +255,16 @@ func MarshalMessageSetJSON(exts interface{}) ([]byte, error) {
|
|||
|
||||
for i, id := range ids {
|
||||
ext := m[id]
|
||||
if i > 0 {
|
||||
b.WriteByte(',')
|
||||
}
|
||||
|
||||
msd, ok := messageSetMap[id]
|
||||
if !ok {
|
||||
// Unknown type; we can't render it, so skip it.
|
||||
continue
|
||||
}
|
||||
|
||||
if i > 0 && b.Len() > 1 {
|
||||
b.WriteByte(',')
|
||||
}
|
||||
|
||||
fmt.Fprintf(&b, `"[%s]":`, msd.name)
|
||||
|
||||
x := ext.value
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// +build appengine js
|
||||
// +build purego appengine js
|
||||
|
||||
// This file contains an implementation of proto field accesses using package reflect.
|
||||
// It is slower than the code in pointer_unsafe.go but it avoids package unsafe and can
|
||||
|
@ -38,32 +38,13 @@
|
|||
package proto
|
||||
|
||||
import (
|
||||
"math"
|
||||
"reflect"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// A structPointer is a pointer to a struct.
|
||||
type structPointer struct {
|
||||
v reflect.Value
|
||||
}
|
||||
const unsafeAllowed = false
|
||||
|
||||
// toStructPointer returns a structPointer equivalent to the given reflect value.
|
||||
// The reflect value must itself be a pointer to a struct.
|
||||
func toStructPointer(v reflect.Value) structPointer {
|
||||
return structPointer{v}
|
||||
}
|
||||
|
||||
// IsNil reports whether p is nil.
|
||||
func structPointer_IsNil(p structPointer) bool {
|
||||
return p.v.IsNil()
|
||||
}
|
||||
|
||||
// Interface returns the struct pointer as an interface value.
|
||||
func structPointer_Interface(p structPointer, _ reflect.Type) interface{} {
|
||||
return p.v.Interface()
|
||||
}
|
||||
|
||||
// A field identifies a field in a struct, accessible from a structPointer.
|
||||
// A field identifies a field in a struct, accessible from a pointer.
|
||||
// In this implementation, a field is identified by the sequence of field indices
|
||||
// passed to reflect's FieldByIndex.
|
||||
type field []int
|
||||
|
@ -76,409 +57,301 @@ func toField(f *reflect.StructField) field {
|
|||
// invalidField is an invalid field identifier.
|
||||
var invalidField = field(nil)
|
||||
|
||||
// zeroField is a noop when calling pointer.offset.
|
||||
var zeroField = field([]int{})
|
||||
|
||||
// IsValid reports whether the field identifier is valid.
|
||||
func (f field) IsValid() bool { return f != nil }
|
||||
|
||||
// field returns the given field in the struct as a reflect value.
|
||||
func structPointer_field(p structPointer, f field) reflect.Value {
|
||||
// Special case: an extension map entry with a value of type T
|
||||
// passes a *T to the struct-handling code with a zero field,
|
||||
// expecting that it will be treated as equivalent to *struct{ X T },
|
||||
// which has the same memory layout. We have to handle that case
|
||||
// specially, because reflect will panic if we call FieldByIndex on a
|
||||
// non-struct.
|
||||
if f == nil {
|
||||
return p.v.Elem()
|
||||
}
|
||||
|
||||
return p.v.Elem().FieldByIndex(f)
|
||||
}
|
||||
|
||||
// ifield returns the given field in the struct as an interface value.
|
||||
func structPointer_ifield(p structPointer, f field) interface{} {
|
||||
return structPointer_field(p, f).Addr().Interface()
|
||||
}
|
||||
|
||||
// Bytes returns the address of a []byte field in the struct.
|
||||
func structPointer_Bytes(p structPointer, f field) *[]byte {
|
||||
return structPointer_ifield(p, f).(*[]byte)
|
||||
}
|
||||
|
||||
// BytesSlice returns the address of a [][]byte field in the struct.
|
||||
func structPointer_BytesSlice(p structPointer, f field) *[][]byte {
|
||||
return structPointer_ifield(p, f).(*[][]byte)
|
||||
}
|
||||
|
||||
// Bool returns the address of a *bool field in the struct.
|
||||
func structPointer_Bool(p structPointer, f field) **bool {
|
||||
return structPointer_ifield(p, f).(**bool)
|
||||
}
|
||||
|
||||
// BoolVal returns the address of a bool field in the struct.
|
||||
func structPointer_BoolVal(p structPointer, f field) *bool {
|
||||
return structPointer_ifield(p, f).(*bool)
|
||||
}
|
||||
|
||||
// BoolSlice returns the address of a []bool field in the struct.
|
||||
func structPointer_BoolSlice(p structPointer, f field) *[]bool {
|
||||
return structPointer_ifield(p, f).(*[]bool)
|
||||
}
|
||||
|
||||
// String returns the address of a *string field in the struct.
|
||||
func structPointer_String(p structPointer, f field) **string {
|
||||
return structPointer_ifield(p, f).(**string)
|
||||
}
|
||||
|
||||
// StringVal returns the address of a string field in the struct.
|
||||
func structPointer_StringVal(p structPointer, f field) *string {
|
||||
return structPointer_ifield(p, f).(*string)
|
||||
}
|
||||
|
||||
// StringSlice returns the address of a []string field in the struct.
|
||||
func structPointer_StringSlice(p structPointer, f field) *[]string {
|
||||
return structPointer_ifield(p, f).(*[]string)
|
||||
}
|
||||
|
||||
// Extensions returns the address of an extension map field in the struct.
|
||||
func structPointer_Extensions(p structPointer, f field) *XXX_InternalExtensions {
|
||||
return structPointer_ifield(p, f).(*XXX_InternalExtensions)
|
||||
}
|
||||
|
||||
// ExtMap returns the address of an extension map field in the struct.
|
||||
func structPointer_ExtMap(p structPointer, f field) *map[int32]Extension {
|
||||
return structPointer_ifield(p, f).(*map[int32]Extension)
|
||||
}
|
||||
|
||||
// NewAt returns the reflect.Value for a pointer to a field in the struct.
|
||||
func structPointer_NewAt(p structPointer, f field, typ reflect.Type) reflect.Value {
|
||||
return structPointer_field(p, f).Addr()
|
||||
}
|
||||
|
||||
// SetStructPointer writes a *struct field in the struct.
|
||||
func structPointer_SetStructPointer(p structPointer, f field, q structPointer) {
|
||||
structPointer_field(p, f).Set(q.v)
|
||||
}
|
||||
|
||||
// GetStructPointer reads a *struct field in the struct.
|
||||
func structPointer_GetStructPointer(p structPointer, f field) structPointer {
|
||||
return structPointer{structPointer_field(p, f)}
|
||||
}
|
||||
|
||||
// StructPointerSlice the address of a []*struct field in the struct.
|
||||
func structPointer_StructPointerSlice(p structPointer, f field) structPointerSlice {
|
||||
return structPointerSlice{structPointer_field(p, f)}
|
||||
}
|
||||
|
||||
// A structPointerSlice represents the address of a slice of pointers to structs
|
||||
// (themselves messages or groups). That is, v.Type() is *[]*struct{...}.
|
||||
type structPointerSlice struct {
|
||||
// The pointer type is for the table-driven decoder.
|
||||
// The implementation here uses a reflect.Value of pointer type to
|
||||
// create a generic pointer. In pointer_unsafe.go we use unsafe
|
||||
// instead of reflect to implement the same (but faster) interface.
|
||||
type pointer struct {
|
||||
v reflect.Value
|
||||
}
|
||||
|
||||
func (p structPointerSlice) Len() int { return p.v.Len() }
|
||||
func (p structPointerSlice) Index(i int) structPointer { return structPointer{p.v.Index(i)} }
|
||||
func (p structPointerSlice) Append(q structPointer) {
|
||||
p.v.Set(reflect.Append(p.v, q.v))
|
||||
// toPointer converts an interface of pointer type to a pointer
|
||||
// that points to the same target.
|
||||
func toPointer(i *Message) pointer {
|
||||
return pointer{v: reflect.ValueOf(*i)}
|
||||
}
|
||||
|
||||
var (
|
||||
int32Type = reflect.TypeOf(int32(0))
|
||||
uint32Type = reflect.TypeOf(uint32(0))
|
||||
float32Type = reflect.TypeOf(float32(0))
|
||||
int64Type = reflect.TypeOf(int64(0))
|
||||
uint64Type = reflect.TypeOf(uint64(0))
|
||||
float64Type = reflect.TypeOf(float64(0))
|
||||
)
|
||||
|
||||
// A word32 represents a field of type *int32, *uint32, *float32, or *enum.
|
||||
// That is, v.Type() is *int32, *uint32, *float32, or *enum and v is assignable.
|
||||
type word32 struct {
|
||||
v reflect.Value
|
||||
// toAddrPointer converts an interface to a pointer that points to
|
||||
// the interface data.
|
||||
func toAddrPointer(i *interface{}, isptr bool) pointer {
|
||||
v := reflect.ValueOf(*i)
|
||||
u := reflect.New(v.Type())
|
||||
u.Elem().Set(v)
|
||||
return pointer{v: u}
|
||||
}
|
||||
|
||||
// IsNil reports whether p is nil.
|
||||
func word32_IsNil(p word32) bool {
|
||||
// valToPointer converts v to a pointer. v must be of pointer type.
|
||||
func valToPointer(v reflect.Value) pointer {
|
||||
return pointer{v: v}
|
||||
}
|
||||
|
||||
// offset converts from a pointer to a structure to a pointer to
|
||||
// one of its fields.
|
||||
func (p pointer) offset(f field) pointer {
|
||||
return pointer{v: p.v.Elem().FieldByIndex(f).Addr()}
|
||||
}
|
||||
|
||||
func (p pointer) isNil() bool {
|
||||
return p.v.IsNil()
|
||||
}
|
||||
|
||||
// Set sets p to point at a newly allocated word with bits set to x.
|
||||
func word32_Set(p word32, o *Buffer, x uint32) {
|
||||
t := p.v.Type().Elem()
|
||||
switch t {
|
||||
case int32Type:
|
||||
if len(o.int32s) == 0 {
|
||||
o.int32s = make([]int32, uint32PoolSize)
|
||||
}
|
||||
o.int32s[0] = int32(x)
|
||||
p.v.Set(reflect.ValueOf(&o.int32s[0]))
|
||||
o.int32s = o.int32s[1:]
|
||||
return
|
||||
case uint32Type:
|
||||
if len(o.uint32s) == 0 {
|
||||
o.uint32s = make([]uint32, uint32PoolSize)
|
||||
}
|
||||
o.uint32s[0] = x
|
||||
p.v.Set(reflect.ValueOf(&o.uint32s[0]))
|
||||
o.uint32s = o.uint32s[1:]
|
||||
return
|
||||
case float32Type:
|
||||
if len(o.float32s) == 0 {
|
||||
o.float32s = make([]float32, uint32PoolSize)
|
||||
}
|
||||
o.float32s[0] = math.Float32frombits(x)
|
||||
p.v.Set(reflect.ValueOf(&o.float32s[0]))
|
||||
o.float32s = o.float32s[1:]
|
||||
return
|
||||
}
|
||||
|
||||
// must be enum
|
||||
p.v.Set(reflect.New(t))
|
||||
p.v.Elem().SetInt(int64(int32(x)))
|
||||
}
|
||||
|
||||
// Get gets the bits pointed at by p, as a uint32.
|
||||
func word32_Get(p word32) uint32 {
|
||||
elem := p.v.Elem()
|
||||
switch elem.Kind() {
|
||||
case reflect.Int32:
|
||||
return uint32(elem.Int())
|
||||
case reflect.Uint32:
|
||||
return uint32(elem.Uint())
|
||||
case reflect.Float32:
|
||||
return math.Float32bits(float32(elem.Float()))
|
||||
}
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
// Word32 returns a reference to a *int32, *uint32, *float32, or *enum field in the struct.
|
||||
func structPointer_Word32(p structPointer, f field) word32 {
|
||||
return word32{structPointer_field(p, f)}
|
||||
}
|
||||
|
||||
// A word32Val represents a field of type int32, uint32, float32, or enum.
|
||||
// That is, v.Type() is int32, uint32, float32, or enum and v is assignable.
|
||||
type word32Val struct {
|
||||
v reflect.Value
|
||||
}
|
||||
|
||||
// Set sets *p to x.
|
||||
func word32Val_Set(p word32Val, x uint32) {
|
||||
switch p.v.Type() {
|
||||
case int32Type:
|
||||
p.v.SetInt(int64(x))
|
||||
return
|
||||
case uint32Type:
|
||||
p.v.SetUint(uint64(x))
|
||||
return
|
||||
case float32Type:
|
||||
p.v.SetFloat(float64(math.Float32frombits(x)))
|
||||
return
|
||||
}
|
||||
|
||||
// must be enum
|
||||
p.v.SetInt(int64(int32(x)))
|
||||
}
|
||||
|
||||
// Get gets the bits pointed at by p, as a uint32.
|
||||
func word32Val_Get(p word32Val) uint32 {
|
||||
elem := p.v
|
||||
switch elem.Kind() {
|
||||
case reflect.Int32:
|
||||
return uint32(elem.Int())
|
||||
case reflect.Uint32:
|
||||
return uint32(elem.Uint())
|
||||
case reflect.Float32:
|
||||
return math.Float32bits(float32(elem.Float()))
|
||||
}
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
// Word32Val returns a reference to a int32, uint32, float32, or enum field in the struct.
|
||||
func structPointer_Word32Val(p structPointer, f field) word32Val {
|
||||
return word32Val{structPointer_field(p, f)}
|
||||
}
|
||||
|
||||
// A word32Slice is a slice of 32-bit values.
|
||||
// That is, v.Type() is []int32, []uint32, []float32, or []enum.
|
||||
type word32Slice struct {
|
||||
v reflect.Value
|
||||
}
|
||||
|
||||
func (p word32Slice) Append(x uint32) {
|
||||
n, m := p.v.Len(), p.v.Cap()
|
||||
// grow updates the slice s in place to make it one element longer.
|
||||
// s must be addressable.
|
||||
// Returns the (addressable) new element.
|
||||
func grow(s reflect.Value) reflect.Value {
|
||||
n, m := s.Len(), s.Cap()
|
||||
if n < m {
|
||||
p.v.SetLen(n + 1)
|
||||
s.SetLen(n + 1)
|
||||
} else {
|
||||
t := p.v.Type().Elem()
|
||||
p.v.Set(reflect.Append(p.v, reflect.Zero(t)))
|
||||
s.Set(reflect.Append(s, reflect.Zero(s.Type().Elem())))
|
||||
}
|
||||
elem := p.v.Index(n)
|
||||
switch elem.Kind() {
|
||||
case reflect.Int32:
|
||||
elem.SetInt(int64(int32(x)))
|
||||
case reflect.Uint32:
|
||||
elem.SetUint(uint64(x))
|
||||
case reflect.Float32:
|
||||
elem.SetFloat(float64(math.Float32frombits(x)))
|
||||
return s.Index(n)
|
||||
}
|
||||
|
||||
func (p pointer) toInt64() *int64 {
|
||||
return p.v.Interface().(*int64)
|
||||
}
|
||||
func (p pointer) toInt64Ptr() **int64 {
|
||||
return p.v.Interface().(**int64)
|
||||
}
|
||||
func (p pointer) toInt64Slice() *[]int64 {
|
||||
return p.v.Interface().(*[]int64)
|
||||
}
|
||||
|
||||
var int32ptr = reflect.TypeOf((*int32)(nil))
|
||||
|
||||
func (p pointer) toInt32() *int32 {
|
||||
return p.v.Convert(int32ptr).Interface().(*int32)
|
||||
}
|
||||
|
||||
// The toInt32Ptr/Slice methods don't work because of enums.
|
||||
// Instead, we must use set/get methods for the int32ptr/slice case.
|
||||
/*
|
||||
func (p pointer) toInt32Ptr() **int32 {
|
||||
return p.v.Interface().(**int32)
|
||||
}
|
||||
func (p pointer) toInt32Slice() *[]int32 {
|
||||
return p.v.Interface().(*[]int32)
|
||||
}
|
||||
*/
|
||||
func (p pointer) getInt32Ptr() *int32 {
|
||||
if p.v.Type().Elem().Elem() == reflect.TypeOf(int32(0)) {
|
||||
// raw int32 type
|
||||
return p.v.Elem().Interface().(*int32)
|
||||
}
|
||||
// an enum
|
||||
return p.v.Elem().Convert(int32PtrType).Interface().(*int32)
|
||||
}
|
||||
func (p pointer) setInt32Ptr(v int32) {
|
||||
// Allocate value in a *int32. Possibly convert that to a *enum.
|
||||
// Then assign it to a **int32 or **enum.
|
||||
// Note: we can convert *int32 to *enum, but we can't convert
|
||||
// **int32 to **enum!
|
||||
p.v.Elem().Set(reflect.ValueOf(&v).Convert(p.v.Type().Elem()))
|
||||
}
|
||||
|
||||
func (p word32Slice) Len() int {
|
||||
return p.v.Len()
|
||||
}
|
||||
|
||||
func (p word32Slice) Index(i int) uint32 {
|
||||
elem := p.v.Index(i)
|
||||
switch elem.Kind() {
|
||||
case reflect.Int32:
|
||||
return uint32(elem.Int())
|
||||
case reflect.Uint32:
|
||||
return uint32(elem.Uint())
|
||||
case reflect.Float32:
|
||||
return math.Float32bits(float32(elem.Float()))
|
||||
// getInt32Slice copies []int32 from p as a new slice.
|
||||
// This behavior differs from the implementation in pointer_unsafe.go.
|
||||
func (p pointer) getInt32Slice() []int32 {
|
||||
if p.v.Type().Elem().Elem() == reflect.TypeOf(int32(0)) {
|
||||
// raw int32 type
|
||||
return p.v.Elem().Interface().([]int32)
|
||||
}
|
||||
panic("unreachable")
|
||||
// an enum
|
||||
// Allocate a []int32, then assign []enum's values into it.
|
||||
// Note: we can't convert []enum to []int32.
|
||||
slice := p.v.Elem()
|
||||
s := make([]int32, slice.Len())
|
||||
for i := 0; i < slice.Len(); i++ {
|
||||
s[i] = int32(slice.Index(i).Int())
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// Word32Slice returns a reference to a []int32, []uint32, []float32, or []enum field in the struct.
|
||||
func structPointer_Word32Slice(p structPointer, f field) word32Slice {
|
||||
return word32Slice{structPointer_field(p, f)}
|
||||
}
|
||||
|
||||
// word64 is like word32 but for 64-bit values.
|
||||
type word64 struct {
|
||||
v reflect.Value
|
||||
}
|
||||
|
||||
func word64_Set(p word64, o *Buffer, x uint64) {
|
||||
t := p.v.Type().Elem()
|
||||
switch t {
|
||||
case int64Type:
|
||||
if len(o.int64s) == 0 {
|
||||
o.int64s = make([]int64, uint64PoolSize)
|
||||
}
|
||||
o.int64s[0] = int64(x)
|
||||
p.v.Set(reflect.ValueOf(&o.int64s[0]))
|
||||
o.int64s = o.int64s[1:]
|
||||
return
|
||||
case uint64Type:
|
||||
if len(o.uint64s) == 0 {
|
||||
o.uint64s = make([]uint64, uint64PoolSize)
|
||||
}
|
||||
o.uint64s[0] = x
|
||||
p.v.Set(reflect.ValueOf(&o.uint64s[0]))
|
||||
o.uint64s = o.uint64s[1:]
|
||||
return
|
||||
case float64Type:
|
||||
if len(o.float64s) == 0 {
|
||||
o.float64s = make([]float64, uint64PoolSize)
|
||||
}
|
||||
o.float64s[0] = math.Float64frombits(x)
|
||||
p.v.Set(reflect.ValueOf(&o.float64s[0]))
|
||||
o.float64s = o.float64s[1:]
|
||||
// setInt32Slice copies []int32 into p as a new slice.
|
||||
// This behavior differs from the implementation in pointer_unsafe.go.
|
||||
func (p pointer) setInt32Slice(v []int32) {
|
||||
if p.v.Type().Elem().Elem() == reflect.TypeOf(int32(0)) {
|
||||
// raw int32 type
|
||||
p.v.Elem().Set(reflect.ValueOf(v))
|
||||
return
|
||||
}
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
func word64_IsNil(p word64) bool {
|
||||
return p.v.IsNil()
|
||||
}
|
||||
|
||||
func word64_Get(p word64) uint64 {
|
||||
elem := p.v.Elem()
|
||||
switch elem.Kind() {
|
||||
case reflect.Int64:
|
||||
return uint64(elem.Int())
|
||||
case reflect.Uint64:
|
||||
return elem.Uint()
|
||||
case reflect.Float64:
|
||||
return math.Float64bits(elem.Float())
|
||||
// an enum
|
||||
// Allocate a []enum, then assign []int32's values into it.
|
||||
// Note: we can't convert []enum to []int32.
|
||||
slice := reflect.MakeSlice(p.v.Type().Elem(), len(v), cap(v))
|
||||
for i, x := range v {
|
||||
slice.Index(i).SetInt(int64(x))
|
||||
}
|
||||
panic("unreachable")
|
||||
p.v.Elem().Set(slice)
|
||||
}
|
||||
func (p pointer) appendInt32Slice(v int32) {
|
||||
grow(p.v.Elem()).SetInt(int64(v))
|
||||
}
|
||||
|
||||
func structPointer_Word64(p structPointer, f field) word64 {
|
||||
return word64{structPointer_field(p, f)}
|
||||
func (p pointer) toUint64() *uint64 {
|
||||
return p.v.Interface().(*uint64)
|
||||
}
|
||||
func (p pointer) toUint64Ptr() **uint64 {
|
||||
return p.v.Interface().(**uint64)
|
||||
}
|
||||
func (p pointer) toUint64Slice() *[]uint64 {
|
||||
return p.v.Interface().(*[]uint64)
|
||||
}
|
||||
func (p pointer) toUint32() *uint32 {
|
||||
return p.v.Interface().(*uint32)
|
||||
}
|
||||
func (p pointer) toUint32Ptr() **uint32 {
|
||||
return p.v.Interface().(**uint32)
|
||||
}
|
||||
func (p pointer) toUint32Slice() *[]uint32 {
|
||||
return p.v.Interface().(*[]uint32)
|
||||
}
|
||||
func (p pointer) toBool() *bool {
|
||||
return p.v.Interface().(*bool)
|
||||
}
|
||||
func (p pointer) toBoolPtr() **bool {
|
||||
return p.v.Interface().(**bool)
|
||||
}
|
||||
func (p pointer) toBoolSlice() *[]bool {
|
||||
return p.v.Interface().(*[]bool)
|
||||
}
|
||||
func (p pointer) toFloat64() *float64 {
|
||||
return p.v.Interface().(*float64)
|
||||
}
|
||||
func (p pointer) toFloat64Ptr() **float64 {
|
||||
return p.v.Interface().(**float64)
|
||||
}
|
||||
func (p pointer) toFloat64Slice() *[]float64 {
|
||||
return p.v.Interface().(*[]float64)
|
||||
}
|
||||
func (p pointer) toFloat32() *float32 {
|
||||
return p.v.Interface().(*float32)
|
||||
}
|
||||
func (p pointer) toFloat32Ptr() **float32 {
|
||||
return p.v.Interface().(**float32)
|
||||
}
|
||||
func (p pointer) toFloat32Slice() *[]float32 {
|
||||
return p.v.Interface().(*[]float32)
|
||||
}
|
||||
func (p pointer) toString() *string {
|
||||
return p.v.Interface().(*string)
|
||||
}
|
||||
func (p pointer) toStringPtr() **string {
|
||||
return p.v.Interface().(**string)
|
||||
}
|
||||
func (p pointer) toStringSlice() *[]string {
|
||||
return p.v.Interface().(*[]string)
|
||||
}
|
||||
func (p pointer) toBytes() *[]byte {
|
||||
return p.v.Interface().(*[]byte)
|
||||
}
|
||||
func (p pointer) toBytesSlice() *[][]byte {
|
||||
return p.v.Interface().(*[][]byte)
|
||||
}
|
||||
func (p pointer) toExtensions() *XXX_InternalExtensions {
|
||||
return p.v.Interface().(*XXX_InternalExtensions)
|
||||
}
|
||||
func (p pointer) toOldExtensions() *map[int32]Extension {
|
||||
return p.v.Interface().(*map[int32]Extension)
|
||||
}
|
||||
func (p pointer) getPointer() pointer {
|
||||
return pointer{v: p.v.Elem()}
|
||||
}
|
||||
func (p pointer) setPointer(q pointer) {
|
||||
p.v.Elem().Set(q.v)
|
||||
}
|
||||
func (p pointer) appendPointer(q pointer) {
|
||||
grow(p.v.Elem()).Set(q.v)
|
||||
}
|
||||
|
||||
// word64Val is like word32Val but for 64-bit values.
|
||||
type word64Val struct {
|
||||
v reflect.Value
|
||||
// getPointerSlice copies []*T from p as a new []pointer.
|
||||
// This behavior differs from the implementation in pointer_unsafe.go.
|
||||
func (p pointer) getPointerSlice() []pointer {
|
||||
if p.v.IsNil() {
|
||||
return nil
|
||||
}
|
||||
n := p.v.Elem().Len()
|
||||
s := make([]pointer, n)
|
||||
for i := 0; i < n; i++ {
|
||||
s[i] = pointer{v: p.v.Elem().Index(i)}
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func word64Val_Set(p word64Val, o *Buffer, x uint64) {
|
||||
switch p.v.Type() {
|
||||
case int64Type:
|
||||
p.v.SetInt(int64(x))
|
||||
return
|
||||
case uint64Type:
|
||||
p.v.SetUint(x)
|
||||
return
|
||||
case float64Type:
|
||||
p.v.SetFloat(math.Float64frombits(x))
|
||||
// setPointerSlice copies []pointer into p as a new []*T.
|
||||
// This behavior differs from the implementation in pointer_unsafe.go.
|
||||
func (p pointer) setPointerSlice(v []pointer) {
|
||||
if v == nil {
|
||||
p.v.Elem().Set(reflect.New(p.v.Elem().Type()).Elem())
|
||||
return
|
||||
}
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
func word64Val_Get(p word64Val) uint64 {
|
||||
elem := p.v
|
||||
switch elem.Kind() {
|
||||
case reflect.Int64:
|
||||
return uint64(elem.Int())
|
||||
case reflect.Uint64:
|
||||
return elem.Uint()
|
||||
case reflect.Float64:
|
||||
return math.Float64bits(elem.Float())
|
||||
s := reflect.MakeSlice(p.v.Elem().Type(), 0, len(v))
|
||||
for _, p := range v {
|
||||
s = reflect.Append(s, p.v)
|
||||
}
|
||||
panic("unreachable")
|
||||
p.v.Elem().Set(s)
|
||||
}
|
||||
|
||||
func structPointer_Word64Val(p structPointer, f field) word64Val {
|
||||
return word64Val{structPointer_field(p, f)}
|
||||
}
|
||||
|
||||
type word64Slice struct {
|
||||
v reflect.Value
|
||||
}
|
||||
|
||||
func (p word64Slice) Append(x uint64) {
|
||||
n, m := p.v.Len(), p.v.Cap()
|
||||
if n < m {
|
||||
p.v.SetLen(n + 1)
|
||||
} else {
|
||||
t := p.v.Type().Elem()
|
||||
p.v.Set(reflect.Append(p.v, reflect.Zero(t)))
|
||||
}
|
||||
elem := p.v.Index(n)
|
||||
switch elem.Kind() {
|
||||
case reflect.Int64:
|
||||
elem.SetInt(int64(int64(x)))
|
||||
case reflect.Uint64:
|
||||
elem.SetUint(uint64(x))
|
||||
case reflect.Float64:
|
||||
elem.SetFloat(float64(math.Float64frombits(x)))
|
||||
// getInterfacePointer returns a pointer that points to the
|
||||
// interface data of the interface pointed by p.
|
||||
func (p pointer) getInterfacePointer() pointer {
|
||||
if p.v.Elem().IsNil() {
|
||||
return pointer{v: p.v.Elem()}
|
||||
}
|
||||
return pointer{v: p.v.Elem().Elem().Elem().Field(0).Addr()} // *interface -> interface -> *struct -> struct
|
||||
}
|
||||
|
||||
func (p word64Slice) Len() int {
|
||||
return p.v.Len()
|
||||
func (p pointer) asPointerTo(t reflect.Type) reflect.Value {
|
||||
// TODO: check that p.v.Type().Elem() == t?
|
||||
return p.v
|
||||
}
|
||||
|
||||
func (p word64Slice) Index(i int) uint64 {
|
||||
elem := p.v.Index(i)
|
||||
switch elem.Kind() {
|
||||
case reflect.Int64:
|
||||
return uint64(elem.Int())
|
||||
case reflect.Uint64:
|
||||
return uint64(elem.Uint())
|
||||
case reflect.Float64:
|
||||
return math.Float64bits(float64(elem.Float()))
|
||||
}
|
||||
panic("unreachable")
|
||||
func atomicLoadUnmarshalInfo(p **unmarshalInfo) *unmarshalInfo {
|
||||
atomicLock.Lock()
|
||||
defer atomicLock.Unlock()
|
||||
return *p
|
||||
}
|
||||
func atomicStoreUnmarshalInfo(p **unmarshalInfo, v *unmarshalInfo) {
|
||||
atomicLock.Lock()
|
||||
defer atomicLock.Unlock()
|
||||
*p = v
|
||||
}
|
||||
func atomicLoadMarshalInfo(p **marshalInfo) *marshalInfo {
|
||||
atomicLock.Lock()
|
||||
defer atomicLock.Unlock()
|
||||
return *p
|
||||
}
|
||||
func atomicStoreMarshalInfo(p **marshalInfo, v *marshalInfo) {
|
||||
atomicLock.Lock()
|
||||
defer atomicLock.Unlock()
|
||||
*p = v
|
||||
}
|
||||
func atomicLoadMergeInfo(p **mergeInfo) *mergeInfo {
|
||||
atomicLock.Lock()
|
||||
defer atomicLock.Unlock()
|
||||
return *p
|
||||
}
|
||||
func atomicStoreMergeInfo(p **mergeInfo, v *mergeInfo) {
|
||||
atomicLock.Lock()
|
||||
defer atomicLock.Unlock()
|
||||
*p = v
|
||||
}
|
||||
func atomicLoadDiscardInfo(p **discardInfo) *discardInfo {
|
||||
atomicLock.Lock()
|
||||
defer atomicLock.Unlock()
|
||||
return *p
|
||||
}
|
||||
func atomicStoreDiscardInfo(p **discardInfo, v *discardInfo) {
|
||||
atomicLock.Lock()
|
||||
defer atomicLock.Unlock()
|
||||
*p = v
|
||||
}
|
||||
|
||||
func structPointer_Word64Slice(p structPointer, f field) word64Slice {
|
||||
return word64Slice{structPointer_field(p, f)}
|
||||
}
|
||||
var atomicLock sync.Mutex
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// +build !appengine,!js
|
||||
// +build !purego,!appengine,!js
|
||||
|
||||
// This file contains the implementation of the proto field accesses using package unsafe.
|
||||
|
||||
|
@ -37,38 +37,13 @@ package proto
|
|||
|
||||
import (
|
||||
"reflect"
|
||||
"sync/atomic"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// NOTE: These type_Foo functions would more idiomatically be methods,
|
||||
// but Go does not allow methods on pointer types, and we must preserve
|
||||
// some pointer type for the garbage collector. We use these
|
||||
// funcs with clunky names as our poor approximation to methods.
|
||||
//
|
||||
// An alternative would be
|
||||
// type structPointer struct { p unsafe.Pointer }
|
||||
// but that does not registerize as well.
|
||||
const unsafeAllowed = true
|
||||
|
||||
// A structPointer is a pointer to a struct.
|
||||
type structPointer unsafe.Pointer
|
||||
|
||||
// toStructPointer returns a structPointer equivalent to the given reflect value.
|
||||
func toStructPointer(v reflect.Value) structPointer {
|
||||
return structPointer(unsafe.Pointer(v.Pointer()))
|
||||
}
|
||||
|
||||
// IsNil reports whether p is nil.
|
||||
func structPointer_IsNil(p structPointer) bool {
|
||||
return p == nil
|
||||
}
|
||||
|
||||
// Interface returns the struct pointer, assumed to have element type t,
|
||||
// as an interface value.
|
||||
func structPointer_Interface(p structPointer, t reflect.Type) interface{} {
|
||||
return reflect.NewAt(t, unsafe.Pointer(p)).Interface()
|
||||
}
|
||||
|
||||
// A field identifies a field in a struct, accessible from a structPointer.
|
||||
// A field identifies a field in a struct, accessible from a pointer.
|
||||
// In this implementation, a field is identified by its byte offset from the start of the struct.
|
||||
type field uintptr
|
||||
|
||||
|
@ -80,191 +55,254 @@ func toField(f *reflect.StructField) field {
|
|||
// invalidField is an invalid field identifier.
|
||||
const invalidField = ^field(0)
|
||||
|
||||
// zeroField is a noop when calling pointer.offset.
|
||||
const zeroField = field(0)
|
||||
|
||||
// IsValid reports whether the field identifier is valid.
|
||||
func (f field) IsValid() bool {
|
||||
return f != ^field(0)
|
||||
return f != invalidField
|
||||
}
|
||||
|
||||
// Bytes returns the address of a []byte field in the struct.
|
||||
func structPointer_Bytes(p structPointer, f field) *[]byte {
|
||||
return (*[]byte)(unsafe.Pointer(uintptr(p) + uintptr(f)))
|
||||
// The pointer type below is for the new table-driven encoder/decoder.
|
||||
// The implementation here uses unsafe.Pointer to create a generic pointer.
|
||||
// In pointer_reflect.go we use reflect instead of unsafe to implement
|
||||
// the same (but slower) interface.
|
||||
type pointer struct {
|
||||
p unsafe.Pointer
|
||||
}
|
||||
|
||||
// BytesSlice returns the address of a [][]byte field in the struct.
|
||||
func structPointer_BytesSlice(p structPointer, f field) *[][]byte {
|
||||
return (*[][]byte)(unsafe.Pointer(uintptr(p) + uintptr(f)))
|
||||
// size of pointer
|
||||
var ptrSize = unsafe.Sizeof(uintptr(0))
|
||||
|
||||
// toPointer converts an interface of pointer type to a pointer
|
||||
// that points to the same target.
|
||||
func toPointer(i *Message) pointer {
|
||||
// Super-tricky - read pointer out of data word of interface value.
|
||||
// Saves ~25ns over the equivalent:
|
||||
// return valToPointer(reflect.ValueOf(*i))
|
||||
return pointer{p: (*[2]unsafe.Pointer)(unsafe.Pointer(i))[1]}
|
||||
}
|
||||
|
||||
// Bool returns the address of a *bool field in the struct.
|
||||
func structPointer_Bool(p structPointer, f field) **bool {
|
||||
return (**bool)(unsafe.Pointer(uintptr(p) + uintptr(f)))
|
||||
}
|
||||
|
||||
// BoolVal returns the address of a bool field in the struct.
|
||||
func structPointer_BoolVal(p structPointer, f field) *bool {
|
||||
return (*bool)(unsafe.Pointer(uintptr(p) + uintptr(f)))
|
||||
}
|
||||
|
||||
// BoolSlice returns the address of a []bool field in the struct.
|
||||
func structPointer_BoolSlice(p structPointer, f field) *[]bool {
|
||||
return (*[]bool)(unsafe.Pointer(uintptr(p) + uintptr(f)))
|
||||
}
|
||||
|
||||
// String returns the address of a *string field in the struct.
|
||||
func structPointer_String(p structPointer, f field) **string {
|
||||
return (**string)(unsafe.Pointer(uintptr(p) + uintptr(f)))
|
||||
}
|
||||
|
||||
// StringVal returns the address of a string field in the struct.
|
||||
func structPointer_StringVal(p structPointer, f field) *string {
|
||||
return (*string)(unsafe.Pointer(uintptr(p) + uintptr(f)))
|
||||
}
|
||||
|
||||
// StringSlice returns the address of a []string field in the struct.
|
||||
func structPointer_StringSlice(p structPointer, f field) *[]string {
|
||||
return (*[]string)(unsafe.Pointer(uintptr(p) + uintptr(f)))
|
||||
}
|
||||
|
||||
// ExtMap returns the address of an extension map field in the struct.
|
||||
func structPointer_Extensions(p structPointer, f field) *XXX_InternalExtensions {
|
||||
return (*XXX_InternalExtensions)(unsafe.Pointer(uintptr(p) + uintptr(f)))
|
||||
}
|
||||
|
||||
func structPointer_ExtMap(p structPointer, f field) *map[int32]Extension {
|
||||
return (*map[int32]Extension)(unsafe.Pointer(uintptr(p) + uintptr(f)))
|
||||
}
|
||||
|
||||
// NewAt returns the reflect.Value for a pointer to a field in the struct.
|
||||
func structPointer_NewAt(p structPointer, f field, typ reflect.Type) reflect.Value {
|
||||
return reflect.NewAt(typ, unsafe.Pointer(uintptr(p)+uintptr(f)))
|
||||
}
|
||||
|
||||
// SetStructPointer writes a *struct field in the struct.
|
||||
func structPointer_SetStructPointer(p structPointer, f field, q structPointer) {
|
||||
*(*structPointer)(unsafe.Pointer(uintptr(p) + uintptr(f))) = q
|
||||
}
|
||||
|
||||
// GetStructPointer reads a *struct field in the struct.
|
||||
func structPointer_GetStructPointer(p structPointer, f field) structPointer {
|
||||
return *(*structPointer)(unsafe.Pointer(uintptr(p) + uintptr(f)))
|
||||
}
|
||||
|
||||
// StructPointerSlice the address of a []*struct field in the struct.
|
||||
func structPointer_StructPointerSlice(p structPointer, f field) *structPointerSlice {
|
||||
return (*structPointerSlice)(unsafe.Pointer(uintptr(p) + uintptr(f)))
|
||||
}
|
||||
|
||||
// A structPointerSlice represents a slice of pointers to structs (themselves submessages or groups).
|
||||
type structPointerSlice []structPointer
|
||||
|
||||
func (v *structPointerSlice) Len() int { return len(*v) }
|
||||
func (v *structPointerSlice) Index(i int) structPointer { return (*v)[i] }
|
||||
func (v *structPointerSlice) Append(p structPointer) { *v = append(*v, p) }
|
||||
|
||||
// A word32 is the address of a "pointer to 32-bit value" field.
|
||||
type word32 **uint32
|
||||
|
||||
// IsNil reports whether *v is nil.
|
||||
func word32_IsNil(p word32) bool {
|
||||
return *p == nil
|
||||
}
|
||||
|
||||
// Set sets *v to point at a newly allocated word set to x.
|
||||
func word32_Set(p word32, o *Buffer, x uint32) {
|
||||
if len(o.uint32s) == 0 {
|
||||
o.uint32s = make([]uint32, uint32PoolSize)
|
||||
// toAddrPointer converts an interface to a pointer that points to
|
||||
// the interface data.
|
||||
func toAddrPointer(i *interface{}, isptr bool) pointer {
|
||||
// Super-tricky - read or get the address of data word of interface value.
|
||||
if isptr {
|
||||
// The interface is of pointer type, thus it is a direct interface.
|
||||
// The data word is the pointer data itself. We take its address.
|
||||
return pointer{p: unsafe.Pointer(uintptr(unsafe.Pointer(i)) + ptrSize)}
|
||||
}
|
||||
o.uint32s[0] = x
|
||||
*p = &o.uint32s[0]
|
||||
o.uint32s = o.uint32s[1:]
|
||||
// The interface is not of pointer type. The data word is the pointer
|
||||
// to the data.
|
||||
return pointer{p: (*[2]unsafe.Pointer)(unsafe.Pointer(i))[1]}
|
||||
}
|
||||
|
||||
// Get gets the value pointed at by *v.
|
||||
func word32_Get(p word32) uint32 {
|
||||
return **p
|
||||
// valToPointer converts v to a pointer. v must be of pointer type.
|
||||
func valToPointer(v reflect.Value) pointer {
|
||||
return pointer{p: unsafe.Pointer(v.Pointer())}
|
||||
}
|
||||
|
||||
// Word32 returns the address of a *int32, *uint32, *float32, or *enum field in the struct.
|
||||
func structPointer_Word32(p structPointer, f field) word32 {
|
||||
return word32((**uint32)(unsafe.Pointer(uintptr(p) + uintptr(f))))
|
||||
// offset converts from a pointer to a structure to a pointer to
|
||||
// one of its fields.
|
||||
func (p pointer) offset(f field) pointer {
|
||||
// For safety, we should panic if !f.IsValid, however calling panic causes
|
||||
// this to no longer be inlineable, which is a serious performance cost.
|
||||
/*
|
||||
if !f.IsValid() {
|
||||
panic("invalid field")
|
||||
}
|
||||
*/
|
||||
return pointer{p: unsafe.Pointer(uintptr(p.p) + uintptr(f))}
|
||||
}
|
||||
|
||||
// A word32Val is the address of a 32-bit value field.
|
||||
type word32Val *uint32
|
||||
|
||||
// Set sets *p to x.
|
||||
func word32Val_Set(p word32Val, x uint32) {
|
||||
*p = x
|
||||
func (p pointer) isNil() bool {
|
||||
return p.p == nil
|
||||
}
|
||||
|
||||
// Get gets the value pointed at by p.
|
||||
func word32Val_Get(p word32Val) uint32 {
|
||||
return *p
|
||||
func (p pointer) toInt64() *int64 {
|
||||
return (*int64)(p.p)
|
||||
}
|
||||
func (p pointer) toInt64Ptr() **int64 {
|
||||
return (**int64)(p.p)
|
||||
}
|
||||
func (p pointer) toInt64Slice() *[]int64 {
|
||||
return (*[]int64)(p.p)
|
||||
}
|
||||
func (p pointer) toInt32() *int32 {
|
||||
return (*int32)(p.p)
|
||||
}
|
||||
|
||||
// Word32Val returns the address of a *int32, *uint32, *float32, or *enum field in the struct.
|
||||
func structPointer_Word32Val(p structPointer, f field) word32Val {
|
||||
return word32Val((*uint32)(unsafe.Pointer(uintptr(p) + uintptr(f))))
|
||||
}
|
||||
|
||||
// A word32Slice is a slice of 32-bit values.
|
||||
type word32Slice []uint32
|
||||
|
||||
func (v *word32Slice) Append(x uint32) { *v = append(*v, x) }
|
||||
func (v *word32Slice) Len() int { return len(*v) }
|
||||
func (v *word32Slice) Index(i int) uint32 { return (*v)[i] }
|
||||
|
||||
// Word32Slice returns the address of a []int32, []uint32, []float32, or []enum field in the struct.
|
||||
func structPointer_Word32Slice(p structPointer, f field) *word32Slice {
|
||||
return (*word32Slice)(unsafe.Pointer(uintptr(p) + uintptr(f)))
|
||||
}
|
||||
|
||||
// word64 is like word32 but for 64-bit values.
|
||||
type word64 **uint64
|
||||
|
||||
func word64_Set(p word64, o *Buffer, x uint64) {
|
||||
if len(o.uint64s) == 0 {
|
||||
o.uint64s = make([]uint64, uint64PoolSize)
|
||||
// See pointer_reflect.go for why toInt32Ptr/Slice doesn't exist.
|
||||
/*
|
||||
func (p pointer) toInt32Ptr() **int32 {
|
||||
return (**int32)(p.p)
|
||||
}
|
||||
o.uint64s[0] = x
|
||||
*p = &o.uint64s[0]
|
||||
o.uint64s = o.uint64s[1:]
|
||||
func (p pointer) toInt32Slice() *[]int32 {
|
||||
return (*[]int32)(p.p)
|
||||
}
|
||||
*/
|
||||
func (p pointer) getInt32Ptr() *int32 {
|
||||
return *(**int32)(p.p)
|
||||
}
|
||||
func (p pointer) setInt32Ptr(v int32) {
|
||||
*(**int32)(p.p) = &v
|
||||
}
|
||||
|
||||
func word64_IsNil(p word64) bool {
|
||||
return *p == nil
|
||||
// getInt32Slice loads a []int32 from p.
|
||||
// The value returned is aliased with the original slice.
|
||||
// This behavior differs from the implementation in pointer_reflect.go.
|
||||
func (p pointer) getInt32Slice() []int32 {
|
||||
return *(*[]int32)(p.p)
|
||||
}
|
||||
|
||||
func word64_Get(p word64) uint64 {
|
||||
return **p
|
||||
// setInt32Slice stores a []int32 to p.
|
||||
// The value set is aliased with the input slice.
|
||||
// This behavior differs from the implementation in pointer_reflect.go.
|
||||
func (p pointer) setInt32Slice(v []int32) {
|
||||
*(*[]int32)(p.p) = v
|
||||
}
|
||||
|
||||
func structPointer_Word64(p structPointer, f field) word64 {
|
||||
return word64((**uint64)(unsafe.Pointer(uintptr(p) + uintptr(f))))
|
||||
// TODO: Can we get rid of appendInt32Slice and use setInt32Slice instead?
|
||||
func (p pointer) appendInt32Slice(v int32) {
|
||||
s := (*[]int32)(p.p)
|
||||
*s = append(*s, v)
|
||||
}
|
||||
|
||||
// word64Val is like word32Val but for 64-bit values.
|
||||
type word64Val *uint64
|
||||
|
||||
func word64Val_Set(p word64Val, o *Buffer, x uint64) {
|
||||
*p = x
|
||||
func (p pointer) toUint64() *uint64 {
|
||||
return (*uint64)(p.p)
|
||||
}
|
||||
func (p pointer) toUint64Ptr() **uint64 {
|
||||
return (**uint64)(p.p)
|
||||
}
|
||||
func (p pointer) toUint64Slice() *[]uint64 {
|
||||
return (*[]uint64)(p.p)
|
||||
}
|
||||
func (p pointer) toUint32() *uint32 {
|
||||
return (*uint32)(p.p)
|
||||
}
|
||||
func (p pointer) toUint32Ptr() **uint32 {
|
||||
return (**uint32)(p.p)
|
||||
}
|
||||
func (p pointer) toUint32Slice() *[]uint32 {
|
||||
return (*[]uint32)(p.p)
|
||||
}
|
||||
func (p pointer) toBool() *bool {
|
||||
return (*bool)(p.p)
|
||||
}
|
||||
func (p pointer) toBoolPtr() **bool {
|
||||
return (**bool)(p.p)
|
||||
}
|
||||
func (p pointer) toBoolSlice() *[]bool {
|
||||
return (*[]bool)(p.p)
|
||||
}
|
||||
func (p pointer) toFloat64() *float64 {
|
||||
return (*float64)(p.p)
|
||||
}
|
||||
func (p pointer) toFloat64Ptr() **float64 {
|
||||
return (**float64)(p.p)
|
||||
}
|
||||
func (p pointer) toFloat64Slice() *[]float64 {
|
||||
return (*[]float64)(p.p)
|
||||
}
|
||||
func (p pointer) toFloat32() *float32 {
|
||||
return (*float32)(p.p)
|
||||
}
|
||||
func (p pointer) toFloat32Ptr() **float32 {
|
||||
return (**float32)(p.p)
|
||||
}
|
||||
func (p pointer) toFloat32Slice() *[]float32 {
|
||||
return (*[]float32)(p.p)
|
||||
}
|
||||
func (p pointer) toString() *string {
|
||||
return (*string)(p.p)
|
||||
}
|
||||
func (p pointer) toStringPtr() **string {
|
||||
return (**string)(p.p)
|
||||
}
|
||||
func (p pointer) toStringSlice() *[]string {
|
||||
return (*[]string)(p.p)
|
||||
}
|
||||
func (p pointer) toBytes() *[]byte {
|
||||
return (*[]byte)(p.p)
|
||||
}
|
||||
func (p pointer) toBytesSlice() *[][]byte {
|
||||
return (*[][]byte)(p.p)
|
||||
}
|
||||
func (p pointer) toExtensions() *XXX_InternalExtensions {
|
||||
return (*XXX_InternalExtensions)(p.p)
|
||||
}
|
||||
func (p pointer) toOldExtensions() *map[int32]Extension {
|
||||
return (*map[int32]Extension)(p.p)
|
||||
}
|
||||
|
||||
func word64Val_Get(p word64Val) uint64 {
|
||||
return *p
|
||||
// getPointerSlice loads []*T from p as a []pointer.
|
||||
// The value returned is aliased with the original slice.
|
||||
// This behavior differs from the implementation in pointer_reflect.go.
|
||||
func (p pointer) getPointerSlice() []pointer {
|
||||
// Super-tricky - p should point to a []*T where T is a
|
||||
// message type. We load it as []pointer.
|
||||
return *(*[]pointer)(p.p)
|
||||
}
|
||||
|
||||
func structPointer_Word64Val(p structPointer, f field) word64Val {
|
||||
return word64Val((*uint64)(unsafe.Pointer(uintptr(p) + uintptr(f))))
|
||||
// setPointerSlice stores []pointer into p as a []*T.
|
||||
// The value set is aliased with the input slice.
|
||||
// This behavior differs from the implementation in pointer_reflect.go.
|
||||
func (p pointer) setPointerSlice(v []pointer) {
|
||||
// Super-tricky - p should point to a []*T where T is a
|
||||
// message type. We store it as []pointer.
|
||||
*(*[]pointer)(p.p) = v
|
||||
}
|
||||
|
||||
// word64Slice is like word32Slice but for 64-bit values.
|
||||
type word64Slice []uint64
|
||||
|
||||
func (v *word64Slice) Append(x uint64) { *v = append(*v, x) }
|
||||
func (v *word64Slice) Len() int { return len(*v) }
|
||||
func (v *word64Slice) Index(i int) uint64 { return (*v)[i] }
|
||||
|
||||
func structPointer_Word64Slice(p structPointer, f field) *word64Slice {
|
||||
return (*word64Slice)(unsafe.Pointer(uintptr(p) + uintptr(f)))
|
||||
// getPointer loads the pointer at p and returns it.
|
||||
func (p pointer) getPointer() pointer {
|
||||
return pointer{p: *(*unsafe.Pointer)(p.p)}
|
||||
}
|
||||
|
||||
// setPointer stores the pointer q at p.
|
||||
func (p pointer) setPointer(q pointer) {
|
||||
*(*unsafe.Pointer)(p.p) = q.p
|
||||
}
|
||||
|
||||
// append q to the slice pointed to by p.
|
||||
func (p pointer) appendPointer(q pointer) {
|
||||
s := (*[]unsafe.Pointer)(p.p)
|
||||
*s = append(*s, q.p)
|
||||
}
|
||||
|
||||
// getInterfacePointer returns a pointer that points to the
|
||||
// interface data of the interface pointed by p.
|
||||
func (p pointer) getInterfacePointer() pointer {
|
||||
// Super-tricky - read pointer out of data word of interface value.
|
||||
return pointer{p: (*(*[2]unsafe.Pointer)(p.p))[1]}
|
||||
}
|
||||
|
||||
// asPointerTo returns a reflect.Value that is a pointer to an
|
||||
// object of type t stored at p.
|
||||
func (p pointer) asPointerTo(t reflect.Type) reflect.Value {
|
||||
return reflect.NewAt(t, p.p)
|
||||
}
|
||||
|
||||
func atomicLoadUnmarshalInfo(p **unmarshalInfo) *unmarshalInfo {
|
||||
return (*unmarshalInfo)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(p))))
|
||||
}
|
||||
func atomicStoreUnmarshalInfo(p **unmarshalInfo, v *unmarshalInfo) {
|
||||
atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(p)), unsafe.Pointer(v))
|
||||
}
|
||||
func atomicLoadMarshalInfo(p **marshalInfo) *marshalInfo {
|
||||
return (*marshalInfo)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(p))))
|
||||
}
|
||||
func atomicStoreMarshalInfo(p **marshalInfo, v *marshalInfo) {
|
||||
atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(p)), unsafe.Pointer(v))
|
||||
}
|
||||
func atomicLoadMergeInfo(p **mergeInfo) *mergeInfo {
|
||||
return (*mergeInfo)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(p))))
|
||||
}
|
||||
func atomicStoreMergeInfo(p **mergeInfo, v *mergeInfo) {
|
||||
atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(p)), unsafe.Pointer(v))
|
||||
}
|
||||
func atomicLoadDiscardInfo(p **discardInfo) *discardInfo {
|
||||
return (*discardInfo)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(p))))
|
||||
}
|
||||
func atomicStoreDiscardInfo(p **discardInfo, v *discardInfo) {
|
||||
atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(p)), unsafe.Pointer(v))
|
||||
}
|
||||
|
|
|
@ -58,42 +58,6 @@ const (
|
|||
WireFixed32 = 5
|
||||
)
|
||||
|
||||
const startSize = 10 // initial slice/string sizes
|
||||
|
||||
// Encoders are defined in encode.go
|
||||
// An encoder outputs the full representation of a field, including its
|
||||
// tag and encoder type.
|
||||
type encoder func(p *Buffer, prop *Properties, base structPointer) error
|
||||
|
||||
// A valueEncoder encodes a single integer in a particular encoding.
|
||||
type valueEncoder func(o *Buffer, x uint64) error
|
||||
|
||||
// Sizers are defined in encode.go
|
||||
// A sizer returns the encoded size of a field, including its tag and encoder
|
||||
// type.
|
||||
type sizer func(prop *Properties, base structPointer) int
|
||||
|
||||
// A valueSizer returns the encoded size of a single integer in a particular
|
||||
// encoding.
|
||||
type valueSizer func(x uint64) int
|
||||
|
||||
// Decoders are defined in decode.go
|
||||
// A decoder creates a value from its wire representation.
|
||||
// Unrecognized subelements are saved in unrec.
|
||||
type decoder func(p *Buffer, prop *Properties, base structPointer) error
|
||||
|
||||
// A valueDecoder decodes a single integer in a particular encoding.
|
||||
type valueDecoder func(o *Buffer) (x uint64, err error)
|
||||
|
||||
// A oneofMarshaler does the marshaling for all oneof fields in a message.
|
||||
type oneofMarshaler func(Message, *Buffer) error
|
||||
|
||||
// A oneofUnmarshaler does the unmarshaling for a oneof field in a message.
|
||||
type oneofUnmarshaler func(Message, int, int, *Buffer) (bool, error)
|
||||
|
||||
// A oneofSizer does the sizing for all oneof fields in a message.
|
||||
type oneofSizer func(Message) int
|
||||
|
||||
// tagMap is an optimization over map[int]int for typical protocol buffer
|
||||
// use-cases. Encoded protocol buffers are often in tag order with small tag
|
||||
// numbers.
|
||||
|
@ -140,13 +104,6 @@ type StructProperties struct {
|
|||
decoderTags tagMap // map from proto tag to struct field number
|
||||
decoderOrigNames map[string]int // map from original name to struct field number
|
||||
order []int // list of struct field numbers in tag order
|
||||
unrecField field // field id of the XXX_unrecognized []byte field
|
||||
extendable bool // is this an extendable proto
|
||||
|
||||
oneofMarshaler oneofMarshaler
|
||||
oneofUnmarshaler oneofUnmarshaler
|
||||
oneofSizer oneofSizer
|
||||
stype reflect.Type
|
||||
|
||||
// OneofTypes contains information about the oneof fields in this message.
|
||||
// It is keyed by the original name of a field.
|
||||
|
@ -182,41 +139,24 @@ type Properties struct {
|
|||
Repeated bool
|
||||
Packed bool // relevant for repeated primitives only
|
||||
Enum string // set for enum types only
|
||||
proto3 bool // whether this is known to be a proto3 field; set for []byte only
|
||||
proto3 bool // whether this is known to be a proto3 field
|
||||
oneof bool // whether this is a oneof field
|
||||
|
||||
Default string // default value
|
||||
HasDefault bool // whether an explicit default was provided
|
||||
def_uint64 uint64
|
||||
|
||||
enc encoder
|
||||
valEnc valueEncoder // set for bool and numeric types only
|
||||
field field
|
||||
tagcode []byte // encoding of EncodeVarint((Tag<<3)|WireType)
|
||||
tagbuf [8]byte
|
||||
stype reflect.Type // set for struct types only
|
||||
sprop *StructProperties // set for struct types only
|
||||
isMarshaler bool
|
||||
isUnmarshaler bool
|
||||
stype reflect.Type // set for struct types only
|
||||
sprop *StructProperties // set for struct types only
|
||||
|
||||
mtype reflect.Type // set for map types only
|
||||
mkeyprop *Properties // set for map types only
|
||||
mvalprop *Properties // set for map types only
|
||||
|
||||
size sizer
|
||||
valSize valueSizer // set for bool and numeric types only
|
||||
|
||||
dec decoder
|
||||
valDec valueDecoder // set for bool and numeric types only
|
||||
|
||||
// If this is a packable field, this will be the decoder for the packed version of the field.
|
||||
packedDec decoder
|
||||
mtype reflect.Type // set for map types only
|
||||
MapKeyProp *Properties // set for map types only
|
||||
MapValProp *Properties // set for map types only
|
||||
}
|
||||
|
||||
// String formats the properties in the protobuf struct field tag style.
|
||||
func (p *Properties) String() string {
|
||||
s := p.Wire
|
||||
s = ","
|
||||
s += ","
|
||||
s += strconv.Itoa(p.Tag)
|
||||
if p.Required {
|
||||
s += ",req"
|
||||
|
@ -262,29 +202,14 @@ func (p *Properties) Parse(s string) {
|
|||
switch p.Wire {
|
||||
case "varint":
|
||||
p.WireType = WireVarint
|
||||
p.valEnc = (*Buffer).EncodeVarint
|
||||
p.valDec = (*Buffer).DecodeVarint
|
||||
p.valSize = sizeVarint
|
||||
case "fixed32":
|
||||
p.WireType = WireFixed32
|
||||
p.valEnc = (*Buffer).EncodeFixed32
|
||||
p.valDec = (*Buffer).DecodeFixed32
|
||||
p.valSize = sizeFixed32
|
||||
case "fixed64":
|
||||
p.WireType = WireFixed64
|
||||
p.valEnc = (*Buffer).EncodeFixed64
|
||||
p.valDec = (*Buffer).DecodeFixed64
|
||||
p.valSize = sizeFixed64
|
||||
case "zigzag32":
|
||||
p.WireType = WireVarint
|
||||
p.valEnc = (*Buffer).EncodeZigzag32
|
||||
p.valDec = (*Buffer).DecodeZigzag32
|
||||
p.valSize = sizeZigzag32
|
||||
case "zigzag64":
|
||||
p.WireType = WireVarint
|
||||
p.valEnc = (*Buffer).EncodeZigzag64
|
||||
p.valDec = (*Buffer).DecodeZigzag64
|
||||
p.valSize = sizeZigzag64
|
||||
case "bytes", "group":
|
||||
p.WireType = WireBytes
|
||||
// no numeric converter for non-numeric types
|
||||
|
@ -299,6 +224,7 @@ func (p *Properties) Parse(s string) {
|
|||
return
|
||||
}
|
||||
|
||||
outer:
|
||||
for i := 2; i < len(fields); i++ {
|
||||
f := fields[i]
|
||||
switch {
|
||||
|
@ -326,256 +252,41 @@ func (p *Properties) Parse(s string) {
|
|||
if i+1 < len(fields) {
|
||||
// Commas aren't escaped, and def is always last.
|
||||
p.Default += "," + strings.Join(fields[i+1:], ",")
|
||||
break
|
||||
break outer
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func logNoSliceEnc(t1, t2 reflect.Type) {
|
||||
fmt.Fprintf(os.Stderr, "proto: no slice oenc for %T = []%T\n", t1, t2)
|
||||
}
|
||||
|
||||
var protoMessageType = reflect.TypeOf((*Message)(nil)).Elem()
|
||||
|
||||
// Initialize the fields for encoding and decoding.
|
||||
func (p *Properties) setEncAndDec(typ reflect.Type, f *reflect.StructField, lockGetProp bool) {
|
||||
p.enc = nil
|
||||
p.dec = nil
|
||||
p.size = nil
|
||||
|
||||
// setFieldProps initializes the field properties for submessages and maps.
|
||||
func (p *Properties) setFieldProps(typ reflect.Type, f *reflect.StructField, lockGetProp bool) {
|
||||
switch t1 := typ; t1.Kind() {
|
||||
default:
|
||||
fmt.Fprintf(os.Stderr, "proto: no coders for %v\n", t1)
|
||||
|
||||
// proto3 scalar types
|
||||
|
||||
case reflect.Bool:
|
||||
p.enc = (*Buffer).enc_proto3_bool
|
||||
p.dec = (*Buffer).dec_proto3_bool
|
||||
p.size = size_proto3_bool
|
||||
case reflect.Int32:
|
||||
p.enc = (*Buffer).enc_proto3_int32
|
||||
p.dec = (*Buffer).dec_proto3_int32
|
||||
p.size = size_proto3_int32
|
||||
case reflect.Uint32:
|
||||
p.enc = (*Buffer).enc_proto3_uint32
|
||||
p.dec = (*Buffer).dec_proto3_int32 // can reuse
|
||||
p.size = size_proto3_uint32
|
||||
case reflect.Int64, reflect.Uint64:
|
||||
p.enc = (*Buffer).enc_proto3_int64
|
||||
p.dec = (*Buffer).dec_proto3_int64
|
||||
p.size = size_proto3_int64
|
||||
case reflect.Float32:
|
||||
p.enc = (*Buffer).enc_proto3_uint32 // can just treat them as bits
|
||||
p.dec = (*Buffer).dec_proto3_int32
|
||||
p.size = size_proto3_uint32
|
||||
case reflect.Float64:
|
||||
p.enc = (*Buffer).enc_proto3_int64 // can just treat them as bits
|
||||
p.dec = (*Buffer).dec_proto3_int64
|
||||
p.size = size_proto3_int64
|
||||
case reflect.String:
|
||||
p.enc = (*Buffer).enc_proto3_string
|
||||
p.dec = (*Buffer).dec_proto3_string
|
||||
p.size = size_proto3_string
|
||||
|
||||
case reflect.Ptr:
|
||||
switch t2 := t1.Elem(); t2.Kind() {
|
||||
default:
|
||||
fmt.Fprintf(os.Stderr, "proto: no encoder function for %v -> %v\n", t1, t2)
|
||||
break
|
||||
case reflect.Bool:
|
||||
p.enc = (*Buffer).enc_bool
|
||||
p.dec = (*Buffer).dec_bool
|
||||
p.size = size_bool
|
||||
case reflect.Int32:
|
||||
p.enc = (*Buffer).enc_int32
|
||||
p.dec = (*Buffer).dec_int32
|
||||
p.size = size_int32
|
||||
case reflect.Uint32:
|
||||
p.enc = (*Buffer).enc_uint32
|
||||
p.dec = (*Buffer).dec_int32 // can reuse
|
||||
p.size = size_uint32
|
||||
case reflect.Int64, reflect.Uint64:
|
||||
p.enc = (*Buffer).enc_int64
|
||||
p.dec = (*Buffer).dec_int64
|
||||
p.size = size_int64
|
||||
case reflect.Float32:
|
||||
p.enc = (*Buffer).enc_uint32 // can just treat them as bits
|
||||
p.dec = (*Buffer).dec_int32
|
||||
p.size = size_uint32
|
||||
case reflect.Float64:
|
||||
p.enc = (*Buffer).enc_int64 // can just treat them as bits
|
||||
p.dec = (*Buffer).dec_int64
|
||||
p.size = size_int64
|
||||
case reflect.String:
|
||||
p.enc = (*Buffer).enc_string
|
||||
p.dec = (*Buffer).dec_string
|
||||
p.size = size_string
|
||||
case reflect.Struct:
|
||||
if t1.Elem().Kind() == reflect.Struct {
|
||||
p.stype = t1.Elem()
|
||||
p.isMarshaler = isMarshaler(t1)
|
||||
p.isUnmarshaler = isUnmarshaler(t1)
|
||||
if p.Wire == "bytes" {
|
||||
p.enc = (*Buffer).enc_struct_message
|
||||
p.dec = (*Buffer).dec_struct_message
|
||||
p.size = size_struct_message
|
||||
} else {
|
||||
p.enc = (*Buffer).enc_struct_group
|
||||
p.dec = (*Buffer).dec_struct_group
|
||||
p.size = size_struct_group
|
||||
}
|
||||
}
|
||||
|
||||
case reflect.Slice:
|
||||
switch t2 := t1.Elem(); t2.Kind() {
|
||||
default:
|
||||
logNoSliceEnc(t1, t2)
|
||||
break
|
||||
case reflect.Bool:
|
||||
if p.Packed {
|
||||
p.enc = (*Buffer).enc_slice_packed_bool
|
||||
p.size = size_slice_packed_bool
|
||||
} else {
|
||||
p.enc = (*Buffer).enc_slice_bool
|
||||
p.size = size_slice_bool
|
||||
}
|
||||
p.dec = (*Buffer).dec_slice_bool
|
||||
p.packedDec = (*Buffer).dec_slice_packed_bool
|
||||
case reflect.Int32:
|
||||
if p.Packed {
|
||||
p.enc = (*Buffer).enc_slice_packed_int32
|
||||
p.size = size_slice_packed_int32
|
||||
} else {
|
||||
p.enc = (*Buffer).enc_slice_int32
|
||||
p.size = size_slice_int32
|
||||
}
|
||||
p.dec = (*Buffer).dec_slice_int32
|
||||
p.packedDec = (*Buffer).dec_slice_packed_int32
|
||||
case reflect.Uint32:
|
||||
if p.Packed {
|
||||
p.enc = (*Buffer).enc_slice_packed_uint32
|
||||
p.size = size_slice_packed_uint32
|
||||
} else {
|
||||
p.enc = (*Buffer).enc_slice_uint32
|
||||
p.size = size_slice_uint32
|
||||
}
|
||||
p.dec = (*Buffer).dec_slice_int32
|
||||
p.packedDec = (*Buffer).dec_slice_packed_int32
|
||||
case reflect.Int64, reflect.Uint64:
|
||||
if p.Packed {
|
||||
p.enc = (*Buffer).enc_slice_packed_int64
|
||||
p.size = size_slice_packed_int64
|
||||
} else {
|
||||
p.enc = (*Buffer).enc_slice_int64
|
||||
p.size = size_slice_int64
|
||||
}
|
||||
p.dec = (*Buffer).dec_slice_int64
|
||||
p.packedDec = (*Buffer).dec_slice_packed_int64
|
||||
case reflect.Uint8:
|
||||
p.dec = (*Buffer).dec_slice_byte
|
||||
if p.proto3 {
|
||||
p.enc = (*Buffer).enc_proto3_slice_byte
|
||||
p.size = size_proto3_slice_byte
|
||||
} else {
|
||||
p.enc = (*Buffer).enc_slice_byte
|
||||
p.size = size_slice_byte
|
||||
}
|
||||
case reflect.Float32, reflect.Float64:
|
||||
switch t2.Bits() {
|
||||
case 32:
|
||||
// can just treat them as bits
|
||||
if p.Packed {
|
||||
p.enc = (*Buffer).enc_slice_packed_uint32
|
||||
p.size = size_slice_packed_uint32
|
||||
} else {
|
||||
p.enc = (*Buffer).enc_slice_uint32
|
||||
p.size = size_slice_uint32
|
||||
}
|
||||
p.dec = (*Buffer).dec_slice_int32
|
||||
p.packedDec = (*Buffer).dec_slice_packed_int32
|
||||
case 64:
|
||||
// can just treat them as bits
|
||||
if p.Packed {
|
||||
p.enc = (*Buffer).enc_slice_packed_int64
|
||||
p.size = size_slice_packed_int64
|
||||
} else {
|
||||
p.enc = (*Buffer).enc_slice_int64
|
||||
p.size = size_slice_int64
|
||||
}
|
||||
p.dec = (*Buffer).dec_slice_int64
|
||||
p.packedDec = (*Buffer).dec_slice_packed_int64
|
||||
default:
|
||||
logNoSliceEnc(t1, t2)
|
||||
break
|
||||
}
|
||||
case reflect.String:
|
||||
p.enc = (*Buffer).enc_slice_string
|
||||
p.dec = (*Buffer).dec_slice_string
|
||||
p.size = size_slice_string
|
||||
case reflect.Ptr:
|
||||
switch t3 := t2.Elem(); t3.Kind() {
|
||||
default:
|
||||
fmt.Fprintf(os.Stderr, "proto: no ptr oenc for %T -> %T -> %T\n", t1, t2, t3)
|
||||
break
|
||||
case reflect.Struct:
|
||||
p.stype = t2.Elem()
|
||||
p.isMarshaler = isMarshaler(t2)
|
||||
p.isUnmarshaler = isUnmarshaler(t2)
|
||||
if p.Wire == "bytes" {
|
||||
p.enc = (*Buffer).enc_slice_struct_message
|
||||
p.dec = (*Buffer).dec_slice_struct_message
|
||||
p.size = size_slice_struct_message
|
||||
} else {
|
||||
p.enc = (*Buffer).enc_slice_struct_group
|
||||
p.dec = (*Buffer).dec_slice_struct_group
|
||||
p.size = size_slice_struct_group
|
||||
}
|
||||
}
|
||||
case reflect.Slice:
|
||||
switch t2.Elem().Kind() {
|
||||
default:
|
||||
fmt.Fprintf(os.Stderr, "proto: no slice elem oenc for %T -> %T -> %T\n", t1, t2, t2.Elem())
|
||||
break
|
||||
case reflect.Uint8:
|
||||
p.enc = (*Buffer).enc_slice_slice_byte
|
||||
p.dec = (*Buffer).dec_slice_slice_byte
|
||||
p.size = size_slice_slice_byte
|
||||
}
|
||||
if t2 := t1.Elem(); t2.Kind() == reflect.Ptr && t2.Elem().Kind() == reflect.Struct {
|
||||
p.stype = t2.Elem()
|
||||
}
|
||||
|
||||
case reflect.Map:
|
||||
p.enc = (*Buffer).enc_new_map
|
||||
p.dec = (*Buffer).dec_new_map
|
||||
p.size = size_new_map
|
||||
|
||||
p.mtype = t1
|
||||
p.mkeyprop = &Properties{}
|
||||
p.mkeyprop.init(reflect.PtrTo(p.mtype.Key()), "Key", f.Tag.Get("protobuf_key"), nil, lockGetProp)
|
||||
p.mvalprop = &Properties{}
|
||||
p.MapKeyProp = &Properties{}
|
||||
p.MapKeyProp.init(reflect.PtrTo(p.mtype.Key()), "Key", f.Tag.Get("protobuf_key"), nil, lockGetProp)
|
||||
p.MapValProp = &Properties{}
|
||||
vtype := p.mtype.Elem()
|
||||
if vtype.Kind() != reflect.Ptr && vtype.Kind() != reflect.Slice {
|
||||
// The value type is not a message (*T) or bytes ([]byte),
|
||||
// so we need encoders for the pointer to this type.
|
||||
vtype = reflect.PtrTo(vtype)
|
||||
}
|
||||
p.mvalprop.init(vtype, "Value", f.Tag.Get("protobuf_val"), nil, lockGetProp)
|
||||
p.MapValProp.init(vtype, "Value", f.Tag.Get("protobuf_val"), nil, lockGetProp)
|
||||
}
|
||||
|
||||
// precalculate tag code
|
||||
wire := p.WireType
|
||||
if p.Packed {
|
||||
wire = WireBytes
|
||||
}
|
||||
x := uint32(p.Tag)<<3 | uint32(wire)
|
||||
i := 0
|
||||
for i = 0; x > 127; i++ {
|
||||
p.tagbuf[i] = 0x80 | uint8(x&0x7F)
|
||||
x >>= 7
|
||||
}
|
||||
p.tagbuf[i] = uint8(x)
|
||||
p.tagcode = p.tagbuf[0 : i+1]
|
||||
|
||||
if p.stype != nil {
|
||||
if lockGetProp {
|
||||
p.sprop = GetProperties(p.stype)
|
||||
|
@ -586,32 +297,9 @@ func (p *Properties) setEncAndDec(typ reflect.Type, f *reflect.StructField, lock
|
|||
}
|
||||
|
||||
var (
|
||||
marshalerType = reflect.TypeOf((*Marshaler)(nil)).Elem()
|
||||
unmarshalerType = reflect.TypeOf((*Unmarshaler)(nil)).Elem()
|
||||
marshalerType = reflect.TypeOf((*Marshaler)(nil)).Elem()
|
||||
)
|
||||
|
||||
// isMarshaler reports whether type t implements Marshaler.
|
||||
func isMarshaler(t reflect.Type) bool {
|
||||
// We're checking for (likely) pointer-receiver methods
|
||||
// so if t is not a pointer, something is very wrong.
|
||||
// The calls above only invoke isMarshaler on pointer types.
|
||||
if t.Kind() != reflect.Ptr {
|
||||
panic("proto: misuse of isMarshaler")
|
||||
}
|
||||
return t.Implements(marshalerType)
|
||||
}
|
||||
|
||||
// isUnmarshaler reports whether type t implements Unmarshaler.
|
||||
func isUnmarshaler(t reflect.Type) bool {
|
||||
// We're checking for (likely) pointer-receiver methods
|
||||
// so if t is not a pointer, something is very wrong.
|
||||
// The calls above only invoke isUnmarshaler on pointer types.
|
||||
if t.Kind() != reflect.Ptr {
|
||||
panic("proto: misuse of isUnmarshaler")
|
||||
}
|
||||
return t.Implements(unmarshalerType)
|
||||
}
|
||||
|
||||
// Init populates the properties from a protocol buffer struct tag.
|
||||
func (p *Properties) Init(typ reflect.Type, name, tag string, f *reflect.StructField) {
|
||||
p.init(typ, name, tag, f, true)
|
||||
|
@ -621,14 +309,11 @@ func (p *Properties) init(typ reflect.Type, name, tag string, f *reflect.StructF
|
|||
// "bytes,49,opt,def=hello!"
|
||||
p.Name = name
|
||||
p.OrigName = name
|
||||
if f != nil {
|
||||
p.field = toField(f)
|
||||
}
|
||||
if tag == "" {
|
||||
return
|
||||
}
|
||||
p.Parse(tag)
|
||||
p.setEncAndDec(typ, f, lockGetProp)
|
||||
p.setFieldProps(typ, f, lockGetProp)
|
||||
}
|
||||
|
||||
var (
|
||||
|
@ -678,9 +363,6 @@ func getPropertiesLocked(t reflect.Type) *StructProperties {
|
|||
propertiesMap[t] = prop
|
||||
|
||||
// build properties
|
||||
prop.extendable = reflect.PtrTo(t).Implements(extendableProtoType) ||
|
||||
reflect.PtrTo(t).Implements(extendableProtoV1Type)
|
||||
prop.unrecField = invalidField
|
||||
prop.Prop = make([]*Properties, t.NumField())
|
||||
prop.order = make([]int, t.NumField())
|
||||
|
||||
|
@ -690,17 +372,6 @@ func getPropertiesLocked(t reflect.Type) *StructProperties {
|
|||
name := f.Name
|
||||
p.init(f.Type, name, f.Tag.Get("protobuf"), &f, false)
|
||||
|
||||
if f.Name == "XXX_InternalExtensions" { // special case
|
||||
p.enc = (*Buffer).enc_exts
|
||||
p.dec = nil // not needed
|
||||
p.size = size_exts
|
||||
} else if f.Name == "XXX_extensions" { // special case
|
||||
p.enc = (*Buffer).enc_map
|
||||
p.dec = nil // not needed
|
||||
p.size = size_map
|
||||
} else if f.Name == "XXX_unrecognized" { // special case
|
||||
prop.unrecField = toField(&f)
|
||||
}
|
||||
oneof := f.Tag.Get("protobuf_oneof") // special case
|
||||
if oneof != "" {
|
||||
// Oneof fields don't use the traditional protobuf tag.
|
||||
|
@ -715,9 +386,6 @@ func getPropertiesLocked(t reflect.Type) *StructProperties {
|
|||
}
|
||||
print("\n")
|
||||
}
|
||||
if p.enc == nil && !strings.HasPrefix(f.Name, "XXX_") && oneof == "" {
|
||||
fmt.Fprintln(os.Stderr, "proto: no encoder for", f.Name, f.Type.String(), "[GetProperties]")
|
||||
}
|
||||
}
|
||||
|
||||
// Re-order prop.order.
|
||||
|
@ -728,8 +396,7 @@ func getPropertiesLocked(t reflect.Type) *StructProperties {
|
|||
}
|
||||
if om, ok := reflect.Zero(reflect.PtrTo(t)).Interface().(oneofMessage); ok {
|
||||
var oots []interface{}
|
||||
prop.oneofMarshaler, prop.oneofUnmarshaler, prop.oneofSizer, oots = om.XXX_OneofFuncs()
|
||||
prop.stype = t
|
||||
_, _, _, oots = om.XXX_OneofFuncs()
|
||||
|
||||
// Interpret oneof metadata.
|
||||
prop.OneofTypes = make(map[string]*OneofProperties)
|
||||
|
@ -779,30 +446,6 @@ func getPropertiesLocked(t reflect.Type) *StructProperties {
|
|||
return prop
|
||||
}
|
||||
|
||||
// Return the Properties object for the x[0]'th field of the structure.
|
||||
func propByIndex(t reflect.Type, x []int) *Properties {
|
||||
if len(x) != 1 {
|
||||
fmt.Fprintf(os.Stderr, "proto: field index dimension %d (not 1) for type %s\n", len(x), t)
|
||||
return nil
|
||||
}
|
||||
prop := GetProperties(t)
|
||||
return prop.Prop[x[0]]
|
||||
}
|
||||
|
||||
// Get the address and type of a pointer to a struct from an interface.
|
||||
func getbase(pb Message) (t reflect.Type, b structPointer, err error) {
|
||||
if pb == nil {
|
||||
err = ErrNil
|
||||
return
|
||||
}
|
||||
// get the reflect type of the pointer to the struct.
|
||||
t = reflect.TypeOf(pb)
|
||||
// get the address of the struct.
|
||||
value := reflect.ValueOf(pb)
|
||||
b = toStructPointer(value)
|
||||
return
|
||||
}
|
||||
|
||||
// A global registry of enum types.
|
||||
// The generated code will register the generated maps by calling RegisterEnum.
|
||||
|
||||
|
@ -826,20 +469,42 @@ func EnumValueMap(enumType string) map[string]int32 {
|
|||
// A registry of all linked message types.
|
||||
// The string is a fully-qualified proto name ("pkg.Message").
|
||||
var (
|
||||
protoTypes = make(map[string]reflect.Type)
|
||||
revProtoTypes = make(map[reflect.Type]string)
|
||||
protoTypedNils = make(map[string]Message) // a map from proto names to typed nil pointers
|
||||
protoMapTypes = make(map[string]reflect.Type) // a map from proto names to map types
|
||||
revProtoTypes = make(map[reflect.Type]string)
|
||||
)
|
||||
|
||||
// RegisterType is called from generated code and maps from the fully qualified
|
||||
// proto name to the type (pointer to struct) of the protocol buffer.
|
||||
func RegisterType(x Message, name string) {
|
||||
if _, ok := protoTypes[name]; ok {
|
||||
if _, ok := protoTypedNils[name]; ok {
|
||||
// TODO: Some day, make this a panic.
|
||||
log.Printf("proto: duplicate proto type registered: %s", name)
|
||||
return
|
||||
}
|
||||
t := reflect.TypeOf(x)
|
||||
protoTypes[name] = t
|
||||
if v := reflect.ValueOf(x); v.Kind() == reflect.Ptr && v.Pointer() == 0 {
|
||||
// Generated code always calls RegisterType with nil x.
|
||||
// This check is just for extra safety.
|
||||
protoTypedNils[name] = x
|
||||
} else {
|
||||
protoTypedNils[name] = reflect.Zero(t).Interface().(Message)
|
||||
}
|
||||
revProtoTypes[t] = name
|
||||
}
|
||||
|
||||
// RegisterMapType is called from generated code and maps from the fully qualified
|
||||
// proto name to the native map type of the proto map definition.
|
||||
func RegisterMapType(x interface{}, name string) {
|
||||
if reflect.TypeOf(x).Kind() != reflect.Map {
|
||||
panic(fmt.Sprintf("RegisterMapType(%T, %q); want map", x, name))
|
||||
}
|
||||
if _, ok := protoMapTypes[name]; ok {
|
||||
log.Printf("proto: duplicate proto type registered: %s", name)
|
||||
return
|
||||
}
|
||||
t := reflect.TypeOf(x)
|
||||
protoMapTypes[name] = t
|
||||
revProtoTypes[t] = name
|
||||
}
|
||||
|
||||
|
@ -855,7 +520,14 @@ func MessageName(x Message) string {
|
|||
}
|
||||
|
||||
// MessageType returns the message type (pointer to struct) for a named message.
|
||||
func MessageType(name string) reflect.Type { return protoTypes[name] }
|
||||
// The type is not guaranteed to implement proto.Message if the name refers to a
|
||||
// map entry.
|
||||
func MessageType(name string) reflect.Type {
|
||||
if t, ok := protoTypedNils[name]; ok {
|
||||
return reflect.TypeOf(t)
|
||||
}
|
||||
return protoMapTypes[name]
|
||||
}
|
||||
|
||||
// A registry of all linked proto files.
|
||||
var (
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,654 @@
|
|||
// Go support for Protocol Buffers - Google's data interchange format
|
||||
//
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// https://github.com/golang/protobuf
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package proto
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
// Merge merges the src message into dst.
|
||||
// This assumes that dst and src of the same type and are non-nil.
|
||||
func (a *InternalMessageInfo) Merge(dst, src Message) {
|
||||
mi := atomicLoadMergeInfo(&a.merge)
|
||||
if mi == nil {
|
||||
mi = getMergeInfo(reflect.TypeOf(dst).Elem())
|
||||
atomicStoreMergeInfo(&a.merge, mi)
|
||||
}
|
||||
mi.merge(toPointer(&dst), toPointer(&src))
|
||||
}
|
||||
|
||||
type mergeInfo struct {
|
||||
typ reflect.Type
|
||||
|
||||
initialized int32 // 0: only typ is valid, 1: everything is valid
|
||||
lock sync.Mutex
|
||||
|
||||
fields []mergeFieldInfo
|
||||
unrecognized field // Offset of XXX_unrecognized
|
||||
}
|
||||
|
||||
type mergeFieldInfo struct {
|
||||
field field // Offset of field, guaranteed to be valid
|
||||
|
||||
// isPointer reports whether the value in the field is a pointer.
|
||||
// This is true for the following situations:
|
||||
// * Pointer to struct
|
||||
// * Pointer to basic type (proto2 only)
|
||||
// * Slice (first value in slice header is a pointer)
|
||||
// * String (first value in string header is a pointer)
|
||||
isPointer bool
|
||||
|
||||
// basicWidth reports the width of the field assuming that it is directly
|
||||
// embedded in the struct (as is the case for basic types in proto3).
|
||||
// The possible values are:
|
||||
// 0: invalid
|
||||
// 1: bool
|
||||
// 4: int32, uint32, float32
|
||||
// 8: int64, uint64, float64
|
||||
basicWidth int
|
||||
|
||||
// Where dst and src are pointers to the types being merged.
|
||||
merge func(dst, src pointer)
|
||||
}
|
||||
|
||||
var (
|
||||
mergeInfoMap = map[reflect.Type]*mergeInfo{}
|
||||
mergeInfoLock sync.Mutex
|
||||
)
|
||||
|
||||
func getMergeInfo(t reflect.Type) *mergeInfo {
|
||||
mergeInfoLock.Lock()
|
||||
defer mergeInfoLock.Unlock()
|
||||
mi := mergeInfoMap[t]
|
||||
if mi == nil {
|
||||
mi = &mergeInfo{typ: t}
|
||||
mergeInfoMap[t] = mi
|
||||
}
|
||||
return mi
|
||||
}
|
||||
|
||||
// merge merges src into dst assuming they are both of type *mi.typ.
|
||||
func (mi *mergeInfo) merge(dst, src pointer) {
|
||||
if dst.isNil() {
|
||||
panic("proto: nil destination")
|
||||
}
|
||||
if src.isNil() {
|
||||
return // Nothing to do.
|
||||
}
|
||||
|
||||
if atomic.LoadInt32(&mi.initialized) == 0 {
|
||||
mi.computeMergeInfo()
|
||||
}
|
||||
|
||||
for _, fi := range mi.fields {
|
||||
sfp := src.offset(fi.field)
|
||||
|
||||
// As an optimization, we can avoid the merge function call cost
|
||||
// if we know for sure that the source will have no effect
|
||||
// by checking if it is the zero value.
|
||||
if unsafeAllowed {
|
||||
if fi.isPointer && sfp.getPointer().isNil() { // Could be slice or string
|
||||
continue
|
||||
}
|
||||
if fi.basicWidth > 0 {
|
||||
switch {
|
||||
case fi.basicWidth == 1 && !*sfp.toBool():
|
||||
continue
|
||||
case fi.basicWidth == 4 && *sfp.toUint32() == 0:
|
||||
continue
|
||||
case fi.basicWidth == 8 && *sfp.toUint64() == 0:
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dfp := dst.offset(fi.field)
|
||||
fi.merge(dfp, sfp)
|
||||
}
|
||||
|
||||
// TODO: Make this faster?
|
||||
out := dst.asPointerTo(mi.typ).Elem()
|
||||
in := src.asPointerTo(mi.typ).Elem()
|
||||
if emIn, err := extendable(in.Addr().Interface()); err == nil {
|
||||
emOut, _ := extendable(out.Addr().Interface())
|
||||
mIn, muIn := emIn.extensionsRead()
|
||||
if mIn != nil {
|
||||
mOut := emOut.extensionsWrite()
|
||||
muIn.Lock()
|
||||
mergeExtension(mOut, mIn)
|
||||
muIn.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
if mi.unrecognized.IsValid() {
|
||||
if b := *src.offset(mi.unrecognized).toBytes(); len(b) > 0 {
|
||||
*dst.offset(mi.unrecognized).toBytes() = append([]byte(nil), b...)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (mi *mergeInfo) computeMergeInfo() {
|
||||
mi.lock.Lock()
|
||||
defer mi.lock.Unlock()
|
||||
if mi.initialized != 0 {
|
||||
return
|
||||
}
|
||||
t := mi.typ
|
||||
n := t.NumField()
|
||||
|
||||
props := GetProperties(t)
|
||||
for i := 0; i < n; i++ {
|
||||
f := t.Field(i)
|
||||
if strings.HasPrefix(f.Name, "XXX_") {
|
||||
continue
|
||||
}
|
||||
|
||||
mfi := mergeFieldInfo{field: toField(&f)}
|
||||
tf := f.Type
|
||||
|
||||
// As an optimization, we can avoid the merge function call cost
|
||||
// if we know for sure that the source will have no effect
|
||||
// by checking if it is the zero value.
|
||||
if unsafeAllowed {
|
||||
switch tf.Kind() {
|
||||
case reflect.Ptr, reflect.Slice, reflect.String:
|
||||
// As a special case, we assume slices and strings are pointers
|
||||
// since we know that the first field in the SliceSlice or
|
||||
// StringHeader is a data pointer.
|
||||
mfi.isPointer = true
|
||||
case reflect.Bool:
|
||||
mfi.basicWidth = 1
|
||||
case reflect.Int32, reflect.Uint32, reflect.Float32:
|
||||
mfi.basicWidth = 4
|
||||
case reflect.Int64, reflect.Uint64, reflect.Float64:
|
||||
mfi.basicWidth = 8
|
||||
}
|
||||
}
|
||||
|
||||
// Unwrap tf to get at its most basic type.
|
||||
var isPointer, isSlice bool
|
||||
if tf.Kind() == reflect.Slice && tf.Elem().Kind() != reflect.Uint8 {
|
||||
isSlice = true
|
||||
tf = tf.Elem()
|
||||
}
|
||||
if tf.Kind() == reflect.Ptr {
|
||||
isPointer = true
|
||||
tf = tf.Elem()
|
||||
}
|
||||
if isPointer && isSlice && tf.Kind() != reflect.Struct {
|
||||
panic("both pointer and slice for basic type in " + tf.Name())
|
||||
}
|
||||
|
||||
switch tf.Kind() {
|
||||
case reflect.Int32:
|
||||
switch {
|
||||
case isSlice: // E.g., []int32
|
||||
mfi.merge = func(dst, src pointer) {
|
||||
// NOTE: toInt32Slice is not defined (see pointer_reflect.go).
|
||||
/*
|
||||
sfsp := src.toInt32Slice()
|
||||
if *sfsp != nil {
|
||||
dfsp := dst.toInt32Slice()
|
||||
*dfsp = append(*dfsp, *sfsp...)
|
||||
if *dfsp == nil {
|
||||
*dfsp = []int64{}
|
||||
}
|
||||
}
|
||||
*/
|
||||
sfs := src.getInt32Slice()
|
||||
if sfs != nil {
|
||||
dfs := dst.getInt32Slice()
|
||||
dfs = append(dfs, sfs...)
|
||||
if dfs == nil {
|
||||
dfs = []int32{}
|
||||
}
|
||||
dst.setInt32Slice(dfs)
|
||||
}
|
||||
}
|
||||
case isPointer: // E.g., *int32
|
||||
mfi.merge = func(dst, src pointer) {
|
||||
// NOTE: toInt32Ptr is not defined (see pointer_reflect.go).
|
||||
/*
|
||||
sfpp := src.toInt32Ptr()
|
||||
if *sfpp != nil {
|
||||
dfpp := dst.toInt32Ptr()
|
||||
if *dfpp == nil {
|
||||
*dfpp = Int32(**sfpp)
|
||||
} else {
|
||||
**dfpp = **sfpp
|
||||
}
|
||||
}
|
||||
*/
|
||||
sfp := src.getInt32Ptr()
|
||||
if sfp != nil {
|
||||
dfp := dst.getInt32Ptr()
|
||||
if dfp == nil {
|
||||
dst.setInt32Ptr(*sfp)
|
||||
} else {
|
||||
*dfp = *sfp
|
||||
}
|
||||
}
|
||||
}
|
||||
default: // E.g., int32
|
||||
mfi.merge = func(dst, src pointer) {
|
||||
if v := *src.toInt32(); v != 0 {
|
||||
*dst.toInt32() = v
|
||||
}
|
||||
}
|
||||
}
|
||||
case reflect.Int64:
|
||||
switch {
|
||||
case isSlice: // E.g., []int64
|
||||
mfi.merge = func(dst, src pointer) {
|
||||
sfsp := src.toInt64Slice()
|
||||
if *sfsp != nil {
|
||||
dfsp := dst.toInt64Slice()
|
||||
*dfsp = append(*dfsp, *sfsp...)
|
||||
if *dfsp == nil {
|
||||
*dfsp = []int64{}
|
||||
}
|
||||
}
|
||||
}
|
||||
case isPointer: // E.g., *int64
|
||||
mfi.merge = func(dst, src pointer) {
|
||||
sfpp := src.toInt64Ptr()
|
||||
if *sfpp != nil {
|
||||
dfpp := dst.toInt64Ptr()
|
||||
if *dfpp == nil {
|
||||
*dfpp = Int64(**sfpp)
|
||||
} else {
|
||||
**dfpp = **sfpp
|
||||
}
|
||||
}
|
||||
}
|
||||
default: // E.g., int64
|
||||
mfi.merge = func(dst, src pointer) {
|
||||
if v := *src.toInt64(); v != 0 {
|
||||
*dst.toInt64() = v
|
||||
}
|
||||
}
|
||||
}
|
||||
case reflect.Uint32:
|
||||
switch {
|
||||
case isSlice: // E.g., []uint32
|
||||
mfi.merge = func(dst, src pointer) {
|
||||
sfsp := src.toUint32Slice()
|
||||
if *sfsp != nil {
|
||||
dfsp := dst.toUint32Slice()
|
||||
*dfsp = append(*dfsp, *sfsp...)
|
||||
if *dfsp == nil {
|
||||
*dfsp = []uint32{}
|
||||
}
|
||||
}
|
||||
}
|
||||
case isPointer: // E.g., *uint32
|
||||
mfi.merge = func(dst, src pointer) {
|
||||
sfpp := src.toUint32Ptr()
|
||||
if *sfpp != nil {
|
||||
dfpp := dst.toUint32Ptr()
|
||||
if *dfpp == nil {
|
||||
*dfpp = Uint32(**sfpp)
|
||||
} else {
|
||||
**dfpp = **sfpp
|
||||
}
|
||||
}
|
||||
}
|
||||
default: // E.g., uint32
|
||||
mfi.merge = func(dst, src pointer) {
|
||||
if v := *src.toUint32(); v != 0 {
|
||||
*dst.toUint32() = v
|
||||
}
|
||||
}
|
||||
}
|
||||
case reflect.Uint64:
|
||||
switch {
|
||||
case isSlice: // E.g., []uint64
|
||||
mfi.merge = func(dst, src pointer) {
|
||||
sfsp := src.toUint64Slice()
|
||||
if *sfsp != nil {
|
||||
dfsp := dst.toUint64Slice()
|
||||
*dfsp = append(*dfsp, *sfsp...)
|
||||
if *dfsp == nil {
|
||||
*dfsp = []uint64{}
|
||||
}
|
||||
}
|
||||
}
|
||||
case isPointer: // E.g., *uint64
|
||||
mfi.merge = func(dst, src pointer) {
|
||||
sfpp := src.toUint64Ptr()
|
||||
if *sfpp != nil {
|
||||
dfpp := dst.toUint64Ptr()
|
||||
if *dfpp == nil {
|
||||
*dfpp = Uint64(**sfpp)
|
||||
} else {
|
||||
**dfpp = **sfpp
|
||||
}
|
||||
}
|
||||
}
|
||||
default: // E.g., uint64
|
||||
mfi.merge = func(dst, src pointer) {
|
||||
if v := *src.toUint64(); v != 0 {
|
||||
*dst.toUint64() = v
|
||||
}
|
||||
}
|
||||
}
|
||||
case reflect.Float32:
|
||||
switch {
|
||||
case isSlice: // E.g., []float32
|
||||
mfi.merge = func(dst, src pointer) {
|
||||
sfsp := src.toFloat32Slice()
|
||||
if *sfsp != nil {
|
||||
dfsp := dst.toFloat32Slice()
|
||||
*dfsp = append(*dfsp, *sfsp...)
|
||||
if *dfsp == nil {
|
||||
*dfsp = []float32{}
|
||||
}
|
||||
}
|
||||
}
|
||||
case isPointer: // E.g., *float32
|
||||
mfi.merge = func(dst, src pointer) {
|
||||
sfpp := src.toFloat32Ptr()
|
||||
if *sfpp != nil {
|
||||
dfpp := dst.toFloat32Ptr()
|
||||
if *dfpp == nil {
|
||||
*dfpp = Float32(**sfpp)
|
||||
} else {
|
||||
**dfpp = **sfpp
|
||||
}
|
||||
}
|
||||
}
|
||||
default: // E.g., float32
|
||||
mfi.merge = func(dst, src pointer) {
|
||||
if v := *src.toFloat32(); v != 0 {
|
||||
*dst.toFloat32() = v
|
||||
}
|
||||
}
|
||||
}
|
||||
case reflect.Float64:
|
||||
switch {
|
||||
case isSlice: // E.g., []float64
|
||||
mfi.merge = func(dst, src pointer) {
|
||||
sfsp := src.toFloat64Slice()
|
||||
if *sfsp != nil {
|
||||
dfsp := dst.toFloat64Slice()
|
||||
*dfsp = append(*dfsp, *sfsp...)
|
||||
if *dfsp == nil {
|
||||
*dfsp = []float64{}
|
||||
}
|
||||
}
|
||||
}
|
||||
case isPointer: // E.g., *float64
|
||||
mfi.merge = func(dst, src pointer) {
|
||||
sfpp := src.toFloat64Ptr()
|
||||
if *sfpp != nil {
|
||||
dfpp := dst.toFloat64Ptr()
|
||||
if *dfpp == nil {
|
||||
*dfpp = Float64(**sfpp)
|
||||
} else {
|
||||
**dfpp = **sfpp
|
||||
}
|
||||
}
|
||||
}
|
||||
default: // E.g., float64
|
||||
mfi.merge = func(dst, src pointer) {
|
||||
if v := *src.toFloat64(); v != 0 {
|
||||
*dst.toFloat64() = v
|
||||
}
|
||||
}
|
||||
}
|
||||
case reflect.Bool:
|
||||
switch {
|
||||
case isSlice: // E.g., []bool
|
||||
mfi.merge = func(dst, src pointer) {
|
||||
sfsp := src.toBoolSlice()
|
||||
if *sfsp != nil {
|
||||
dfsp := dst.toBoolSlice()
|
||||
*dfsp = append(*dfsp, *sfsp...)
|
||||
if *dfsp == nil {
|
||||
*dfsp = []bool{}
|
||||
}
|
||||
}
|
||||
}
|
||||
case isPointer: // E.g., *bool
|
||||
mfi.merge = func(dst, src pointer) {
|
||||
sfpp := src.toBoolPtr()
|
||||
if *sfpp != nil {
|
||||
dfpp := dst.toBoolPtr()
|
||||
if *dfpp == nil {
|
||||
*dfpp = Bool(**sfpp)
|
||||
} else {
|
||||
**dfpp = **sfpp
|
||||
}
|
||||
}
|
||||
}
|
||||
default: // E.g., bool
|
||||
mfi.merge = func(dst, src pointer) {
|
||||
if v := *src.toBool(); v {
|
||||
*dst.toBool() = v
|
||||
}
|
||||
}
|
||||
}
|
||||
case reflect.String:
|
||||
switch {
|
||||
case isSlice: // E.g., []string
|
||||
mfi.merge = func(dst, src pointer) {
|
||||
sfsp := src.toStringSlice()
|
||||
if *sfsp != nil {
|
||||
dfsp := dst.toStringSlice()
|
||||
*dfsp = append(*dfsp, *sfsp...)
|
||||
if *dfsp == nil {
|
||||
*dfsp = []string{}
|
||||
}
|
||||
}
|
||||
}
|
||||
case isPointer: // E.g., *string
|
||||
mfi.merge = func(dst, src pointer) {
|
||||
sfpp := src.toStringPtr()
|
||||
if *sfpp != nil {
|
||||
dfpp := dst.toStringPtr()
|
||||
if *dfpp == nil {
|
||||
*dfpp = String(**sfpp)
|
||||
} else {
|
||||
**dfpp = **sfpp
|
||||
}
|
||||
}
|
||||
}
|
||||
default: // E.g., string
|
||||
mfi.merge = func(dst, src pointer) {
|
||||
if v := *src.toString(); v != "" {
|
||||
*dst.toString() = v
|
||||
}
|
||||
}
|
||||
}
|
||||
case reflect.Slice:
|
||||
isProto3 := props.Prop[i].proto3
|
||||
switch {
|
||||
case isPointer:
|
||||
panic("bad pointer in byte slice case in " + tf.Name())
|
||||
case tf.Elem().Kind() != reflect.Uint8:
|
||||
panic("bad element kind in byte slice case in " + tf.Name())
|
||||
case isSlice: // E.g., [][]byte
|
||||
mfi.merge = func(dst, src pointer) {
|
||||
sbsp := src.toBytesSlice()
|
||||
if *sbsp != nil {
|
||||
dbsp := dst.toBytesSlice()
|
||||
for _, sb := range *sbsp {
|
||||
if sb == nil {
|
||||
*dbsp = append(*dbsp, nil)
|
||||
} else {
|
||||
*dbsp = append(*dbsp, append([]byte{}, sb...))
|
||||
}
|
||||
}
|
||||
if *dbsp == nil {
|
||||
*dbsp = [][]byte{}
|
||||
}
|
||||
}
|
||||
}
|
||||
default: // E.g., []byte
|
||||
mfi.merge = func(dst, src pointer) {
|
||||
sbp := src.toBytes()
|
||||
if *sbp != nil {
|
||||
dbp := dst.toBytes()
|
||||
if !isProto3 || len(*sbp) > 0 {
|
||||
*dbp = append([]byte{}, *sbp...)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
case reflect.Struct:
|
||||
switch {
|
||||
case !isPointer:
|
||||
panic(fmt.Sprintf("message field %s without pointer", tf))
|
||||
case isSlice: // E.g., []*pb.T
|
||||
mi := getMergeInfo(tf)
|
||||
mfi.merge = func(dst, src pointer) {
|
||||
sps := src.getPointerSlice()
|
||||
if sps != nil {
|
||||
dps := dst.getPointerSlice()
|
||||
for _, sp := range sps {
|
||||
var dp pointer
|
||||
if !sp.isNil() {
|
||||
dp = valToPointer(reflect.New(tf))
|
||||
mi.merge(dp, sp)
|
||||
}
|
||||
dps = append(dps, dp)
|
||||
}
|
||||
if dps == nil {
|
||||
dps = []pointer{}
|
||||
}
|
||||
dst.setPointerSlice(dps)
|
||||
}
|
||||
}
|
||||
default: // E.g., *pb.T
|
||||
mi := getMergeInfo(tf)
|
||||
mfi.merge = func(dst, src pointer) {
|
||||
sp := src.getPointer()
|
||||
if !sp.isNil() {
|
||||
dp := dst.getPointer()
|
||||
if dp.isNil() {
|
||||
dp = valToPointer(reflect.New(tf))
|
||||
dst.setPointer(dp)
|
||||
}
|
||||
mi.merge(dp, sp)
|
||||
}
|
||||
}
|
||||
}
|
||||
case reflect.Map:
|
||||
switch {
|
||||
case isPointer || isSlice:
|
||||
panic("bad pointer or slice in map case in " + tf.Name())
|
||||
default: // E.g., map[K]V
|
||||
mfi.merge = func(dst, src pointer) {
|
||||
sm := src.asPointerTo(tf).Elem()
|
||||
if sm.Len() == 0 {
|
||||
return
|
||||
}
|
||||
dm := dst.asPointerTo(tf).Elem()
|
||||
if dm.IsNil() {
|
||||
dm.Set(reflect.MakeMap(tf))
|
||||
}
|
||||
|
||||
switch tf.Elem().Kind() {
|
||||
case reflect.Ptr: // Proto struct (e.g., *T)
|
||||
for _, key := range sm.MapKeys() {
|
||||
val := sm.MapIndex(key)
|
||||
val = reflect.ValueOf(Clone(val.Interface().(Message)))
|
||||
dm.SetMapIndex(key, val)
|
||||
}
|
||||
case reflect.Slice: // E.g. Bytes type (e.g., []byte)
|
||||
for _, key := range sm.MapKeys() {
|
||||
val := sm.MapIndex(key)
|
||||
val = reflect.ValueOf(append([]byte{}, val.Bytes()...))
|
||||
dm.SetMapIndex(key, val)
|
||||
}
|
||||
default: // Basic type (e.g., string)
|
||||
for _, key := range sm.MapKeys() {
|
||||
val := sm.MapIndex(key)
|
||||
dm.SetMapIndex(key, val)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
case reflect.Interface:
|
||||
// Must be oneof field.
|
||||
switch {
|
||||
case isPointer || isSlice:
|
||||
panic("bad pointer or slice in interface case in " + tf.Name())
|
||||
default: // E.g., interface{}
|
||||
// TODO: Make this faster?
|
||||
mfi.merge = func(dst, src pointer) {
|
||||
su := src.asPointerTo(tf).Elem()
|
||||
if !su.IsNil() {
|
||||
du := dst.asPointerTo(tf).Elem()
|
||||
typ := su.Elem().Type()
|
||||
if du.IsNil() || du.Elem().Type() != typ {
|
||||
du.Set(reflect.New(typ.Elem())) // Initialize interface if empty
|
||||
}
|
||||
sv := su.Elem().Elem().Field(0)
|
||||
if sv.Kind() == reflect.Ptr && sv.IsNil() {
|
||||
return
|
||||
}
|
||||
dv := du.Elem().Elem().Field(0)
|
||||
if dv.Kind() == reflect.Ptr && dv.IsNil() {
|
||||
dv.Set(reflect.New(sv.Type().Elem())) // Initialize proto message if empty
|
||||
}
|
||||
switch sv.Type().Kind() {
|
||||
case reflect.Ptr: // Proto struct (e.g., *T)
|
||||
Merge(dv.Interface().(Message), sv.Interface().(Message))
|
||||
case reflect.Slice: // E.g. Bytes type (e.g., []byte)
|
||||
dv.Set(reflect.ValueOf(append([]byte{}, sv.Bytes()...)))
|
||||
default: // Basic type (e.g., string)
|
||||
dv.Set(sv)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
default:
|
||||
panic(fmt.Sprintf("merger not found for type:%s", tf))
|
||||
}
|
||||
mi.fields = append(mi.fields, mfi)
|
||||
}
|
||||
|
||||
mi.unrecognized = invalidField
|
||||
if f, ok := t.FieldByName("XXX_unrecognized"); ok {
|
||||
if f.Type != reflect.TypeOf([]byte{}) {
|
||||
panic("expected XXX_unrecognized to be of type []byte")
|
||||
}
|
||||
mi.unrecognized = toField(&f)
|
||||
}
|
||||
|
||||
atomic.StoreInt32(&mi.initialized, 1)
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -50,7 +50,6 @@ import (
|
|||
var (
|
||||
newline = []byte("\n")
|
||||
spaces = []byte(" ")
|
||||
gtNewline = []byte(">\n")
|
||||
endBraceNewline = []byte("}\n")
|
||||
backslashN = []byte{'\\', 'n'}
|
||||
backslashR = []byte{'\\', 'r'}
|
||||
|
@ -170,11 +169,6 @@ func writeName(w *textWriter, props *Properties) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// raw is the interface satisfied by RawMessage.
|
||||
type raw interface {
|
||||
Bytes() []byte
|
||||
}
|
||||
|
||||
func requiresQuotes(u string) bool {
|
||||
// When type URL contains any characters except [0-9A-Za-z./\-]*, it must be quoted.
|
||||
for _, ch := range u {
|
||||
|
@ -269,6 +263,10 @@ func (tm *TextMarshaler) writeStruct(w *textWriter, sv reflect.Value) error {
|
|||
props := sprops.Prop[i]
|
||||
name := st.Field(i).Name
|
||||
|
||||
if name == "XXX_NoUnkeyedLiteral" {
|
||||
continue
|
||||
}
|
||||
|
||||
if strings.HasPrefix(name, "XXX_") {
|
||||
// There are two XXX_ fields:
|
||||
// XXX_unrecognized []byte
|
||||
|
@ -355,7 +353,7 @@ func (tm *TextMarshaler) writeStruct(w *textWriter, sv reflect.Value) error {
|
|||
return err
|
||||
}
|
||||
}
|
||||
if err := tm.writeAny(w, key, props.mkeyprop); err != nil {
|
||||
if err := tm.writeAny(w, key, props.MapKeyProp); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := w.WriteByte('\n'); err != nil {
|
||||
|
@ -372,7 +370,7 @@ func (tm *TextMarshaler) writeStruct(w *textWriter, sv reflect.Value) error {
|
|||
return err
|
||||
}
|
||||
}
|
||||
if err := tm.writeAny(w, val, props.mvalprop); err != nil {
|
||||
if err := tm.writeAny(w, val, props.MapValProp); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := w.WriteByte('\n'); err != nil {
|
||||
|
@ -436,12 +434,6 @@ func (tm *TextMarshaler) writeStruct(w *textWriter, sv reflect.Value) error {
|
|||
return err
|
||||
}
|
||||
}
|
||||
if b, ok := fv.Interface().(raw); ok {
|
||||
if err := writeRaw(w, b.Bytes()); err != nil {
|
||||
return err
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// Enums have a String method, so writeAny will work fine.
|
||||
if err := tm.writeAny(w, fv, props); err != nil {
|
||||
|
@ -455,7 +447,7 @@ func (tm *TextMarshaler) writeStruct(w *textWriter, sv reflect.Value) error {
|
|||
|
||||
// Extensions (the XXX_extensions field).
|
||||
pv := sv.Addr()
|
||||
if _, ok := extendable(pv.Interface()); ok {
|
||||
if _, err := extendable(pv.Interface()); err == nil {
|
||||
if err := tm.writeExtensions(w, pv); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -464,27 +456,6 @@ func (tm *TextMarshaler) writeStruct(w *textWriter, sv reflect.Value) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// writeRaw writes an uninterpreted raw message.
|
||||
func writeRaw(w *textWriter, b []byte) error {
|
||||
if err := w.WriteByte('<'); err != nil {
|
||||
return err
|
||||
}
|
||||
if !w.compact {
|
||||
if err := w.WriteByte('\n'); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
w.indent()
|
||||
if err := writeUnknownStruct(w, b); err != nil {
|
||||
return err
|
||||
}
|
||||
w.unindent()
|
||||
if err := w.WriteByte('>'); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// writeAny writes an arbitrary field.
|
||||
func (tm *TextMarshaler) writeAny(w *textWriter, v reflect.Value, props *Properties) error {
|
||||
v = reflect.Indirect(v)
|
||||
|
@ -535,6 +506,19 @@ func (tm *TextMarshaler) writeAny(w *textWriter, v reflect.Value, props *Propert
|
|||
}
|
||||
}
|
||||
w.indent()
|
||||
if v.CanAddr() {
|
||||
// Calling v.Interface on a struct causes the reflect package to
|
||||
// copy the entire struct. This is racy with the new Marshaler
|
||||
// since we atomically update the XXX_sizecache.
|
||||
//
|
||||
// Thus, we retrieve a pointer to the struct if possible to avoid
|
||||
// a race since v.Interface on the pointer doesn't copy the struct.
|
||||
//
|
||||
// If v is not addressable, then we are not worried about a race
|
||||
// since it implies that the binary Marshaler cannot possibly be
|
||||
// mutating this value.
|
||||
v = v.Addr()
|
||||
}
|
||||
if etm, ok := v.Interface().(encoding.TextMarshaler); ok {
|
||||
text, err := etm.MarshalText()
|
||||
if err != nil {
|
||||
|
@ -543,8 +527,13 @@ func (tm *TextMarshaler) writeAny(w *textWriter, v reflect.Value, props *Propert
|
|||
if _, err = w.Write(text); err != nil {
|
||||
return err
|
||||
}
|
||||
} else if err := tm.writeStruct(w, v); err != nil {
|
||||
return err
|
||||
} else {
|
||||
if v.Kind() == reflect.Ptr {
|
||||
v = v.Elem()
|
||||
}
|
||||
if err := tm.writeStruct(w, v); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
w.unindent()
|
||||
if err := w.WriteByte(ket); err != nil {
|
||||
|
|
|
@ -206,7 +206,6 @@ func (p *textParser) advance() {
|
|||
|
||||
var (
|
||||
errBadUTF8 = errors.New("proto: bad UTF-8")
|
||||
errBadHex = errors.New("proto: bad hexadecimal")
|
||||
)
|
||||
|
||||
func unquoteC(s string, quote rune) (string, error) {
|
||||
|
@ -277,60 +276,47 @@ func unescape(s string) (ch string, tail string, err error) {
|
|||
return "?", s, nil // trigraph workaround
|
||||
case '\'', '"', '\\':
|
||||
return string(r), s, nil
|
||||
case '0', '1', '2', '3', '4', '5', '6', '7', 'x', 'X':
|
||||
case '0', '1', '2', '3', '4', '5', '6', '7':
|
||||
if len(s) < 2 {
|
||||
return "", "", fmt.Errorf(`\%c requires 2 following digits`, r)
|
||||
}
|
||||
base := 8
|
||||
ss := s[:2]
|
||||
ss := string(r) + s[:2]
|
||||
s = s[2:]
|
||||
if r == 'x' || r == 'X' {
|
||||
base = 16
|
||||
} else {
|
||||
ss = string(r) + ss
|
||||
}
|
||||
i, err := strconv.ParseUint(ss, base, 8)
|
||||
i, err := strconv.ParseUint(ss, 8, 8)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
return "", "", fmt.Errorf(`\%s contains non-octal digits`, ss)
|
||||
}
|
||||
return string([]byte{byte(i)}), s, nil
|
||||
case 'u', 'U':
|
||||
n := 4
|
||||
if r == 'U' {
|
||||
case 'x', 'X', 'u', 'U':
|
||||
var n int
|
||||
switch r {
|
||||
case 'x', 'X':
|
||||
n = 2
|
||||
case 'u':
|
||||
n = 4
|
||||
case 'U':
|
||||
n = 8
|
||||
}
|
||||
if len(s) < n {
|
||||
return "", "", fmt.Errorf(`\%c requires %d digits`, r, n)
|
||||
}
|
||||
|
||||
bs := make([]byte, n/2)
|
||||
for i := 0; i < n; i += 2 {
|
||||
a, ok1 := unhex(s[i])
|
||||
b, ok2 := unhex(s[i+1])
|
||||
if !ok1 || !ok2 {
|
||||
return "", "", errBadHex
|
||||
}
|
||||
bs[i/2] = a<<4 | b
|
||||
return "", "", fmt.Errorf(`\%c requires %d following digits`, r, n)
|
||||
}
|
||||
ss := s[:n]
|
||||
s = s[n:]
|
||||
return string(bs), s, nil
|
||||
i, err := strconv.ParseUint(ss, 16, 64)
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf(`\%c%s contains non-hexadecimal digits`, r, ss)
|
||||
}
|
||||
if r == 'x' || r == 'X' {
|
||||
return string([]byte{byte(i)}), s, nil
|
||||
}
|
||||
if i > utf8.MaxRune {
|
||||
return "", "", fmt.Errorf(`\%c%s is not a valid Unicode code point`, r, ss)
|
||||
}
|
||||
return string(i), s, nil
|
||||
}
|
||||
return "", "", fmt.Errorf(`unknown escape \%c`, r)
|
||||
}
|
||||
|
||||
// Adapted from src/pkg/strconv/quote.go.
|
||||
func unhex(b byte) (v byte, ok bool) {
|
||||
switch {
|
||||
case '0' <= b && b <= '9':
|
||||
return b - '0', true
|
||||
case 'a' <= b && b <= 'f':
|
||||
return b - 'a' + 10, true
|
||||
case 'A' <= b && b <= 'F':
|
||||
return b - 'A' + 10, true
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
|
||||
// Back off the parser by one token. Can only be done between calls to next().
|
||||
// It makes the next advance() a no-op.
|
||||
func (p *textParser) back() { p.backed = true }
|
||||
|
@ -644,17 +630,17 @@ func (p *textParser) readStruct(sv reflect.Value, terminator string) error {
|
|||
if err := p.consumeToken(":"); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := p.readAny(key, props.mkeyprop); err != nil {
|
||||
if err := p.readAny(key, props.MapKeyProp); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := p.consumeOptionalSeparator(); err != nil {
|
||||
return err
|
||||
}
|
||||
case "value":
|
||||
if err := p.checkForColon(props.mvalprop, dst.Type().Elem()); err != nil {
|
||||
if err := p.checkForColon(props.MapValProp, dst.Type().Elem()); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := p.readAny(val, props.mvalprop); err != nil {
|
||||
if err := p.readAny(val, props.MapValProp); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := p.consumeOptionalSeparator(); err != nil {
|
||||
|
@ -728,6 +714,9 @@ func (p *textParser) consumeExtName() (string, error) {
|
|||
if tok.err != nil {
|
||||
return "", p.errorf("unrecognized type_url or extension name: %s", tok.err)
|
||||
}
|
||||
if p.done && tok.value != "]" {
|
||||
return "", p.errorf("unclosed type_url or extension name")
|
||||
}
|
||||
}
|
||||
return strings.Join(parts, ""), nil
|
||||
}
|
||||
|
@ -865,7 +854,7 @@ func (p *textParser) readAny(v reflect.Value, props *Properties) error {
|
|||
return p.readStruct(fv, terminator)
|
||||
case reflect.Uint32:
|
||||
if x, err := strconv.ParseUint(tok.value, 0, 32); err == nil {
|
||||
fv.SetUint(x)
|
||||
fv.SetUint(uint64(x))
|
||||
return nil
|
||||
}
|
||||
case reflect.Uint64:
|
||||
|
@ -883,13 +872,9 @@ func (p *textParser) readAny(v reflect.Value, props *Properties) error {
|
|||
// UnmarshalText returns *RequiredNotSetError.
|
||||
func UnmarshalText(s string, pb Message) error {
|
||||
if um, ok := pb.(encoding.TextUnmarshaler); ok {
|
||||
err := um.UnmarshalText([]byte(s))
|
||||
return err
|
||||
return um.UnmarshalText([]byte(s))
|
||||
}
|
||||
pb.Reset()
|
||||
v := reflect.ValueOf(pb)
|
||||
if pe := newTextParser(s).readStruct(v.Elem(), ""); pe != nil {
|
||||
return pe
|
||||
}
|
||||
return nil
|
||||
return newTextParser(s).readStruct(v.Elem(), "")
|
||||
}
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
(The MIT License)
|
||||
|
||||
Copyright (c) 2017 marvin + konsorten GmbH (open-source@konsorten.de)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
40
vendor/github.com/konsorten/go-windows-terminal-sequences/README.md
generated
vendored
Normal file
40
vendor/github.com/konsorten/go-windows-terminal-sequences/README.md
generated
vendored
Normal file
|
@ -0,0 +1,40 @@
|
|||
# Windows Terminal Sequences
|
||||
|
||||
This library allow for enabling Windows terminal color support for Go.
|
||||
|
||||
See [Console Virtual Terminal Sequences](https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences) for details.
|
||||
|
||||
## Usage
|
||||
|
||||
```go
|
||||
import (
|
||||
"syscall"
|
||||
|
||||
sequences "github.com/konsorten/go-windows-terminal-sequences"
|
||||
)
|
||||
|
||||
func main() {
|
||||
sequences.EnableVirtualTerminalProcessing(syscall.Stdout, true)
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Authors
|
||||
|
||||
The tool is sponsored by the [marvin + konsorten GmbH](http://www.konsorten.de).
|
||||
|
||||
We thank all the authors who provided code to this library:
|
||||
|
||||
* Felix Kollmann
|
||||
|
||||
## License
|
||||
|
||||
(The MIT License)
|
||||
|
||||
Copyright (c) 2018 marvin + konsorten GmbH (open-source@konsorten.de)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -0,0 +1 @@
|
|||
module github.com/konsorten/go-windows-terminal-sequences
|
36
vendor/github.com/konsorten/go-windows-terminal-sequences/sequences.go
generated
vendored
Normal file
36
vendor/github.com/konsorten/go-windows-terminal-sequences/sequences.go
generated
vendored
Normal file
|
@ -0,0 +1,36 @@
|
|||
// +build windows
|
||||
|
||||
package sequences
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var (
|
||||
kernel32Dll *syscall.LazyDLL = syscall.NewLazyDLL("Kernel32.dll")
|
||||
setConsoleMode *syscall.LazyProc = kernel32Dll.NewProc("SetConsoleMode")
|
||||
)
|
||||
|
||||
func EnableVirtualTerminalProcessing(stream syscall.Handle, enable bool) error {
|
||||
const ENABLE_VIRTUAL_TERMINAL_PROCESSING uint32 = 0x4
|
||||
|
||||
var mode uint32
|
||||
err := syscall.GetConsoleMode(syscall.Stdout, &mode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if enable {
|
||||
mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING
|
||||
} else {
|
||||
mode &^= ENABLE_VIRTUAL_TERMINAL_PROCESSING
|
||||
}
|
||||
|
||||
ret, _, err := setConsoleMode.Call(uintptr(unsafe.Pointer(stream)), uintptr(mode))
|
||||
if ret == 0 {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -1,6 +1,8 @@
|
|||
package genetlink
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
|
||||
"github.com/mdlayher/netlink"
|
||||
"golang.org/x/net/bpf"
|
||||
)
|
||||
|
@ -77,6 +79,34 @@ func (c *Conn) SetOption(option netlink.ConnOption, enable bool) error {
|
|||
return c.c.SetOption(option, enable)
|
||||
}
|
||||
|
||||
// SetReadBuffer sets the size of the operating system's receive buffer
|
||||
// associated with the Conn.
|
||||
func (c *Conn) SetReadBuffer(bytes int) error {
|
||||
return c.c.SetReadBuffer(bytes)
|
||||
}
|
||||
|
||||
// SetWriteBuffer sets the size of the operating system's transmit buffer
|
||||
// associated with the Conn.
|
||||
func (c *Conn) SetWriteBuffer(bytes int) error {
|
||||
return c.c.SetWriteBuffer(bytes)
|
||||
}
|
||||
|
||||
// SyscallConn returns a raw network connection. This implements the
|
||||
// syscall.Conn interface.
|
||||
//
|
||||
// Only the Control method of the returned syscall.RawConn is currently
|
||||
// implemented.
|
||||
//
|
||||
// SyscallConn is intended for advanced use cases, such as getting and setting
|
||||
// arbitrary socket options using the netlink socket's file descriptor.
|
||||
//
|
||||
// Once invoked, it is the caller's responsibility to ensure that operations
|
||||
// performed using Conn and the syscall.RawConn do not conflict with
|
||||
// each other.
|
||||
func (c *Conn) SyscallConn() (syscall.RawConn, error) {
|
||||
return c.c.SyscallConn()
|
||||
}
|
||||
|
||||
// Send sends a single Message to netlink, wrapping it in a netlink.Message
|
||||
// using the specified generic netlink family and flags. On success, Send
|
||||
// returns a copy of the netlink.Message with all parameters populated, for
|
||||
|
|
|
@ -26,24 +26,22 @@ type Attribute struct {
|
|||
Data []byte
|
||||
}
|
||||
|
||||
// MarshalBinary marshals an Attribute into a byte slice.
|
||||
func (a Attribute) MarshalBinary() ([]byte, error) {
|
||||
// marshal marshals the contents of a into b and returns the number of bytes
|
||||
// written to b, including attribute alignment padding.
|
||||
func (a *Attribute) marshal(b []byte) (int, error) {
|
||||
if int(a.Length) < nlaHeaderLen {
|
||||
return nil, errInvalidAttribute
|
||||
return 0, errInvalidAttribute
|
||||
}
|
||||
|
||||
b := make([]byte, nlaAlign(int(a.Length)))
|
||||
|
||||
nlenc.PutUint16(b[0:2], a.Length)
|
||||
nlenc.PutUint16(b[2:4], a.Type)
|
||||
n := copy(b[nlaHeaderLen:], a.Data)
|
||||
|
||||
copy(b[nlaHeaderLen:], a.Data)
|
||||
|
||||
return b, nil
|
||||
return nlaHeaderLen + nlaAlign(n), nil
|
||||
}
|
||||
|
||||
// UnmarshalBinary unmarshals the contents of a byte slice into an Attribute.
|
||||
func (a *Attribute) UnmarshalBinary(b []byte) error {
|
||||
// unmarshal unmarshals the contents of a byte slice into an Attribute.
|
||||
func (a *Attribute) unmarshal(b []byte) error {
|
||||
if len(b) < nlaHeaderLen {
|
||||
return errInvalidAttribute
|
||||
}
|
||||
|
@ -75,23 +73,27 @@ func (a *Attribute) UnmarshalBinary(b []byte) error {
|
|||
// In most cases, the Length field of each Attribute should be set to 0, so it
|
||||
// can be calculated and populated automatically for each Attribute.
|
||||
func MarshalAttributes(attrs []Attribute) ([]byte, error) {
|
||||
// Count how many bytes we should allocate to store each attribute's contents.
|
||||
var c int
|
||||
for _, a := range attrs {
|
||||
c += nlaAlign(len(a.Data))
|
||||
c += nlaHeaderLen + nlaAlign(len(a.Data))
|
||||
}
|
||||
|
||||
b := make([]byte, 0, c)
|
||||
// Advance through b with idx to place attribute data at the correct offset.
|
||||
var idx int
|
||||
b := make([]byte, c)
|
||||
for _, a := range attrs {
|
||||
// Infer the length of attribute if zero.
|
||||
if a.Length == 0 {
|
||||
a.Length = uint16(nlaHeaderLen + len(a.Data))
|
||||
}
|
||||
|
||||
ab, err := a.MarshalBinary()
|
||||
// Marshal a into b and advance idx to show many bytes are occupied.
|
||||
n, err := a.marshal(b[idx:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
b = append(b, ab...)
|
||||
idx += n
|
||||
}
|
||||
|
||||
return b, nil
|
||||
|
@ -110,7 +112,7 @@ func UnmarshalAttributes(b []byte) ([]Attribute, error) {
|
|||
}
|
||||
|
||||
var a Attribute
|
||||
if err := (&a).UnmarshalBinary(b[i:]); err != nil {
|
||||
if err := (&a).unmarshal(b[i:]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
@ -207,6 +209,14 @@ func (ad *AttributeDecoder) Err() error {
|
|||
return ad.err
|
||||
}
|
||||
|
||||
// Bytes returns the raw bytes of the current Attribute's data.
|
||||
func (ad *AttributeDecoder) Bytes() []byte {
|
||||
src := ad.data()
|
||||
dest := make([]byte, len(src))
|
||||
copy(dest, src)
|
||||
return dest
|
||||
}
|
||||
|
||||
// String returns the string representation of the current Attribute's data.
|
||||
func (ad *AttributeDecoder) String() string {
|
||||
if ad.err != nil {
|
||||
|
@ -296,3 +306,143 @@ func (ad *AttributeDecoder) Do(fn func(b []byte) error) {
|
|||
ad.err = err
|
||||
}
|
||||
}
|
||||
|
||||
// An AttributeEncoder provides a safe way to encode attributes.
|
||||
//
|
||||
// It is recommended to use an AttributeEncoder where possible instead of
|
||||
// calling MarshalAttributes or using package nlenc directly.
|
||||
//
|
||||
// Errors from intermediate encoding steps are returned in the call to
|
||||
// Encode.
|
||||
type AttributeEncoder struct {
|
||||
// ByteOrder defines a specific byte order to use when processing integer
|
||||
// attributes. ByteOrder should be set immediately after creating the
|
||||
// AttributeEncoder: before any attributes are encoded.
|
||||
//
|
||||
// If not set, the native byte order will be used.
|
||||
ByteOrder binary.ByteOrder
|
||||
|
||||
attrs []Attribute
|
||||
err error
|
||||
}
|
||||
|
||||
// NewAttributeEncoder creates an AttributeEncoder that encodes Attributes.
|
||||
func NewAttributeEncoder() *AttributeEncoder {
|
||||
return &AttributeEncoder{
|
||||
ByteOrder: nlenc.NativeEndian(),
|
||||
}
|
||||
}
|
||||
|
||||
// Uint8 encodes uint8 data into an Attribute specified by typ.
|
||||
func (ae *AttributeEncoder) Uint8(typ uint16, v uint8) {
|
||||
if ae.err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
ae.attrs = append(ae.attrs, Attribute{
|
||||
Type: typ,
|
||||
Data: []byte{v},
|
||||
})
|
||||
}
|
||||
|
||||
// Uint16 encodes uint16 data into an Attribute specified by typ.
|
||||
func (ae *AttributeEncoder) Uint16(typ uint16, v uint16) {
|
||||
if ae.err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
b := make([]byte, 2)
|
||||
ae.ByteOrder.PutUint16(b, v)
|
||||
|
||||
ae.attrs = append(ae.attrs, Attribute{
|
||||
Type: typ,
|
||||
Data: b,
|
||||
})
|
||||
}
|
||||
|
||||
// Uint32 encodes uint32 data into an Attribute specified by typ.
|
||||
func (ae *AttributeEncoder) Uint32(typ uint16, v uint32) {
|
||||
if ae.err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
b := make([]byte, 4)
|
||||
ae.ByteOrder.PutUint32(b, v)
|
||||
|
||||
ae.attrs = append(ae.attrs, Attribute{
|
||||
Type: typ,
|
||||
Data: b,
|
||||
})
|
||||
}
|
||||
|
||||
// Uint64 encodes uint64 data into an Attribute specified by typ.
|
||||
func (ae *AttributeEncoder) Uint64(typ uint16, v uint64) {
|
||||
if ae.err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
b := make([]byte, 8)
|
||||
ae.ByteOrder.PutUint64(b, v)
|
||||
|
||||
ae.attrs = append(ae.attrs, Attribute{
|
||||
Type: typ,
|
||||
Data: b,
|
||||
})
|
||||
}
|
||||
|
||||
// String encodes string s as a null-terminated string into an Attribute
|
||||
// specified by typ.
|
||||
func (ae *AttributeEncoder) String(typ uint16, s string) {
|
||||
if ae.err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
ae.attrs = append(ae.attrs, Attribute{
|
||||
Type: typ,
|
||||
Data: nlenc.Bytes(s),
|
||||
})
|
||||
}
|
||||
|
||||
// Bytes embeds raw byte data into an Attribute specified by typ.
|
||||
func (ae *AttributeEncoder) Bytes(typ uint16, b []byte) {
|
||||
if ae.err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
ae.attrs = append(ae.attrs, Attribute{
|
||||
Type: typ,
|
||||
Data: b,
|
||||
})
|
||||
}
|
||||
|
||||
// Do is a general purpose function to encode arbitrary data into an attribute
|
||||
// specified by typ.
|
||||
//
|
||||
// Do is especially helpful in encoding nested attributes, attribute arrays,
|
||||
// or encoding arbitrary types (such as C structures) which don't fit cleanly
|
||||
// into an unsigned integer value.
|
||||
func (ae *AttributeEncoder) Do(typ uint16, fn func() ([]byte, error)) {
|
||||
if ae.err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
b, err := fn()
|
||||
if err != nil {
|
||||
ae.err = err
|
||||
return
|
||||
}
|
||||
|
||||
ae.attrs = append(ae.attrs, Attribute{
|
||||
Type: typ,
|
||||
Data: b,
|
||||
})
|
||||
}
|
||||
|
||||
// Encode returns the encoded bytes representing the attributes.
|
||||
func (ae *AttributeEncoder) Encode() ([]byte, error) {
|
||||
if ae.err != nil {
|
||||
return nil, ae.err
|
||||
}
|
||||
|
||||
return MarshalAttributes(ae.attrs)
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"math/rand"
|
||||
"os"
|
||||
"sync/atomic"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/bpf"
|
||||
|
@ -25,6 +26,8 @@ var (
|
|||
errMulticastGroupsNotSupported = errors.New("multicast groups not supported")
|
||||
errBPFFiltersNotSupported = errors.New("BPF filters not supported")
|
||||
errOptionsNotSupported = errors.New("options not supported")
|
||||
errSetBufferNotSupported = errors.New("setting buffer sizes not supported")
|
||||
errSyscallConnNotSupported = errors.New("syscall.RawConn operation not supported")
|
||||
)
|
||||
|
||||
// A Conn is a connection to netlink. A Conn can be used to send and
|
||||
|
@ -76,7 +79,7 @@ func Dial(family int, config *Config) (*Conn, error) {
|
|||
//
|
||||
// NewConn is primarily useful for tests. Most applications should use
|
||||
// Dial instead.
|
||||
func NewConn(c Socket, pid uint32) *Conn {
|
||||
func NewConn(sock Socket, pid uint32) *Conn {
|
||||
// Seed the sequence number using a random number generator.
|
||||
r := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
seq := r.Uint32()
|
||||
|
@ -88,7 +91,7 @@ func NewConn(c Socket, pid uint32) *Conn {
|
|||
}
|
||||
|
||||
return &Conn{
|
||||
sock: c,
|
||||
sock: sock,
|
||||
seq: &seq,
|
||||
pid: pid,
|
||||
d: d,
|
||||
|
@ -115,8 +118,8 @@ func (c *Conn) Close() error {
|
|||
//
|
||||
// See the documentation of Conn.Send, Conn.Receive, and Validate for details about
|
||||
// each function.
|
||||
func (c *Conn) Execute(m Message) ([]Message, error) {
|
||||
req, err := c.Send(m)
|
||||
func (c *Conn) Execute(message Message) ([]Message, error) {
|
||||
req, err := c.Send(message)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -148,7 +151,8 @@ func (c *Conn) fixMsg(m *Message, ml int) {
|
|||
}
|
||||
|
||||
// SendMessages sends multiple Messages to netlink. The handling of
|
||||
// m.Header.Length, Sequence and PID is the same as when calling Send.
|
||||
// a Header's Length, Sequence and PID fields is the same as when
|
||||
// calling Send.
|
||||
func (c *Conn) SendMessages(messages []Message) ([]Message, error) {
|
||||
for idx, m := range messages {
|
||||
ml := nlmsgLength(len(m.Data))
|
||||
|
@ -178,34 +182,34 @@ func (c *Conn) SendMessages(messages []Message) ([]Message, error) {
|
|||
return messages, nil
|
||||
}
|
||||
|
||||
// Send sends a single Message to netlink. In most cases, m.Header's Length,
|
||||
// Send sends a single Message to netlink. In most cases, a Header's Length,
|
||||
// Sequence, and PID fields should be set to 0, so they can be populated
|
||||
// automatically before the Message is sent. On success, Send returns a copy
|
||||
// of the Message with all parameters populated, for later validation.
|
||||
//
|
||||
// If m.Header.Length is 0, it will be automatically populated using the
|
||||
// If Header.Length is 0, it will be automatically populated using the
|
||||
// correct length for the Message, including its payload.
|
||||
//
|
||||
// If m.Header.Sequence is 0, it will be automatically populated using the
|
||||
// If Header.Sequence is 0, it will be automatically populated using the
|
||||
// next sequence number for this connection.
|
||||
//
|
||||
// If m.Header.PID is 0, it will be automatically populated using a PID
|
||||
// If Header.PID is 0, it will be automatically populated using a PID
|
||||
// assigned by netlink.
|
||||
func (c *Conn) Send(m Message) (Message, error) {
|
||||
ml := nlmsgLength(len(m.Data))
|
||||
func (c *Conn) Send(message Message) (Message, error) {
|
||||
ml := nlmsgLength(len(message.Data))
|
||||
|
||||
// TODO(mdlayher): fine-tune this limit.
|
||||
if ml > (1024 * 32) {
|
||||
return Message{}, errors.New("netlink message data too large")
|
||||
}
|
||||
|
||||
c.fixMsg(&m, ml)
|
||||
c.fixMsg(&message, ml)
|
||||
|
||||
c.debug(func(d *debugger) {
|
||||
d.debugf(1, "send: %+v", m)
|
||||
d.debugf(1, "send: %+v", message)
|
||||
})
|
||||
|
||||
if err := c.sock.Send(m); err != nil {
|
||||
if err := c.sock.Send(message); err != nil {
|
||||
c.debug(func(d *debugger) {
|
||||
d.debugf(1, "send: err: %v", err)
|
||||
})
|
||||
|
@ -213,7 +217,7 @@ func (c *Conn) Send(m Message) (Message, error) {
|
|||
return Message{}, err
|
||||
}
|
||||
|
||||
return m, nil
|
||||
return message, nil
|
||||
}
|
||||
|
||||
// Receive receives one or more messages from netlink. Multi-part messages are
|
||||
|
@ -419,6 +423,80 @@ func (c *Conn) SetOption(option ConnOption, enable bool) error {
|
|||
return fc.SetOption(option, enable)
|
||||
}
|
||||
|
||||
// A bufferSetter is a Socket that supports setting connection buffer sizes.
|
||||
type bufferSetter interface {
|
||||
Socket
|
||||
SetReadBuffer(bytes int) error
|
||||
SetWriteBuffer(bytes int) error
|
||||
}
|
||||
|
||||
// SetReadBuffer sets the size of the operating system's receive buffer
|
||||
// associated with the Conn.
|
||||
func (c *Conn) SetReadBuffer(bytes int) error {
|
||||
conn, ok := c.sock.(bufferSetter)
|
||||
if !ok {
|
||||
return errSetBufferNotSupported
|
||||
}
|
||||
|
||||
return conn.SetReadBuffer(bytes)
|
||||
}
|
||||
|
||||
// SetWriteBuffer sets the size of the operating system's transmit buffer
|
||||
// associated with the Conn.
|
||||
func (c *Conn) SetWriteBuffer(bytes int) error {
|
||||
conn, ok := c.sock.(bufferSetter)
|
||||
if !ok {
|
||||
return errSetBufferNotSupported
|
||||
}
|
||||
|
||||
return conn.SetWriteBuffer(bytes)
|
||||
}
|
||||
|
||||
var _ syscall.Conn = &Conn{}
|
||||
|
||||
// TODO(mdlayher): mutex or similar to enforce syscall.RawConn contract of
|
||||
// FD remaining valid for duration of calls?
|
||||
|
||||
// SyscallConn returns a raw network connection. This implements the
|
||||
// syscall.Conn interface.
|
||||
//
|
||||
// Only the Control method of the returned syscall.RawConn is currently
|
||||
// implemented.
|
||||
//
|
||||
// SyscallConn is intended for advanced use cases, such as getting and setting
|
||||
// arbitrary socket options using the netlink socket's file descriptor.
|
||||
//
|
||||
// Once invoked, it is the caller's responsibility to ensure that operations
|
||||
// performed using Conn and the syscall.RawConn do not conflict with
|
||||
// each other.
|
||||
func (c *Conn) SyscallConn() (syscall.RawConn, error) {
|
||||
conn, ok := c.sock.(fder)
|
||||
if !ok {
|
||||
return nil, errSyscallConnNotSupported
|
||||
}
|
||||
|
||||
return &rawConn{
|
||||
fd: uintptr(conn.FD()),
|
||||
}, nil
|
||||
}
|
||||
|
||||
var _ syscall.RawConn = &rawConn{}
|
||||
|
||||
// A rawConn is a syscall.RawConn.
|
||||
type rawConn struct {
|
||||
fd uintptr
|
||||
}
|
||||
|
||||
func (rc *rawConn) Control(f func(fd uintptr)) error {
|
||||
f(rc.fd)
|
||||
return nil
|
||||
}
|
||||
|
||||
// TODO(mdlayher): implement Read and Write?
|
||||
|
||||
func (rc *rawConn) Read(_ func(fd uintptr) (done bool)) error { return errSyscallConnNotSupported }
|
||||
func (rc *rawConn) Write(_ func(fd uintptr) (done bool)) error { return errSyscallConnNotSupported }
|
||||
|
||||
// nextSequence atomically increments Conn's sequence number and returns
|
||||
// the incremented value.
|
||||
func (c *Conn) nextSequence() uint32 {
|
||||
|
@ -455,13 +533,7 @@ type Config struct {
|
|||
// no multicast group subscriptions will be made.
|
||||
Groups uint32
|
||||
|
||||
// Experimental: do not lock the internal system call handling goroutine
|
||||
// to its OS thread. This may result in a speed-up of system call handling,
|
||||
// but may cause unexpected behavior when sending and receiving a large number
|
||||
// of messages.
|
||||
//
|
||||
// This should almost certainly be set to false, but if you come up with a
|
||||
// valid reason for using this, please file an issue at
|
||||
// https://github.com/mdlayher/netlink to discuss your thoughts.
|
||||
NoLockThread bool
|
||||
// Network namespace the Conn needs to operate in. If set to 0,
|
||||
// no network namespace will be entered.
|
||||
NetNS int
|
||||
}
|
||||
|
|
|
@ -50,8 +50,10 @@ func dial(family int, config *Config) (*conn, uint32, error) {
|
|||
config = &Config{}
|
||||
}
|
||||
|
||||
lockThread := !config.NoLockThread
|
||||
sock := newSysSocket(lockThread)
|
||||
sock, err := newSysSocket(config)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
if err := sock.Socket(family); err != nil {
|
||||
return nil, 0, err
|
||||
|
@ -260,6 +262,32 @@ func (c *conn) SetOption(option ConnOption, enable bool) error {
|
|||
)
|
||||
}
|
||||
|
||||
// SetReadBuffer sets the size of the operating system's receive buffer
|
||||
// associated with the Conn.
|
||||
func (c *conn) SetReadBuffer(bytes int) error {
|
||||
v := uint32(bytes)
|
||||
|
||||
return c.s.SetSockopt(
|
||||
unix.SOL_SOCKET,
|
||||
unix.SO_RCVBUF,
|
||||
unsafe.Pointer(&v),
|
||||
uint32(unsafe.Sizeof(v)),
|
||||
)
|
||||
}
|
||||
|
||||
// SetReadBuffer sets the size of the operating system's transmit buffer
|
||||
// associated with the Conn.
|
||||
func (c *conn) SetWriteBuffer(bytes int) error {
|
||||
v := uint32(bytes)
|
||||
|
||||
return c.s.SetSockopt(
|
||||
unix.SOL_SOCKET,
|
||||
unix.SO_SNDBUF,
|
||||
unsafe.Pointer(&v),
|
||||
uint32(unsafe.Sizeof(v)),
|
||||
)
|
||||
}
|
||||
|
||||
// linuxOption converts a ConnOption to its Linux value.
|
||||
func linuxOption(o ConnOption) (int, bool) {
|
||||
switch o {
|
||||
|
@ -299,11 +327,16 @@ type sysSocket struct {
|
|||
|
||||
wg *sync.WaitGroup
|
||||
funcC chan<- func()
|
||||
|
||||
mu sync.RWMutex
|
||||
|
||||
done bool
|
||||
doneC chan<- bool
|
||||
}
|
||||
|
||||
// newSysSocket creates a sysSocket that optionally locks its internal goroutine
|
||||
// to a single thread.
|
||||
func newSysSocket(lockThread bool) *sysSocket {
|
||||
func newSysSocket(config *Config) (*sysSocket, error) {
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(1)
|
||||
|
||||
|
@ -312,52 +345,98 @@ func newSysSocket(lockThread bool) *sysSocket {
|
|||
// Gophers Slack for providing this useful link.
|
||||
|
||||
funcC := make(chan func())
|
||||
doneC := make(chan bool)
|
||||
errC := make(chan error)
|
||||
|
||||
go func() {
|
||||
// It is important to lock this goroutine to its OS thread for the duration
|
||||
// of the netlink socket being used, or else the kernel may end up routing
|
||||
// messages to the wrong places.
|
||||
// See: http://lists.infradead.org/pipermail/libnl/2017-February/002293.html.
|
||||
//
|
||||
// But since this is very experimental, we'll leave it as a configurable at
|
||||
// this point.
|
||||
if lockThread {
|
||||
// The intent is to never unlock the OS thread, so that the thread
|
||||
// will terminate when the goroutine exits starting in Go 1.10:
|
||||
// https://go-review.googlesource.com/c/go/+/46038.
|
||||
//
|
||||
// However, due to recent instability and a potential bad interaction
|
||||
// with the Go runtime for threads which are not unlocked, we have
|
||||
// elected to temporarily unlock the thread:
|
||||
// https://github.com/golang/go/issues/25128#issuecomment-410764489.
|
||||
//
|
||||
// If we ever allow a Conn to set its own network namespace, we must
|
||||
// either ensure that the namespace is restored on exit here or that
|
||||
// the thread is properly terminated at some point in the future.
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
}
|
||||
// The intent is to never unlock the OS thread, so that the thread
|
||||
// will terminate when the goroutine exits starting in Go 1.10:
|
||||
// https://go-review.googlesource.com/c/go/+/46038.
|
||||
//
|
||||
// However, due to recent instability and a potential bad interaction
|
||||
// with the Go runtime for threads which are not unlocked, we have
|
||||
// elected to temporarily unlock the thread when the goroutine terminates:
|
||||
// https://github.com/golang/go/issues/25128#issuecomment-410764489.
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
defer wg.Done()
|
||||
|
||||
for f := range funcC {
|
||||
f()
|
||||
// The user requested the Conn to operate in a non-default network namespace.
|
||||
if config.NetNS != 0 {
|
||||
|
||||
// Get the current namespace of the thread the goroutine is locked to.
|
||||
origNetNS, err := getThreadNetNS()
|
||||
if err != nil {
|
||||
errC <- err
|
||||
return
|
||||
}
|
||||
|
||||
// Set the network namespace of the current thread using
|
||||
// the file descriptor provided by the user.
|
||||
err = setThreadNetNS(config.NetNS)
|
||||
if err != nil {
|
||||
errC <- err
|
||||
return
|
||||
}
|
||||
|
||||
// Once the thread's namespace has been successfully manipulated,
|
||||
// make sure we change it back when the goroutine returns.
|
||||
defer setThreadNetNS(origNetNS)
|
||||
}
|
||||
|
||||
// Signal to caller that initialization was successful.
|
||||
errC <- nil
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-doneC:
|
||||
return
|
||||
case f := <-funcC:
|
||||
f()
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
// Wait for the goroutine to return err or nil.
|
||||
if err := <-errC; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &sysSocket{
|
||||
wg: &wg,
|
||||
funcC: funcC,
|
||||
}
|
||||
doneC: doneC,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// do runs f in a worker goroutine which can be locked to one thread.
|
||||
func (s *sysSocket) do(f func()) {
|
||||
func (s *sysSocket) do(f func()) error {
|
||||
done := make(chan bool, 1)
|
||||
|
||||
// All operations handled by this function are assumed to only
|
||||
// read from s.done.
|
||||
s.mu.RLock()
|
||||
|
||||
if s.done {
|
||||
s.mu.RUnlock()
|
||||
return syscall.EBADF
|
||||
}
|
||||
|
||||
s.funcC <- func() {
|
||||
f()
|
||||
done <- true
|
||||
}
|
||||
<-done
|
||||
|
||||
s.mu.RUnlock()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *sysSocket) Socket(family int) error {
|
||||
|
@ -366,13 +445,16 @@ func (s *sysSocket) Socket(family int) error {
|
|||
err error
|
||||
)
|
||||
|
||||
s.do(func() {
|
||||
doErr := s.do(func() {
|
||||
fd, err = unix.Socket(
|
||||
unix.AF_NETLINK,
|
||||
unix.SOCK_RAW,
|
||||
family,
|
||||
)
|
||||
})
|
||||
if doErr != nil {
|
||||
return doErr
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -383,21 +465,35 @@ func (s *sysSocket) Socket(family int) error {
|
|||
|
||||
func (s *sysSocket) Bind(sa unix.Sockaddr) error {
|
||||
var err error
|
||||
s.do(func() {
|
||||
doErr := s.do(func() {
|
||||
err = unix.Bind(s.fd, sa)
|
||||
})
|
||||
if doErr != nil {
|
||||
return doErr
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *sysSocket) Close() error {
|
||||
var err error
|
||||
s.do(func() {
|
||||
err = unix.Close(s.fd)
|
||||
})
|
||||
|
||||
close(s.funcC)
|
||||
// Be sure to acquire a write lock because we need to stop any other
|
||||
// goroutines from sending system call requests after close.
|
||||
// Any invocation of do() after this write lock unlocks is guaranteed
|
||||
// to find s.done being true.
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
// Close the socket from the main thread, this operation has no risk
|
||||
// of routing data to the wrong socket.
|
||||
err := unix.Close(s.fd)
|
||||
s.done = true
|
||||
|
||||
// Signal the syscall worker to exit, wait for the WaitGroup to join,
|
||||
// and close the job channel only when the worker is guaranteed to have stopped.
|
||||
close(s.doneC)
|
||||
s.wg.Wait()
|
||||
close(s.funcC)
|
||||
|
||||
return err
|
||||
}
|
||||
|
@ -410,12 +506,16 @@ func (s *sysSocket) Getsockname() (unix.Sockaddr, error) {
|
|||
err error
|
||||
)
|
||||
|
||||
s.do(func() {
|
||||
doErr := s.do(func() {
|
||||
sa, err = unix.Getsockname(s.fd)
|
||||
})
|
||||
if doErr != nil {
|
||||
return nil, doErr
|
||||
}
|
||||
|
||||
return sa, err
|
||||
}
|
||||
|
||||
func (s *sysSocket) Recvmsg(p, oob []byte, flags int) (int, int, int, unix.Sockaddr, error) {
|
||||
var (
|
||||
n, oobn, recvflags int
|
||||
|
@ -423,27 +523,36 @@ func (s *sysSocket) Recvmsg(p, oob []byte, flags int) (int, int, int, unix.Socka
|
|||
err error
|
||||
)
|
||||
|
||||
s.do(func() {
|
||||
doErr := s.do(func() {
|
||||
n, oobn, recvflags, from, err = unix.Recvmsg(s.fd, p, oob, flags)
|
||||
})
|
||||
if doErr != nil {
|
||||
return 0, 0, 0, nil, doErr
|
||||
}
|
||||
|
||||
return n, oobn, recvflags, from, err
|
||||
}
|
||||
|
||||
func (s *sysSocket) Sendmsg(p, oob []byte, to unix.Sockaddr, flags int) error {
|
||||
var err error
|
||||
s.do(func() {
|
||||
doErr := s.do(func() {
|
||||
err = unix.Sendmsg(s.fd, p, oob, to, flags)
|
||||
})
|
||||
if doErr != nil {
|
||||
return doErr
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *sysSocket) SetSockopt(level, name int, v unsafe.Pointer, l uint32) error {
|
||||
var err error
|
||||
s.do(func() {
|
||||
doErr := s.do(func() {
|
||||
err = setsockopt(s.fd, level, name, v, l)
|
||||
})
|
||||
if doErr != nil {
|
||||
return doErr
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -233,17 +233,16 @@ func (m *Message) UnmarshalBinary(b []byte) error {
|
|||
func checkMessage(m Message) error {
|
||||
const success = 0
|
||||
|
||||
// Both "done" and "error" can contain error codes.
|
||||
isDone := m.Header.Type == HeaderTypeDone
|
||||
isError := m.Header.Type == HeaderTypeError
|
||||
|
||||
switch {
|
||||
// "done" with no data means success.
|
||||
case isDone && len(m.Data) == 0:
|
||||
return nil
|
||||
case isError, isDone:
|
||||
break
|
||||
default:
|
||||
// Per libnl documentation, only messages that indicate type error can
|
||||
// contain error codes:
|
||||
// https://www.infradead.org/~tgr/libnl/doc/core.html#core_errmsg.
|
||||
//
|
||||
// However, at one point, this package checked both done and error for
|
||||
// error codes. Because there was no issue associated with the change,
|
||||
// it is unknown whether this change was correct or not. If you run into
|
||||
// a problem with your application because of this change, please file
|
||||
// an issue.
|
||||
if m.Header.Type != HeaderTypeError {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
//+build linux
|
||||
|
||||
package netlink
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// getThreadNetNS gets the network namespace file descriptor of the thread the current goroutine
|
||||
// is running on. Make sure to call runtime.LockOSThread() before this so the goroutine does not
|
||||
// get scheduled on another thread in the meantime.
|
||||
func getThreadNetNS() (int, error) {
|
||||
file, err := os.Open(fmt.Sprintf("/proc/%d/task/%d/ns/net", unix.Getpid(), unix.Gettid()))
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
return int(file.Fd()), nil
|
||||
}
|
||||
|
||||
// setThreadNetNS sets the network namespace of the thread of the current goroutine to
|
||||
// the namespace described by the user-provided file descriptor.
|
||||
func setThreadNetNS(fd int) error {
|
||||
return unix.Setns(fd, unix.CLONE_NEWNET)
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
/fixtures/
|
|
@ -1,15 +0,0 @@
|
|||
sudo: false
|
||||
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.7.x
|
||||
- 1.8.x
|
||||
- 1.9.x
|
||||
- 1.10.x
|
||||
- 1.x
|
||||
|
||||
go_import_path: github.com/prometheus/procfs
|
||||
|
||||
script:
|
||||
- make style check_license vet test staticcheck
|
|
@ -1,114 +0,0 @@
|
|||
// Copyright 2017 The Prometheus Authors
|
||||
// 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 bcache
|
||||
|
||||
import (
|
||||
"math"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDehumanizeTests(t *testing.T) {
|
||||
dehumanizeTests := []struct {
|
||||
in []byte
|
||||
out uint64
|
||||
invalid bool
|
||||
}{
|
||||
{
|
||||
in: []byte("542k"),
|
||||
out: 555008,
|
||||
},
|
||||
{
|
||||
in: []byte("322M"),
|
||||
out: 337641472,
|
||||
},
|
||||
{
|
||||
in: []byte("1.1k"),
|
||||
out: 1124,
|
||||
},
|
||||
{
|
||||
in: []byte("1.9k"),
|
||||
out: 1924,
|
||||
},
|
||||
{
|
||||
in: []byte("1.10k"),
|
||||
out: 2024,
|
||||
},
|
||||
{
|
||||
in: []byte(""),
|
||||
out: 0,
|
||||
invalid: true,
|
||||
},
|
||||
}
|
||||
for _, tst := range dehumanizeTests {
|
||||
got, err := dehumanize(tst.in)
|
||||
if tst.invalid && err == nil {
|
||||
t.Error("expected an error, but none occurred")
|
||||
}
|
||||
if !tst.invalid && err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
if got != tst.out {
|
||||
t.Errorf("dehumanize: '%s', want %d, got %d", tst.in, tst.out, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParsePseudoFloatTests(t *testing.T) {
|
||||
parsePseudoFloatTests := []struct {
|
||||
in string
|
||||
out float64
|
||||
}{
|
||||
{
|
||||
in: "1.1",
|
||||
out: float64(1.097656),
|
||||
},
|
||||
{
|
||||
in: "1.9",
|
||||
out: float64(1.878906),
|
||||
},
|
||||
{
|
||||
in: "1.10",
|
||||
out: float64(1.976562),
|
||||
},
|
||||
}
|
||||
for _, tst := range parsePseudoFloatTests {
|
||||
got, err := parsePseudoFloat(tst.in)
|
||||
if err != nil || math.Abs(got-tst.out) > 0.0001 {
|
||||
t.Errorf("parsePseudoFloat: %s, want %f, got %f", tst.in, tst.out, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPriorityStats(t *testing.T) {
|
||||
var want = PriorityStats{
|
||||
UnusedPercent: 99,
|
||||
MetadataPercent: 5,
|
||||
}
|
||||
var (
|
||||
in string
|
||||
gotErr error
|
||||
got PriorityStats
|
||||
)
|
||||
in = "Metadata: 5%"
|
||||
gotErr = parsePriorityStats(in, &got)
|
||||
if gotErr != nil || got.MetadataPercent != want.MetadataPercent {
|
||||
t.Errorf("parsePriorityStats: '%s', want %d, got %d", in, want.MetadataPercent, got.MetadataPercent)
|
||||
}
|
||||
|
||||
in = "Unused: 99%"
|
||||
gotErr = parsePriorityStats(in, &got)
|
||||
if gotErr != nil || got.UnusedPercent != want.UnusedPercent {
|
||||
t.Errorf("parsePriorityStats: '%s', want %d, got %d", in, want.UnusedPercent, got.UnusedPercent)
|
||||
}
|
||||
}
|
|
@ -1,64 +0,0 @@
|
|||
// Copyright 2017 The Prometheus Authors
|
||||
// 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 procfs
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestBuddyInfo(t *testing.T) {
|
||||
buddyInfo, err := FS("fixtures/buddyinfo/valid").NewBuddyInfo()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if want, got := "DMA", buddyInfo[0].Zone; want != got {
|
||||
t.Errorf("want Node 0, Zone %s, got %s", want, got)
|
||||
}
|
||||
|
||||
if want, got := "Normal", buddyInfo[2].Zone; want != got {
|
||||
t.Errorf("want Node 0, Zone %s, got %s", want, got)
|
||||
}
|
||||
|
||||
if want, got := 4381.0, buddyInfo[2].Sizes[0]; want != got {
|
||||
t.Errorf("want Node 0, Zone Normal %f, got %f", want, got)
|
||||
}
|
||||
|
||||
if want, got := 572.0, buddyInfo[1].Sizes[1]; want != got {
|
||||
t.Errorf("want Node 0, Zone DMA32 %f, got %f", want, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuddyInfoShort(t *testing.T) {
|
||||
_, err := FS("fixtures/buddyinfo/short").NewBuddyInfo()
|
||||
if err == nil {
|
||||
t.Errorf("expected error, but none occurred")
|
||||
}
|
||||
|
||||
if want, got := "invalid number of fields when parsing buddyinfo", err.Error(); want != got {
|
||||
t.Errorf("wrong error returned, wanted %q, got %q", want, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuddyInfoSizeMismatch(t *testing.T) {
|
||||
_, err := FS("fixtures/buddyinfo/sizemismatch").NewBuddyInfo()
|
||||
if err == nil {
|
||||
t.Errorf("expected error, but none occurred")
|
||||
}
|
||||
|
||||
if want, got := "mismatch in number of buddyinfo buckets", err.Error(); !strings.HasPrefix(got, want) {
|
||||
t.Errorf("wrong error returned, wanted prefix %q, got %q", want, got)
|
||||
}
|
||||
}
|
|
@ -15,6 +15,9 @@ Lines: 1
|
|||
vim
|
||||
Mode: 644
|
||||
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Path: fixtures/26231/cwd
|
||||
SymlinkTo: /usr/bin
|
||||
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Path: fixtures/26231/exe
|
||||
SymlinkTo: /usr/bin/vim
|
||||
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -111,6 +114,9 @@ SymlinkTo: mnt:[4026531840]
|
|||
Path: fixtures/26231/ns/net
|
||||
SymlinkTo: net:[4026531993]
|
||||
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Path: fixtures/26231/root
|
||||
SymlinkTo: /
|
||||
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Path: fixtures/26231/stat
|
||||
Lines: 1
|
||||
26231 (vim) R 5392 7446 5392 34835 7446 4218880 32533 309516 26 82 1677 44 158 99 20 0 1 0 82375 56274944 1981 18446744073709551615 4194304 6294284 140736914091744 140736914087944 139965136429984 0 0 12288 1870679807 0 0 0 17 0 0 0 31 0 0 8391624 8481048 16420864 140736914093252 140736914093279 140736914093279 140736914096107 0
|
||||
|
@ -128,6 +134,9 @@ Lines: 1
|
|||
ata_sff
|
||||
Mode: 644
|
||||
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Path: fixtures/26232/cwd
|
||||
SymlinkTo: /does/not/exist
|
||||
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Directory: fixtures/26232/fd
|
||||
Mode: 755
|
||||
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -167,6 +176,9 @@ Max realtime priority 0 0
|
|||
Max realtime timeout unlimited unlimited us
|
||||
Mode: 644
|
||||
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Path: fixtures/26232/root
|
||||
SymlinkTo: /does/not/exist
|
||||
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Path: fixtures/26232/stat
|
||||
Lines: 1
|
||||
33 (ata_sff) S 2 0 0 0 -1 69238880 0 0 0 0 0 0 0 0 0 -20 1 0 5 0 0 18446744073709551615 0 0 0 0 0 0 0 2147483647 0 18446744073709551615 0 0 17 1 0 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
|
@ -444,3 +456,7 @@ Path: fixtures/symlinktargets/xyz
|
|||
Lines: 0
|
||||
Mode: 644
|
||||
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Path: fixtures/.unpacked
|
||||
Lines: 0
|
||||
Mode: 664
|
||||
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
|
|
@ -1,39 +0,0 @@
|
|||
// Copyright 2018 The Prometheus Authors
|
||||
// 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 procfs
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestNewFS(t *testing.T) {
|
||||
if _, err := NewFS("foobar"); err == nil {
|
||||
t.Error("want NewFS to fail for non-existing mount point")
|
||||
}
|
||||
|
||||
if _, err := NewFS("procfs.go"); err == nil {
|
||||
t.Error("want NewFS to fail if mount point is not a directory")
|
||||
}
|
||||
}
|
||||
|
||||
func TestFSXFSStats(t *testing.T) {
|
||||
stats, err := FS("fixtures").XFSStats()
|
||||
if err != nil {
|
||||
t.Fatalf("failed to parse XFS stats: %v", err)
|
||||
}
|
||||
|
||||
// Very lightweight test just to sanity check the path used
|
||||
// to open XFS stats. Heavier tests in package xfs.
|
||||
if want, got := uint32(92447), stats.ExtentAllocation.ExtentsAllocated; want != got {
|
||||
t.Errorf("unexpected extents allocated:\nwant: %d\nhave: %d", want, got)
|
||||
}
|
||||
}
|
|
@ -13,7 +13,11 @@
|
|||
|
||||
package util
|
||||
|
||||
import "strconv"
|
||||
import (
|
||||
"io/ioutil"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ParseUint32s parses a slice of strings into a slice of uint32s.
|
||||
func ParseUint32s(ss []string) ([]uint32, error) {
|
||||
|
@ -44,3 +48,12 @@ func ParseUint64s(ss []string) ([]uint64, error) {
|
|||
|
||||
return us, nil
|
||||
}
|
||||
|
||||
// ReadUintFromFile reads a file and attempts to parse a uint64 from it.
|
||||
func ReadUintFromFile(path string) (uint64, error) {
|
||||
data, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return strconv.ParseUint(strings.TrimSpace(string(data)), 10, 64)
|
||||
}
|
||||
|
|
45
vendor/github.com/prometheus/procfs/internal/util/sysreadfile_linux.go
generated
vendored
Normal file
45
vendor/github.com/prometheus/procfs/internal/util/sysreadfile_linux.go
generated
vendored
Normal file
|
@ -0,0 +1,45 @@
|
|||
// Copyright 2018 The Prometheus Authors
|
||||
// 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.
|
||||
|
||||
// +build !windows
|
||||
|
||||
package util
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// SysReadFile is a simplified ioutil.ReadFile that invokes syscall.Read directly.
|
||||
// https://github.com/prometheus/node_exporter/pull/728/files
|
||||
func SysReadFile(file string) (string, error) {
|
||||
f, err := os.Open(file)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
// On some machines, hwmon drivers are broken and return EAGAIN. This causes
|
||||
// Go's ioutil.ReadFile implementation to poll forever.
|
||||
//
|
||||
// Since we either want to read data or bail immediately, do the simplest
|
||||
// possible read using syscall directly.
|
||||
b := make([]byte, 128)
|
||||
n, err := syscall.Read(int(f.Fd()), b)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return string(bytes.TrimSpace(b[:n])), nil
|
||||
}
|
|
@ -1,250 +0,0 @@
|
|||
// Copyright 2018 The Prometheus Authors
|
||||
// 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 procfs
|
||||
|
||||
import (
|
||||
"net"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var (
|
||||
expectedIPVSStats = IPVSStats{
|
||||
Connections: 23765872,
|
||||
IncomingPackets: 3811989221,
|
||||
OutgoingPackets: 0,
|
||||
IncomingBytes: 89991519156915,
|
||||
OutgoingBytes: 0,
|
||||
}
|
||||
expectedIPVSBackendStatuses = []IPVSBackendStatus{
|
||||
{
|
||||
LocalAddress: net.ParseIP("192.168.0.22"),
|
||||
LocalPort: 3306,
|
||||
RemoteAddress: net.ParseIP("192.168.82.22"),
|
||||
RemotePort: 3306,
|
||||
Proto: "TCP",
|
||||
Weight: 100,
|
||||
ActiveConn: 248,
|
||||
InactConn: 2,
|
||||
},
|
||||
{
|
||||
LocalAddress: net.ParseIP("192.168.0.22"),
|
||||
LocalPort: 3306,
|
||||
RemoteAddress: net.ParseIP("192.168.83.24"),
|
||||
RemotePort: 3306,
|
||||
Proto: "TCP",
|
||||
Weight: 100,
|
||||
ActiveConn: 248,
|
||||
InactConn: 2,
|
||||
},
|
||||
{
|
||||
LocalAddress: net.ParseIP("192.168.0.22"),
|
||||
LocalPort: 3306,
|
||||
RemoteAddress: net.ParseIP("192.168.83.21"),
|
||||
RemotePort: 3306,
|
||||
Proto: "TCP",
|
||||
Weight: 100,
|
||||
ActiveConn: 248,
|
||||
InactConn: 1,
|
||||
},
|
||||
{
|
||||
LocalAddress: net.ParseIP("192.168.0.57"),
|
||||
LocalPort: 3306,
|
||||
RemoteAddress: net.ParseIP("192.168.84.22"),
|
||||
RemotePort: 3306,
|
||||
Proto: "TCP",
|
||||
Weight: 0,
|
||||
ActiveConn: 0,
|
||||
InactConn: 0,
|
||||
},
|
||||
{
|
||||
LocalAddress: net.ParseIP("192.168.0.57"),
|
||||
LocalPort: 3306,
|
||||
RemoteAddress: net.ParseIP("192.168.82.21"),
|
||||
RemotePort: 3306,
|
||||
Proto: "TCP",
|
||||
Weight: 100,
|
||||
ActiveConn: 1499,
|
||||
InactConn: 0,
|
||||
},
|
||||
{
|
||||
LocalAddress: net.ParseIP("192.168.0.57"),
|
||||
LocalPort: 3306,
|
||||
RemoteAddress: net.ParseIP("192.168.50.21"),
|
||||
RemotePort: 3306,
|
||||
Proto: "TCP",
|
||||
Weight: 100,
|
||||
ActiveConn: 1498,
|
||||
InactConn: 0,
|
||||
},
|
||||
{
|
||||
LocalAddress: net.ParseIP("192.168.0.55"),
|
||||
LocalPort: 3306,
|
||||
RemoteAddress: net.ParseIP("192.168.50.26"),
|
||||
RemotePort: 3306,
|
||||
Proto: "TCP",
|
||||
Weight: 0,
|
||||
ActiveConn: 0,
|
||||
InactConn: 0,
|
||||
},
|
||||
{
|
||||
LocalAddress: net.ParseIP("192.168.0.55"),
|
||||
LocalPort: 3306,
|
||||
RemoteAddress: net.ParseIP("192.168.49.32"),
|
||||
RemotePort: 3306,
|
||||
Proto: "TCP",
|
||||
Weight: 100,
|
||||
ActiveConn: 0,
|
||||
InactConn: 0,
|
||||
},
|
||||
{
|
||||
LocalAddress: net.ParseIP("2620::1"),
|
||||
LocalPort: 80,
|
||||
RemoteAddress: net.ParseIP("2620::2"),
|
||||
RemotePort: 80,
|
||||
Proto: "TCP",
|
||||
Weight: 1,
|
||||
ActiveConn: 0,
|
||||
InactConn: 0,
|
||||
},
|
||||
{
|
||||
LocalAddress: net.ParseIP("2620::1"),
|
||||
LocalPort: 80,
|
||||
RemoteAddress: net.ParseIP("2620::3"),
|
||||
RemotePort: 80,
|
||||
Proto: "TCP",
|
||||
Weight: 1,
|
||||
ActiveConn: 0,
|
||||
InactConn: 0,
|
||||
},
|
||||
{
|
||||
LocalAddress: net.ParseIP("2620::1"),
|
||||
LocalPort: 80,
|
||||
RemoteAddress: net.ParseIP("2620::4"),
|
||||
RemotePort: 80,
|
||||
Proto: "TCP",
|
||||
Weight: 1,
|
||||
ActiveConn: 1,
|
||||
InactConn: 1,
|
||||
},
|
||||
{
|
||||
LocalMark: "10001000",
|
||||
RemoteAddress: net.ParseIP("192.168.50.26"),
|
||||
RemotePort: 3306,
|
||||
Proto: "FWM",
|
||||
Weight: 0,
|
||||
ActiveConn: 0,
|
||||
InactConn: 1,
|
||||
},
|
||||
{
|
||||
LocalMark: "10001000",
|
||||
RemoteAddress: net.ParseIP("192.168.50.21"),
|
||||
RemotePort: 3306,
|
||||
Proto: "FWM",
|
||||
Weight: 0,
|
||||
ActiveConn: 0,
|
||||
InactConn: 2,
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
func TestIPVSStats(t *testing.T) {
|
||||
stats, err := FS("fixtures").NewIPVSStats()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if stats != expectedIPVSStats {
|
||||
t.Errorf("want %+v, have %+v", expectedIPVSStats, stats)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseIPPort(t *testing.T) {
|
||||
ip := net.ParseIP("192.168.0.22")
|
||||
port := uint16(3306)
|
||||
|
||||
gotIP, gotPort, err := parseIPPort("C0A80016:0CEA")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !(gotIP.Equal(ip) && port == gotPort) {
|
||||
t.Errorf("want %s:%d, have %s:%d", ip, port, gotIP, gotPort)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseIPPortInvalid(t *testing.T) {
|
||||
testcases := []string{
|
||||
"",
|
||||
"C0A80016",
|
||||
"C0A800:1234",
|
||||
"FOOBARBA:1234",
|
||||
"C0A80016:0CEA:1234",
|
||||
}
|
||||
|
||||
for _, s := range testcases {
|
||||
ip, port, err := parseIPPort(s)
|
||||
if ip != nil || port != uint16(0) || err == nil {
|
||||
t.Errorf("Expected error for input %s, have ip = %s, port = %v, err = %v", s, ip, port, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseIPPortIPv6(t *testing.T) {
|
||||
ip := net.ParseIP("dead:beef::1")
|
||||
port := uint16(8080)
|
||||
|
||||
gotIP, gotPort, err := parseIPPort("[DEAD:BEEF:0000:0000:0000:0000:0000:0001]:1F90")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !(gotIP.Equal(ip) && port == gotPort) {
|
||||
t.Errorf("want %s:%d, have %s:%d", ip, port, gotIP, gotPort)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIPVSBackendStatus(t *testing.T) {
|
||||
backendStats, err := FS("fixtures").NewIPVSBackendStatus()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if want, have := len(expectedIPVSBackendStatuses), len(backendStats); want != have {
|
||||
t.Fatalf("want %d backend statuses, have %d", want, have)
|
||||
}
|
||||
|
||||
for idx, expect := range expectedIPVSBackendStatuses {
|
||||
if !backendStats[idx].LocalAddress.Equal(expect.LocalAddress) {
|
||||
t.Errorf("want LocalAddress %s, have %s", expect.LocalAddress, backendStats[idx].LocalAddress)
|
||||
}
|
||||
if backendStats[idx].LocalPort != expect.LocalPort {
|
||||
t.Errorf("want LocalPort %d, have %d", expect.LocalPort, backendStats[idx].LocalPort)
|
||||
}
|
||||
if !backendStats[idx].RemoteAddress.Equal(expect.RemoteAddress) {
|
||||
t.Errorf("want RemoteAddress %s, have %s", expect.RemoteAddress, backendStats[idx].RemoteAddress)
|
||||
}
|
||||
if backendStats[idx].RemotePort != expect.RemotePort {
|
||||
t.Errorf("want RemotePort %d, have %d", expect.RemotePort, backendStats[idx].RemotePort)
|
||||
}
|
||||
if backendStats[idx].Proto != expect.Proto {
|
||||
t.Errorf("want Proto %s, have %s", expect.Proto, backendStats[idx].Proto)
|
||||
}
|
||||
if backendStats[idx].Weight != expect.Weight {
|
||||
t.Errorf("want Weight %d, have %d", expect.Weight, backendStats[idx].Weight)
|
||||
}
|
||||
if backendStats[idx].ActiveConn != expect.ActiveConn {
|
||||
t.Errorf("want ActiveConn %d, have %d", expect.ActiveConn, backendStats[idx].ActiveConn)
|
||||
}
|
||||
if backendStats[idx].InactConn != expect.InactConn {
|
||||
t.Errorf("want InactConn %d, have %d", expect.InactConn, backendStats[idx].InactConn)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
// Copyright 2018 The Prometheus Authors
|
||||
// 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 procfs
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestMDStat(t *testing.T) {
|
||||
mdStates, err := FS("fixtures").ParseMDStat()
|
||||
if err != nil {
|
||||
t.Fatalf("parsing of reference-file failed entirely: %s", err)
|
||||
}
|
||||
|
||||
refs := map[string]MDStat{
|
||||
"md3": {"md3", "active", 8, 8, 5853468288, 5853468288},
|
||||
"md127": {"md127", "active", 2, 2, 312319552, 312319552},
|
||||
"md0": {"md0", "active", 2, 2, 248896, 248896},
|
||||
"md4": {"md4", "inactive", 2, 2, 4883648, 4883648},
|
||||
"md6": {"md6", "active", 1, 2, 195310144, 16775552},
|
||||
"md8": {"md8", "active", 2, 2, 195310144, 16775552},
|
||||
"md7": {"md7", "active", 3, 4, 7813735424, 7813735424},
|
||||
}
|
||||
|
||||
if want, have := len(refs), len(mdStates); want != have {
|
||||
t.Errorf("want %d parsed md-devices, have %d", want, have)
|
||||
}
|
||||
for _, md := range mdStates {
|
||||
if want, have := refs[md.Name], md; want != have {
|
||||
t.Errorf("%s: want %v, have %v", md.Name, want, have)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,380 +0,0 @@
|
|||
// Copyright 2018 The Prometheus Authors
|
||||
// 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 procfs
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestMountStats(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
s string
|
||||
mounts []*Mount
|
||||
invalid bool
|
||||
}{
|
||||
{
|
||||
name: "no devices",
|
||||
s: `hello`,
|
||||
},
|
||||
{
|
||||
name: "device has too few fields",
|
||||
s: `device foo`,
|
||||
invalid: true,
|
||||
},
|
||||
{
|
||||
name: "device incorrect format",
|
||||
s: `device rootfs BAD on / with fstype rootfs`,
|
||||
invalid: true,
|
||||
},
|
||||
{
|
||||
name: "device incorrect format",
|
||||
s: `device rootfs mounted BAD / with fstype rootfs`,
|
||||
invalid: true,
|
||||
},
|
||||
{
|
||||
name: "device incorrect format",
|
||||
s: `device rootfs mounted on / BAD fstype rootfs`,
|
||||
invalid: true,
|
||||
},
|
||||
{
|
||||
name: "device incorrect format",
|
||||
s: `device rootfs mounted on / with BAD rootfs`,
|
||||
invalid: true,
|
||||
},
|
||||
{
|
||||
name: "device rootfs cannot have stats",
|
||||
s: `device rootfs mounted on / with fstype rootfs stats`,
|
||||
invalid: true,
|
||||
},
|
||||
{
|
||||
name: "NFSv4 device with too little info",
|
||||
s: "device 192.168.1.1:/srv mounted on /mnt/nfs with fstype nfs4 statvers=1.1\nhello",
|
||||
invalid: true,
|
||||
},
|
||||
{
|
||||
name: "NFSv4 device with bad bytes",
|
||||
s: "device 192.168.1.1:/srv mounted on /mnt/nfs with fstype nfs4 statvers=1.1\nbytes: 0",
|
||||
invalid: true,
|
||||
},
|
||||
{
|
||||
name: "NFSv4 device with bad events",
|
||||
s: "device 192.168.1.1:/srv mounted on /mnt/nfs with fstype nfs4 statvers=1.1\nevents: 0",
|
||||
invalid: true,
|
||||
},
|
||||
{
|
||||
name: "NFSv4 device with bad per-op stats",
|
||||
s: "device 192.168.1.1:/srv mounted on /mnt/nfs with fstype nfs4 statvers=1.1\nper-op statistics\nFOO 0",
|
||||
invalid: true,
|
||||
},
|
||||
{
|
||||
name: "NFSv4 device with bad transport stats",
|
||||
s: "device 192.168.1.1:/srv mounted on /mnt/nfs with fstype nfs4 statvers=1.1\nxprt: tcp",
|
||||
invalid: true,
|
||||
},
|
||||
{
|
||||
name: "NFSv4 device with bad transport version",
|
||||
s: "device 192.168.1.1:/srv mounted on /mnt/nfs with fstype nfs4 statvers=foo\nxprt: tcp 0",
|
||||
invalid: true,
|
||||
},
|
||||
{
|
||||
name: "NFSv4 device with bad transport stats version 1.0",
|
||||
s: "device 192.168.1.1:/srv mounted on /mnt/nfs with fstype nfs4 statvers=1.0\nxprt: tcp 0 0 0 0 0 0 0 0 0 0 0 0 0",
|
||||
invalid: true,
|
||||
},
|
||||
{
|
||||
name: "NFSv4 device with bad transport stats version 1.1",
|
||||
s: "device 192.168.1.1:/srv mounted on /mnt/nfs with fstype nfs4 statvers=1.1\nxprt: tcp 0 0 0 0 0 0 0 0 0 0",
|
||||
invalid: true,
|
||||
},
|
||||
{
|
||||
name: "NFSv3 device with bad transport protocol",
|
||||
s: "device 192.168.1.1:/srv mounted on /mnt/nfs with fstype nfs4 statvers=1.1\nxprt: tcpx 0 0 0 0 0 0 0 0 0 0",
|
||||
invalid: true,
|
||||
},
|
||||
{
|
||||
name: "NFSv3 device using TCP with transport stats version 1.0 OK",
|
||||
s: "device 192.168.1.1:/srv mounted on /mnt/nfs with fstype nfs statvers=1.0\nxprt: tcp 1 2 3 4 5 6 7 8 9 10",
|
||||
mounts: []*Mount{{
|
||||
Device: "192.168.1.1:/srv",
|
||||
Mount: "/mnt/nfs",
|
||||
Type: "nfs",
|
||||
Stats: &MountStatsNFS{
|
||||
StatVersion: "1.0",
|
||||
Transport: NFSTransportStats{
|
||||
Protocol: "tcp",
|
||||
Port: 1,
|
||||
Bind: 2,
|
||||
Connect: 3,
|
||||
ConnectIdleTime: 4,
|
||||
IdleTime: 5 * time.Second,
|
||||
Sends: 6,
|
||||
Receives: 7,
|
||||
BadTransactionIDs: 8,
|
||||
CumulativeActiveRequests: 9,
|
||||
CumulativeBacklog: 10,
|
||||
MaximumRPCSlotsUsed: 0, // these three are not
|
||||
CumulativeSendingQueue: 0, // present in statvers=1.0
|
||||
CumulativePendingQueue: 0, //
|
||||
},
|
||||
},
|
||||
}},
|
||||
},
|
||||
{
|
||||
name: "NFSv3 device using UDP with transport stats version 1.0 OK",
|
||||
s: "device 192.168.1.1:/srv mounted on /mnt/nfs with fstype nfs statvers=1.0\nxprt: udp 1 2 3 4 5 6 7",
|
||||
mounts: []*Mount{{
|
||||
Device: "192.168.1.1:/srv",
|
||||
Mount: "/mnt/nfs",
|
||||
Type: "nfs",
|
||||
Stats: &MountStatsNFS{
|
||||
StatVersion: "1.0",
|
||||
Transport: NFSTransportStats{
|
||||
Protocol: "udp",
|
||||
Port: 1,
|
||||
Bind: 2,
|
||||
Connect: 0,
|
||||
ConnectIdleTime: 0,
|
||||
IdleTime: 0,
|
||||
Sends: 3,
|
||||
Receives: 4,
|
||||
BadTransactionIDs: 5,
|
||||
CumulativeActiveRequests: 6,
|
||||
CumulativeBacklog: 7,
|
||||
MaximumRPCSlotsUsed: 0, // these three are not
|
||||
CumulativeSendingQueue: 0, // present in statvers=1.0
|
||||
CumulativePendingQueue: 0, //
|
||||
},
|
||||
},
|
||||
}},
|
||||
},
|
||||
{
|
||||
name: "NFSv3 device using TCP with transport stats version 1.1 OK",
|
||||
s: "device 192.168.1.1:/srv mounted on /mnt/nfs with fstype nfs statvers=1.1\nxprt: tcp 1 2 3 4 5 6 7 8 9 10 11 12 13",
|
||||
mounts: []*Mount{{
|
||||
Device: "192.168.1.1:/srv",
|
||||
Mount: "/mnt/nfs",
|
||||
Type: "nfs",
|
||||
Stats: &MountStatsNFS{
|
||||
StatVersion: "1.1",
|
||||
Transport: NFSTransportStats{
|
||||
Protocol: "tcp",
|
||||
Port: 1,
|
||||
Bind: 2,
|
||||
Connect: 3,
|
||||
ConnectIdleTime: 4,
|
||||
IdleTime: 5 * time.Second,
|
||||
Sends: 6,
|
||||
Receives: 7,
|
||||
BadTransactionIDs: 8,
|
||||
CumulativeActiveRequests: 9,
|
||||
CumulativeBacklog: 10,
|
||||
MaximumRPCSlotsUsed: 11,
|
||||
CumulativeSendingQueue: 12,
|
||||
CumulativePendingQueue: 13,
|
||||
},
|
||||
},
|
||||
}},
|
||||
},
|
||||
{
|
||||
name: "NFSv3 device using UDP with transport stats version 1.1 OK",
|
||||
s: "device 192.168.1.1:/srv mounted on /mnt/nfs with fstype nfs statvers=1.1\nxprt: udp 1 2 3 4 5 6 7 8 9 10",
|
||||
mounts: []*Mount{{
|
||||
Device: "192.168.1.1:/srv",
|
||||
Mount: "/mnt/nfs",
|
||||
Type: "nfs",
|
||||
Stats: &MountStatsNFS{
|
||||
StatVersion: "1.1",
|
||||
Transport: NFSTransportStats{
|
||||
Protocol: "udp",
|
||||
Port: 1,
|
||||
Bind: 2,
|
||||
Connect: 0, // these three are not
|
||||
ConnectIdleTime: 0, // present for UDP
|
||||
IdleTime: 0, //
|
||||
Sends: 3,
|
||||
Receives: 4,
|
||||
BadTransactionIDs: 5,
|
||||
CumulativeActiveRequests: 6,
|
||||
CumulativeBacklog: 7,
|
||||
MaximumRPCSlotsUsed: 8,
|
||||
CumulativeSendingQueue: 9,
|
||||
CumulativePendingQueue: 10,
|
||||
},
|
||||
},
|
||||
}},
|
||||
},
|
||||
{
|
||||
name: "device rootfs OK",
|
||||
s: `device rootfs mounted on / with fstype rootfs`,
|
||||
mounts: []*Mount{{
|
||||
Device: "rootfs",
|
||||
Mount: "/",
|
||||
Type: "rootfs",
|
||||
}},
|
||||
},
|
||||
{
|
||||
name: "NFSv3 device with minimal stats OK",
|
||||
s: `device 192.168.1.1:/srv mounted on /mnt/nfs with fstype nfs statvers=1.1`,
|
||||
mounts: []*Mount{{
|
||||
Device: "192.168.1.1:/srv",
|
||||
Mount: "/mnt/nfs",
|
||||
Type: "nfs",
|
||||
Stats: &MountStatsNFS{
|
||||
StatVersion: "1.1",
|
||||
},
|
||||
}},
|
||||
},
|
||||
{
|
||||
name: "fixtures OK",
|
||||
mounts: []*Mount{
|
||||
{
|
||||
Device: "rootfs",
|
||||
Mount: "/",
|
||||
Type: "rootfs",
|
||||
},
|
||||
{
|
||||
Device: "sysfs",
|
||||
Mount: "/sys",
|
||||
Type: "sysfs",
|
||||
},
|
||||
{
|
||||
Device: "proc",
|
||||
Mount: "/proc",
|
||||
Type: "proc",
|
||||
},
|
||||
{
|
||||
Device: "/dev/sda1",
|
||||
Mount: "/",
|
||||
Type: "ext4",
|
||||
},
|
||||
{
|
||||
Device: "192.168.1.1:/srv/test",
|
||||
Mount: "/mnt/nfs/test",
|
||||
Type: "nfs4",
|
||||
Stats: &MountStatsNFS{
|
||||
StatVersion: "1.1",
|
||||
Age: 13968 * time.Second,
|
||||
Bytes: NFSBytesStats{
|
||||
Read: 1207640230,
|
||||
ReadTotal: 1210214218,
|
||||
ReadPages: 295483,
|
||||
},
|
||||
Events: NFSEventsStats{
|
||||
InodeRevalidate: 52,
|
||||
DnodeRevalidate: 226,
|
||||
VFSOpen: 1,
|
||||
VFSLookup: 13,
|
||||
VFSAccess: 398,
|
||||
VFSReadPages: 331,
|
||||
VFSWritePages: 47,
|
||||
VFSFlush: 77,
|
||||
VFSFileRelease: 77,
|
||||
},
|
||||
Operations: []NFSOperationStats{
|
||||
{
|
||||
Operation: "NULL",
|
||||
},
|
||||
{
|
||||
Operation: "READ",
|
||||
Requests: 1298,
|
||||
Transmissions: 1298,
|
||||
BytesSent: 207680,
|
||||
BytesReceived: 1210292152,
|
||||
CumulativeQueueTime: 6 * time.Millisecond,
|
||||
CumulativeTotalResponseTime: 79386 * time.Millisecond,
|
||||
CumulativeTotalRequestTime: 79407 * time.Millisecond,
|
||||
},
|
||||
{
|
||||
Operation: "WRITE",
|
||||
},
|
||||
},
|
||||
Transport: NFSTransportStats{
|
||||
Protocol: "tcp",
|
||||
Port: 832,
|
||||
Connect: 1,
|
||||
IdleTime: 11 * time.Second,
|
||||
Sends: 6428,
|
||||
Receives: 6428,
|
||||
CumulativeActiveRequests: 12154,
|
||||
MaximumRPCSlotsUsed: 24,
|
||||
CumulativeSendingQueue: 26,
|
||||
CumulativePendingQueue: 5726,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
t.Logf("[%02d] test %q", i, tt.name)
|
||||
|
||||
var mounts []*Mount
|
||||
var err error
|
||||
|
||||
if tt.s != "" {
|
||||
mounts, err = parseMountStats(strings.NewReader(tt.s))
|
||||
} else {
|
||||
proc, e := FS("fixtures").NewProc(26231)
|
||||
if e != nil {
|
||||
t.Fatalf("failed to create proc: %v", err)
|
||||
}
|
||||
|
||||
mounts, err = proc.MountStats()
|
||||
}
|
||||
|
||||
if tt.invalid && err == nil {
|
||||
t.Error("expected an error, but none occurred")
|
||||
}
|
||||
if !tt.invalid && err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
if want, have := tt.mounts, mounts; !reflect.DeepEqual(want, have) {
|
||||
t.Errorf("mounts:\nwant:\n%v\nhave:\n%v", mountsStr(want), mountsStr(have))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func mountsStr(mounts []*Mount) string {
|
||||
var out string
|
||||
for i, m := range mounts {
|
||||
out += fmt.Sprintf("[%d] %q on %q (%q)", i, m.Device, m.Mount, m.Type)
|
||||
|
||||
stats, ok := m.Stats.(*MountStatsNFS)
|
||||
if !ok {
|
||||
out += "\n"
|
||||
continue
|
||||
}
|
||||
|
||||
out += fmt.Sprintf("\n\t- v%s, age: %s", stats.StatVersion, stats.Age)
|
||||
out += fmt.Sprintf("\n\t- bytes: %v", stats.Bytes)
|
||||
out += fmt.Sprintf("\n\t- events: %v", stats.Events)
|
||||
out += fmt.Sprintf("\n\t- transport: %v", stats.Transport)
|
||||
out += fmt.Sprintf("\n\t- per-operation stats:")
|
||||
|
||||
for _, o := range stats.Operations {
|
||||
out += fmt.Sprintf("\n\t\t- %v", o)
|
||||
}
|
||||
|
||||
out += "\n"
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
|
@ -1,86 +0,0 @@
|
|||
// Copyright 2018 The Prometheus Authors
|
||||
// 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 procfs
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestNetDevParseLine(t *testing.T) {
|
||||
const rawLine = ` eth0: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16`
|
||||
|
||||
have, err := NetDev{}.parseLine(rawLine)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
want := NetDevLine{"eth0", 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}
|
||||
if want != *have {
|
||||
t.Errorf("want %v, have %v", want, have)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewNetDev(t *testing.T) {
|
||||
fs, err := NewFS("fixtures")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
nd, err := fs.NewNetDev()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
lines := map[string]NetDevLine{
|
||||
"vethf345468": {Name: "vethf345468", RxBytes: 648, RxPackets: 8, TxBytes: 438, TxPackets: 5},
|
||||
"lo": {Name: "lo", RxBytes: 1664039048, RxPackets: 1566805, TxBytes: 1664039048, TxPackets: 1566805},
|
||||
"docker0": {Name: "docker0", RxBytes: 2568, RxPackets: 38, TxBytes: 438, TxPackets: 5},
|
||||
"eth0": {Name: "eth0", RxBytes: 874354587, RxPackets: 1036395, TxBytes: 563352563, TxPackets: 732147},
|
||||
}
|
||||
|
||||
if want, have := len(lines), len(nd); want != have {
|
||||
t.Errorf("want %d parsed net/dev lines, have %d", want, have)
|
||||
}
|
||||
for _, line := range nd {
|
||||
if want, have := lines[line.Name], line; want != have {
|
||||
t.Errorf("%s: want %v, have %v", line.Name, want, have)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestProcNewNetDev(t *testing.T) {
|
||||
p, err := FS("fixtures").NewProc(26231)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
nd, err := p.NewNetDev()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
lines := map[string]NetDevLine{
|
||||
"lo": {Name: "lo"},
|
||||
"eth0": {Name: "eth0", RxBytes: 438, RxPackets: 5, TxBytes: 648, TxPackets: 8},
|
||||
}
|
||||
|
||||
if want, have := len(lines), len(nd); want != have {
|
||||
t.Errorf("want %d parsed net/dev lines, have %d", want, have)
|
||||
}
|
||||
for _, line := range nd {
|
||||
if want, have := lines[line.Name], line; want != have {
|
||||
t.Errorf("%s: want %v, have %v", line.Name, want, have)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,305 +0,0 @@
|
|||
// Copyright 2018 The Prometheus Authors
|
||||
// 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 nfs_test
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/prometheus/procfs/nfs"
|
||||
)
|
||||
|
||||
func TestNewNFSClientRPCStats(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
content string
|
||||
stats *nfs.ClientRPCStats
|
||||
invalid bool
|
||||
}{
|
||||
{
|
||||
name: "invalid file",
|
||||
content: "invalid",
|
||||
invalid: true,
|
||||
}, {
|
||||
name: "good old kernel version file",
|
||||
content: `net 70 70 69 45
|
||||
rpc 1218785755 374636 1218815394
|
||||
proc2 18 16 57 74 52 71 73 45 86 0 52 83 61 17 53 50 23 70 82
|
||||
proc3 22 0 1061909262 48906 4077635 117661341 5 29391916 2570425 2993289 590 0 0 7815 15 1130 0 3983 92385 13332 2 1 23729
|
||||
proc4 48 98 51 54 83 85 23 24 1 28 73 68 83 12 84 39 68 59 58 88 29 74 69 96 21 84 15 53 86 54 66 56 97 36 49 32 85 81 11 58 32 67 13 28 35 90 1 26 1337
|
||||
`,
|
||||
stats: &nfs.ClientRPCStats{
|
||||
Network: nfs.Network{
|
||||
NetCount: 70,
|
||||
UDPCount: 70,
|
||||
TCPCount: 69,
|
||||
TCPConnect: 45,
|
||||
},
|
||||
ClientRPC: nfs.ClientRPC{
|
||||
RPCCount: 1218785755,
|
||||
Retransmissions: 374636,
|
||||
AuthRefreshes: 1218815394,
|
||||
},
|
||||
V2Stats: nfs.V2Stats{
|
||||
Null: 16,
|
||||
GetAttr: 57,
|
||||
SetAttr: 74,
|
||||
Root: 52,
|
||||
Lookup: 71,
|
||||
ReadLink: 73,
|
||||
Read: 45,
|
||||
WrCache: 86,
|
||||
Write: 0,
|
||||
Create: 52,
|
||||
Remove: 83,
|
||||
Rename: 61,
|
||||
Link: 17,
|
||||
SymLink: 53,
|
||||
MkDir: 50,
|
||||
RmDir: 23,
|
||||
ReadDir: 70,
|
||||
FsStat: 82,
|
||||
},
|
||||
V3Stats: nfs.V3Stats{
|
||||
Null: 0,
|
||||
GetAttr: 1061909262,
|
||||
SetAttr: 48906,
|
||||
Lookup: 4077635,
|
||||
Access: 117661341,
|
||||
ReadLink: 5,
|
||||
Read: 29391916,
|
||||
Write: 2570425,
|
||||
Create: 2993289,
|
||||
MkDir: 590,
|
||||
SymLink: 0,
|
||||
MkNod: 0,
|
||||
Remove: 7815,
|
||||
RmDir: 15,
|
||||
Rename: 1130,
|
||||
Link: 0,
|
||||
ReadDir: 3983,
|
||||
ReadDirPlus: 92385,
|
||||
FsStat: 13332,
|
||||
FsInfo: 2,
|
||||
PathConf: 1,
|
||||
Commit: 23729},
|
||||
ClientV4Stats: nfs.ClientV4Stats{
|
||||
Null: 98,
|
||||
Read: 51,
|
||||
Write: 54,
|
||||
Commit: 83,
|
||||
Open: 85,
|
||||
OpenConfirm: 23,
|
||||
OpenNoattr: 24,
|
||||
OpenDowngrade: 1,
|
||||
Close: 28,
|
||||
Setattr: 73,
|
||||
FsInfo: 68,
|
||||
Renew: 83,
|
||||
SetClientID: 12,
|
||||
SetClientIDConfirm: 84,
|
||||
Lock: 39,
|
||||
Lockt: 68,
|
||||
Locku: 59,
|
||||
Access: 58,
|
||||
Getattr: 88,
|
||||
Lookup: 29,
|
||||
LookupRoot: 74,
|
||||
Remove: 69,
|
||||
Rename: 96,
|
||||
Link: 21,
|
||||
Symlink: 84,
|
||||
Create: 15,
|
||||
Pathconf: 53,
|
||||
StatFs: 86,
|
||||
ReadLink: 54,
|
||||
ReadDir: 66,
|
||||
ServerCaps: 56,
|
||||
DelegReturn: 97,
|
||||
GetACL: 36,
|
||||
SetACL: 49,
|
||||
FsLocations: 32,
|
||||
ReleaseLockowner: 85,
|
||||
Secinfo: 81,
|
||||
FsidPresent: 11,
|
||||
ExchangeID: 58,
|
||||
CreateSession: 32,
|
||||
DestroySession: 67,
|
||||
Sequence: 13,
|
||||
GetLeaseTime: 28,
|
||||
ReclaimComplete: 35,
|
||||
LayoutGet: 90,
|
||||
GetDeviceInfo: 1,
|
||||
LayoutCommit: 26,
|
||||
LayoutReturn: 1337,
|
||||
SecinfoNoName: 0,
|
||||
TestStateID: 0,
|
||||
FreeStateID: 0,
|
||||
GetDeviceList: 0,
|
||||
BindConnToSession: 0,
|
||||
DestroyClientID: 0,
|
||||
Seek: 0,
|
||||
Allocate: 0,
|
||||
DeAllocate: 0,
|
||||
LayoutStats: 0,
|
||||
Clone: 0,
|
||||
},
|
||||
},
|
||||
}, {
|
||||
name: "good file",
|
||||
content: `net 18628 0 18628 6
|
||||
rpc 4329785 0 4338291
|
||||
proc2 18 2 69 0 0 4410 0 0 0 0 0 0 0 0 0 0 0 99 2
|
||||
proc3 22 1 4084749 29200 94754 32580 186 47747 7981 8639 0 6356 0 6962 0 7958 0 0 241 4 4 2 39
|
||||
proc4 61 1 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
`,
|
||||
stats: &nfs.ClientRPCStats{
|
||||
Network: nfs.Network{
|
||||
NetCount: 18628,
|
||||
UDPCount: 0,
|
||||
TCPCount: 18628,
|
||||
TCPConnect: 6,
|
||||
},
|
||||
ClientRPC: nfs.ClientRPC{
|
||||
RPCCount: 4329785,
|
||||
Retransmissions: 0,
|
||||
AuthRefreshes: 4338291,
|
||||
},
|
||||
V2Stats: nfs.V2Stats{
|
||||
Null: 2,
|
||||
GetAttr: 69,
|
||||
SetAttr: 0,
|
||||
Root: 0,
|
||||
Lookup: 4410,
|
||||
ReadLink: 0,
|
||||
Read: 0,
|
||||
WrCache: 0,
|
||||
Write: 0,
|
||||
Create: 0,
|
||||
Remove: 0,
|
||||
Rename: 0,
|
||||
Link: 0,
|
||||
SymLink: 0,
|
||||
MkDir: 0,
|
||||
RmDir: 0,
|
||||
ReadDir: 99,
|
||||
FsStat: 2,
|
||||
},
|
||||
V3Stats: nfs.V3Stats{
|
||||
Null: 1,
|
||||
GetAttr: 4084749,
|
||||
SetAttr: 29200,
|
||||
Lookup: 94754,
|
||||
Access: 32580,
|
||||
ReadLink: 186,
|
||||
Read: 47747,
|
||||
Write: 7981,
|
||||
Create: 8639,
|
||||
MkDir: 0,
|
||||
SymLink: 6356,
|
||||
MkNod: 0,
|
||||
Remove: 6962,
|
||||
RmDir: 0,
|
||||
Rename: 7958,
|
||||
Link: 0,
|
||||
ReadDir: 0,
|
||||
ReadDirPlus: 241,
|
||||
FsStat: 4,
|
||||
FsInfo: 4,
|
||||
PathConf: 2,
|
||||
Commit: 39,
|
||||
},
|
||||
ClientV4Stats: nfs.ClientV4Stats{
|
||||
Null: 1,
|
||||
Read: 0,
|
||||
Write: 0,
|
||||
Commit: 0,
|
||||
Open: 0,
|
||||
OpenConfirm: 0,
|
||||
OpenNoattr: 0,
|
||||
OpenDowngrade: 0,
|
||||
Close: 0,
|
||||
Setattr: 0,
|
||||
FsInfo: 0,
|
||||
Renew: 0,
|
||||
SetClientID: 1,
|
||||
SetClientIDConfirm: 1,
|
||||
Lock: 0,
|
||||
Lockt: 0,
|
||||
Locku: 0,
|
||||
Access: 0,
|
||||
Getattr: 0,
|
||||
Lookup: 0,
|
||||
LookupRoot: 0,
|
||||
Remove: 2,
|
||||
Rename: 0,
|
||||
Link: 0,
|
||||
Symlink: 0,
|
||||
Create: 0,
|
||||
Pathconf: 0,
|
||||
StatFs: 0,
|
||||
ReadLink: 0,
|
||||
ReadDir: 0,
|
||||
ServerCaps: 0,
|
||||
DelegReturn: 0,
|
||||
GetACL: 0,
|
||||
SetACL: 0,
|
||||
FsLocations: 0,
|
||||
ReleaseLockowner: 0,
|
||||
Secinfo: 0,
|
||||
FsidPresent: 0,
|
||||
ExchangeID: 0,
|
||||
CreateSession: 0,
|
||||
DestroySession: 0,
|
||||
Sequence: 0,
|
||||
GetLeaseTime: 0,
|
||||
ReclaimComplete: 0,
|
||||
LayoutGet: 0,
|
||||
GetDeviceInfo: 0,
|
||||
LayoutCommit: 0,
|
||||
LayoutReturn: 0,
|
||||
SecinfoNoName: 0,
|
||||
TestStateID: 0,
|
||||
FreeStateID: 0,
|
||||
GetDeviceList: 0,
|
||||
BindConnToSession: 0,
|
||||
DestroyClientID: 0,
|
||||
Seek: 0,
|
||||
Allocate: 0,
|
||||
DeAllocate: 0,
|
||||
LayoutStats: 0,
|
||||
Clone: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
stats, err := nfs.ParseClientRPCStats(strings.NewReader(tt.content))
|
||||
|
||||
if tt.invalid && err == nil {
|
||||
t.Fatal("expected an error, but none occurred")
|
||||
}
|
||||
if !tt.invalid && err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
if want, have := tt.stats, stats; !reflect.DeepEqual(want, have) {
|
||||
t.Fatalf("unexpected NFS stats:\nwant:\n%v\nhave:\n%v", want, have)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -1,196 +0,0 @@
|
|||
// Copyright 2018 The Prometheus Authors
|
||||
// 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 nfs_test
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/prometheus/procfs/nfs"
|
||||
)
|
||||
|
||||
func TestNewNFSdServerRPCStats(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
content string
|
||||
stats *nfs.ServerRPCStats
|
||||
invalid bool
|
||||
}{
|
||||
{
|
||||
name: "invalid file",
|
||||
content: "invalid",
|
||||
invalid: true,
|
||||
}, {
|
||||
name: "good file",
|
||||
content: `rc 0 6 18622
|
||||
fh 0 0 0 0 0
|
||||
io 157286400 0
|
||||
th 8 0 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000
|
||||
ra 32 0 0 0 0 0 0 0 0 0 0 0
|
||||
net 18628 0 18628 6
|
||||
rpc 18628 0 0 0 0
|
||||
proc2 18 2 69 0 0 4410 0 0 0 0 0 0 0 0 0 0 0 99 2
|
||||
proc3 22 2 112 0 2719 111 0 0 0 0 0 0 0 0 0 0 0 27 216 0 2 1 0
|
||||
proc4 2 2 10853
|
||||
proc4ops 72 0 0 0 1098 2 0 0 0 0 8179 5896 0 0 0 0 5900 0 0 2 0 2 0 9609 0 2 150 1272 0 0 0 1236 0 0 0 0 3 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
`,
|
||||
stats: &nfs.ServerRPCStats{
|
||||
ReplyCache: nfs.ReplyCache{
|
||||
Hits: 0,
|
||||
Misses: 6,
|
||||
NoCache: 18622,
|
||||
},
|
||||
FileHandles: nfs.FileHandles{
|
||||
Stale: 0,
|
||||
TotalLookups: 0,
|
||||
AnonLookups: 0,
|
||||
DirNoCache: 0,
|
||||
NoDirNoCache: 0,
|
||||
},
|
||||
InputOutput: nfs.InputOutput{
|
||||
Read: 157286400,
|
||||
Write: 0,
|
||||
},
|
||||
Threads: nfs.Threads{
|
||||
Threads: 8,
|
||||
FullCnt: 0,
|
||||
},
|
||||
ReadAheadCache: nfs.ReadAheadCache{
|
||||
CacheSize: 32,
|
||||
CacheHistogram: []uint64{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
NotFound: 0,
|
||||
},
|
||||
Network: nfs.Network{
|
||||
NetCount: 18628,
|
||||
UDPCount: 0,
|
||||
TCPCount: 18628,
|
||||
TCPConnect: 6,
|
||||
},
|
||||
ServerRPC: nfs.ServerRPC{
|
||||
RPCCount: 18628,
|
||||
BadCnt: 0,
|
||||
BadFmt: 0,
|
||||
BadAuth: 0,
|
||||
BadcInt: 0,
|
||||
},
|
||||
V2Stats: nfs.V2Stats{
|
||||
Null: 2,
|
||||
GetAttr: 69,
|
||||
SetAttr: 0,
|
||||
Root: 0,
|
||||
Lookup: 4410,
|
||||
ReadLink: 0,
|
||||
Read: 0,
|
||||
WrCache: 0,
|
||||
Write: 0,
|
||||
Create: 0,
|
||||
Remove: 0,
|
||||
Rename: 0,
|
||||
Link: 0,
|
||||
SymLink: 0,
|
||||
MkDir: 0,
|
||||
RmDir: 0,
|
||||
ReadDir: 99,
|
||||
FsStat: 2,
|
||||
},
|
||||
V3Stats: nfs.V3Stats{
|
||||
Null: 2,
|
||||
GetAttr: 112,
|
||||
SetAttr: 0,
|
||||
Lookup: 2719,
|
||||
Access: 111,
|
||||
ReadLink: 0,
|
||||
Read: 0,
|
||||
Write: 0,
|
||||
Create: 0,
|
||||
MkDir: 0,
|
||||
SymLink: 0,
|
||||
MkNod: 0,
|
||||
Remove: 0,
|
||||
RmDir: 0,
|
||||
Rename: 0,
|
||||
Link: 0,
|
||||
ReadDir: 27,
|
||||
ReadDirPlus: 216,
|
||||
FsStat: 0,
|
||||
FsInfo: 2,
|
||||
PathConf: 1,
|
||||
Commit: 0,
|
||||
},
|
||||
ServerV4Stats: nfs.ServerV4Stats{
|
||||
Null: 2,
|
||||
Compound: 10853,
|
||||
},
|
||||
V4Ops: nfs.V4Ops{
|
||||
Op0Unused: 0,
|
||||
Op1Unused: 0,
|
||||
Op2Future: 0,
|
||||
Access: 1098,
|
||||
Close: 2,
|
||||
Commit: 0,
|
||||
Create: 0,
|
||||
DelegPurge: 0,
|
||||
DelegReturn: 0,
|
||||
GetAttr: 8179,
|
||||
GetFH: 5896,
|
||||
Link: 0,
|
||||
Lock: 0,
|
||||
Lockt: 0,
|
||||
Locku: 0,
|
||||
Lookup: 5900,
|
||||
LookupRoot: 0,
|
||||
Nverify: 0,
|
||||
Open: 2,
|
||||
OpenAttr: 0,
|
||||
OpenConfirm: 2,
|
||||
OpenDgrd: 0,
|
||||
PutFH: 9609,
|
||||
PutPubFH: 0,
|
||||
PutRootFH: 2,
|
||||
Read: 150,
|
||||
ReadDir: 1272,
|
||||
ReadLink: 0,
|
||||
Remove: 0,
|
||||
Rename: 0,
|
||||
Renew: 1236,
|
||||
RestoreFH: 0,
|
||||
SaveFH: 0,
|
||||
SecInfo: 0,
|
||||
SetAttr: 0,
|
||||
Verify: 3,
|
||||
Write: 3,
|
||||
RelLockOwner: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
stats, err := nfs.ParseServerRPCStats(strings.NewReader(tt.content))
|
||||
|
||||
if tt.invalid && err == nil {
|
||||
t.Fatal("expected an error, but none occurred")
|
||||
}
|
||||
if !tt.invalid && err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
if want, have := tt.stats, stats; !reflect.DeepEqual(want, have) {
|
||||
t.Fatalf("unexpected NFS stats:\nwant:\n%v\nhave:\n%v", want, have)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -156,6 +156,26 @@ func (p Proc) Executable() (string, error) {
|
|||
return exe, err
|
||||
}
|
||||
|
||||
// Cwd returns the absolute path to the current working directory of the process.
|
||||
func (p Proc) Cwd() (string, error) {
|
||||
wd, err := os.Readlink(p.path("cwd"))
|
||||
if os.IsNotExist(err) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
return wd, err
|
||||
}
|
||||
|
||||
// RootDir returns the absolute path to the process's root directory (as set by chroot)
|
||||
func (p Proc) RootDir() (string, error) {
|
||||
rdir, err := os.Readlink(p.path("root"))
|
||||
if os.IsNotExist(err) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
return rdir, err
|
||||
}
|
||||
|
||||
// FileDescriptors returns the currently open file descriptors of a process.
|
||||
func (p Proc) FileDescriptors() ([]uintptr, error) {
|
||||
names, err := p.fileDescriptors()
|
||||
|
|
|
@ -1,46 +0,0 @@
|
|||
// Copyright 2018 The Prometheus Authors
|
||||
// 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 procfs
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestProcIO(t *testing.T) {
|
||||
p, err := FS("fixtures").NewProc(26231)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
s, err := p.NewIO()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
for _, test := range []struct {
|
||||
name string
|
||||
want int64
|
||||
have int64
|
||||
}{
|
||||
{name: "RChar", want: 750339, have: int64(s.RChar)},
|
||||
{name: "WChar", want: 818609, have: int64(s.WChar)},
|
||||
{name: "SyscR", want: 7405, have: int64(s.SyscR)},
|
||||
{name: "SyscW", want: 5245, have: int64(s.SyscW)},
|
||||
{name: "ReadBytes", want: 1024, have: int64(s.ReadBytes)},
|
||||
{name: "WriteBytes", want: 2048, have: int64(s.WriteBytes)},
|
||||
{name: "CancelledWriteBytes", want: -1024, have: s.CancelledWriteBytes},
|
||||
} {
|
||||
if test.want != test.have {
|
||||
t.Errorf("want %s %d, have %d", test.name, test.want, test.have)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
// Copyright 2018 The Prometheus Authors
|
||||
// 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 procfs
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestNewLimits(t *testing.T) {
|
||||
p, err := FS("fixtures").NewProc(26231)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
l, err := p.NewLimits()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
for _, test := range []struct {
|
||||
name string
|
||||
want int64
|
||||
have int64
|
||||
}{
|
||||
{name: "cpu time", want: -1, have: l.CPUTime},
|
||||
{name: "open files", want: 2048, have: l.OpenFiles},
|
||||
{name: "msgqueue size", want: 819200, have: l.MsqqueueSize},
|
||||
{name: "nice priority", want: 0, have: l.NicePriority},
|
||||
{name: "address space", want: 8589934592, have: l.AddressSpace},
|
||||
} {
|
||||
if test.want != test.have {
|
||||
t.Errorf("want %s %d, have %d", test.name, test.want, test.have)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
// Copyright 2018 The Prometheus Authors
|
||||
// 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 procfs
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestNewNamespaces(t *testing.T) {
|
||||
p, err := FS("fixtures").NewProc(26231)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
namespaces, err := p.NewNamespaces()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
expectedNamespaces := map[string]Namespace{
|
||||
"mnt": {"mnt", 4026531840},
|
||||
"net": {"net", 4026531993},
|
||||
}
|
||||
|
||||
if want, have := len(expectedNamespaces), len(namespaces); want != have {
|
||||
t.Errorf("want %d parsed namespaces, have %d", want, have)
|
||||
}
|
||||
for _, ns := range namespaces {
|
||||
if want, have := expectedNamespaces[ns.Type], ns; want != have {
|
||||
t.Errorf("%s: want %v, have %v", ns.Type, want, have)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,123 +0,0 @@
|
|||
// Copyright 2018 The Prometheus Authors
|
||||
// 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 procfs
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestProcStat(t *testing.T) {
|
||||
p, err := FS("fixtures").NewProc(26231)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
s, err := p.NewStat()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
for _, test := range []struct {
|
||||
name string
|
||||
want int
|
||||
have int
|
||||
}{
|
||||
{name: "pid", want: 26231, have: s.PID},
|
||||
{name: "user time", want: 1677, have: int(s.UTime)},
|
||||
{name: "system time", want: 44, have: int(s.STime)},
|
||||
{name: "start time", want: 82375, have: int(s.Starttime)},
|
||||
{name: "virtual memory size", want: 56274944, have: s.VSize},
|
||||
{name: "resident set size", want: 1981, have: s.RSS},
|
||||
} {
|
||||
if test.want != test.have {
|
||||
t.Errorf("want %s %d, have %d", test.name, test.want, test.have)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestProcStatComm(t *testing.T) {
|
||||
s1, err := testProcStat(26231)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if want, have := "vim", s1.Comm; want != have {
|
||||
t.Errorf("want comm %s, have %s", want, have)
|
||||
}
|
||||
|
||||
s2, err := testProcStat(584)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if want, have := "(a b ) ( c d) ", s2.Comm; want != have {
|
||||
t.Errorf("want comm %s, have %s", want, have)
|
||||
}
|
||||
}
|
||||
|
||||
func TestProcStatVirtualMemory(t *testing.T) {
|
||||
s, err := testProcStat(26231)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if want, have := 56274944, s.VirtualMemory(); want != have {
|
||||
t.Errorf("want virtual memory %d, have %d", want, have)
|
||||
}
|
||||
}
|
||||
|
||||
func TestProcStatResidentMemory(t *testing.T) {
|
||||
s, err := testProcStat(26231)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if want, have := 1981*os.Getpagesize(), s.ResidentMemory(); want != have {
|
||||
t.Errorf("want resident memory %d, have %d", want, have)
|
||||
}
|
||||
}
|
||||
|
||||
func TestProcStatStartTime(t *testing.T) {
|
||||
s, err := testProcStat(26231)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
time, err := s.StartTime()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if want, have := 1418184099.75, time; want != have {
|
||||
t.Errorf("want start time %f, have %f", want, have)
|
||||
}
|
||||
}
|
||||
|
||||
func TestProcStatCPUTime(t *testing.T) {
|
||||
s, err := testProcStat(26231)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if want, have := 17.21, s.CPUTime(); want != have {
|
||||
t.Errorf("want cpu time %f, have %f", want, have)
|
||||
}
|
||||
}
|
||||
|
||||
func testProcStat(pid int) (ProcStat, error) {
|
||||
p, err := FS("fixtures").NewProc(pid)
|
||||
if err != nil {
|
||||
return ProcStat{}, err
|
||||
}
|
||||
|
||||
return p.NewStat()
|
||||
}
|
|
@ -1,174 +0,0 @@
|
|||
// Copyright 2018 The Prometheus Authors
|
||||
// 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 procfs
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"sort"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSelf(t *testing.T) {
|
||||
fs := FS("fixtures")
|
||||
|
||||
p1, err := fs.NewProc(26231)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
p2, err := fs.Self()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(p1, p2) {
|
||||
t.Errorf("want process %v, have %v", p1, p2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAllProcs(t *testing.T) {
|
||||
procs, err := FS("fixtures").AllProcs()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
sort.Sort(procs)
|
||||
for i, p := range []*Proc{{PID: 584}, {PID: 26231}} {
|
||||
if want, have := p.PID, procs[i].PID; want != have {
|
||||
t.Errorf("want processes %d, have %d", want, have)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCmdLine(t *testing.T) {
|
||||
for _, tt := range []struct {
|
||||
process int
|
||||
want []string
|
||||
}{
|
||||
{process: 26231, want: []string{"vim", "test.go", "+10"}},
|
||||
{process: 26232, want: []string{}},
|
||||
{process: 26233, want: []string{"com.github.uiautomator"}},
|
||||
} {
|
||||
p1, err := FS("fixtures").NewProc(tt.process)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
c1, err := p1.CmdLine()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !reflect.DeepEqual(tt.want, c1) {
|
||||
t.Errorf("want cmdline %v, have %v", tt.want, c1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestComm(t *testing.T) {
|
||||
for _, tt := range []struct {
|
||||
process int
|
||||
want string
|
||||
}{
|
||||
{process: 26231, want: "vim"},
|
||||
{process: 26232, want: "ata_sff"},
|
||||
} {
|
||||
p1, err := FS("fixtures").NewProc(tt.process)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
c1, err := p1.Comm()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !reflect.DeepEqual(tt.want, c1) {
|
||||
t.Errorf("want comm %v, have %v", tt.want, c1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestExecutable(t *testing.T) {
|
||||
for _, tt := range []struct {
|
||||
process int
|
||||
want string
|
||||
}{
|
||||
{process: 26231, want: "/usr/bin/vim"},
|
||||
{process: 26232, want: ""},
|
||||
} {
|
||||
p, err := FS("fixtures").NewProc(tt.process)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
exe, err := p.Executable()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !reflect.DeepEqual(tt.want, exe) {
|
||||
t.Errorf("want absolute path to cmdline %v, have %v", tt.want, exe)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFileDescriptors(t *testing.T) {
|
||||
p1, err := FS("fixtures").NewProc(26231)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
fds, err := p1.FileDescriptors()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
sort.Sort(byUintptr(fds))
|
||||
if want := []uintptr{0, 1, 2, 3, 10}; !reflect.DeepEqual(want, fds) {
|
||||
t.Errorf("want fds %v, have %v", want, fds)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFileDescriptorTargets(t *testing.T) {
|
||||
p1, err := FS("fixtures").NewProc(26231)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
fds, err := p1.FileDescriptorTargets()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
sort.Strings(fds)
|
||||
var want = []string{
|
||||
"../../symlinktargets/abc",
|
||||
"../../symlinktargets/def",
|
||||
"../../symlinktargets/ghi",
|
||||
"../../symlinktargets/uvw",
|
||||
"../../symlinktargets/xyz",
|
||||
}
|
||||
if !reflect.DeepEqual(want, fds) {
|
||||
t.Errorf("want fds %v, have %v", want, fds)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFileDescriptorsLen(t *testing.T) {
|
||||
p1, err := FS("fixtures").NewProc(26231)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
l, err := p1.FileDescriptorsLen()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if want, have := 5, l; want != have {
|
||||
t.Errorf("want fds %d, have %d", want, have)
|
||||
}
|
||||
}
|
||||
|
||||
type byUintptr []uintptr
|
||||
|
||||
func (a byUintptr) Len() int { return len(a) }
|
||||
func (a byUintptr) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
||||
func (a byUintptr) Less(i, j int) bool { return a[i] < a[j] }
|
|
@ -1,74 +0,0 @@
|
|||
// Copyright 2018 The Prometheus Authors
|
||||
// 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 procfs
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestStat(t *testing.T) {
|
||||
s, err := FS("fixtures").NewStat()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// cpu
|
||||
if want, have := float64(301854)/userHZ, s.CPUTotal.User; want != have {
|
||||
t.Errorf("want cpu/user %v, have %v", want, have)
|
||||
}
|
||||
if want, have := float64(31)/userHZ, s.CPU[7].SoftIRQ; want != have {
|
||||
t.Errorf("want cpu7/softirq %v, have %v", want, have)
|
||||
}
|
||||
|
||||
// intr
|
||||
if want, have := uint64(8885917), s.IRQTotal; want != have {
|
||||
t.Errorf("want irq/total %d, have %d", want, have)
|
||||
}
|
||||
if want, have := uint64(1), s.IRQ[8]; want != have {
|
||||
t.Errorf("want irq8 %d, have %d", want, have)
|
||||
}
|
||||
|
||||
// ctxt
|
||||
if want, have := uint64(38014093), s.ContextSwitches; want != have {
|
||||
t.Errorf("want context switches (ctxt) %d, have %d", want, have)
|
||||
}
|
||||
|
||||
// btime
|
||||
if want, have := uint64(1418183276), s.BootTime; want != have {
|
||||
t.Errorf("want boot time (btime) %d, have %d", want, have)
|
||||
}
|
||||
|
||||
// processes
|
||||
if want, have := uint64(26442), s.ProcessCreated; want != have {
|
||||
t.Errorf("want process created (processes) %d, have %d", want, have)
|
||||
}
|
||||
|
||||
// procs_running
|
||||
if want, have := uint64(2), s.ProcessesRunning; want != have {
|
||||
t.Errorf("want processes running (procs_running) %d, have %d", want, have)
|
||||
}
|
||||
|
||||
// procs_blocked
|
||||
if want, have := uint64(1), s.ProcessesBlocked; want != have {
|
||||
t.Errorf("want processes blocked (procs_blocked) %d, have %d", want, have)
|
||||
}
|
||||
|
||||
// softirq
|
||||
if want, have := uint64(5057579), s.SoftIRQTotal; want != have {
|
||||
t.Errorf("want softirq total %d, have %d", want, have)
|
||||
}
|
||||
|
||||
if want, have := uint64(508444), s.SoftIRQ.Rcu; want != have {
|
||||
t.Errorf("want softirq RCU %d, have %d", want, have)
|
||||
}
|
||||
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
fixtures/
|
|
@ -389,6 +389,148 @@ Lines: 1
|
|||
0
|
||||
Mode: 644
|
||||
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Directory: fixtures/devices/system
|
||||
Mode: 775
|
||||
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Directory: fixtures/devices/system/cpu
|
||||
Mode: 775
|
||||
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Directory: fixtures/devices/system/cpu/cpu0
|
||||
Mode: 775
|
||||
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Path: fixtures/devices/system/cpu/cpu0/cpufreq
|
||||
SymlinkTo: ../cpufreq/policy0
|
||||
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Directory: fixtures/devices/system/cpu/cpu1
|
||||
Mode: 775
|
||||
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Directory: fixtures/devices/system/cpu/cpu1/cpufreq
|
||||
Mode: 775
|
||||
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Path: fixtures/devices/system/cpu/cpu1/cpufreq/cpuinfo_cur_freq
|
||||
Lines: 1
|
||||
1200195
|
||||
Mode: 400
|
||||
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Path: fixtures/devices/system/cpu/cpu1/cpufreq/cpuinfo_max_freq
|
||||
Lines: 1
|
||||
3300000
|
||||
Mode: 664
|
||||
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Path: fixtures/devices/system/cpu/cpu1/cpufreq/cpuinfo_min_freq
|
||||
Lines: 1
|
||||
1200000
|
||||
Mode: 664
|
||||
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Path: fixtures/devices/system/cpu/cpu1/cpufreq/cpuinfo_transition_latency
|
||||
Lines: 1
|
||||
4294967295
|
||||
Mode: 664
|
||||
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Path: fixtures/devices/system/cpu/cpu1/cpufreq/related_cpus
|
||||
Lines: 1
|
||||
1
|
||||
Mode: 664
|
||||
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Path: fixtures/devices/system/cpu/cpu1/cpufreq/scaling_available_governors
|
||||
Lines: 1
|
||||
performance powersave
|
||||
Mode: 664
|
||||
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Path: fixtures/devices/system/cpu/cpu1/cpufreq/scaling_driver
|
||||
Lines: 1
|
||||
intel_pstate
|
||||
Mode: 664
|
||||
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Path: fixtures/devices/system/cpu/cpu1/cpufreq/scaling_governor
|
||||
Lines: 1
|
||||
powersave
|
||||
Mode: 664
|
||||
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Path: fixtures/devices/system/cpu/cpu1/cpufreq/scaling_max_freq
|
||||
Lines: 1
|
||||
3300000
|
||||
Mode: 664
|
||||
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Path: fixtures/devices/system/cpu/cpu1/cpufreq/scaling_min_freq
|
||||
Lines: 1
|
||||
1200000
|
||||
Mode: 664
|
||||
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Path: fixtures/devices/system/cpu/cpu1/cpufreq/scaling_setspeed
|
||||
Lines: 1
|
||||
<unsupported>
|
||||
Mode: 664
|
||||
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Directory: fixtures/devices/system/cpu/cpufreq
|
||||
Mode: 775
|
||||
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Directory: fixtures/devices/system/cpu/cpufreq/policy0
|
||||
Mode: 775
|
||||
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Path: fixtures/devices/system/cpu/cpufreq/policy0/affected_cpus
|
||||
Lines: 1
|
||||
0
|
||||
Mode: 444
|
||||
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Path: fixtures/devices/system/cpu/cpufreq/policy0/cpuinfo_max_freq
|
||||
Lines: 1
|
||||
2400000
|
||||
Mode: 444
|
||||
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Path: fixtures/devices/system/cpu/cpufreq/policy0/cpuinfo_min_freq
|
||||
Lines: 1
|
||||
800000
|
||||
Mode: 444
|
||||
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Path: fixtures/devices/system/cpu/cpufreq/policy0/cpuinfo_transition_latency
|
||||
Lines: 1
|
||||
0
|
||||
Mode: 444
|
||||
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Path: fixtures/devices/system/cpu/cpufreq/policy0/related_cpus
|
||||
Lines: 1
|
||||
0
|
||||
Mode: 444
|
||||
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Path: fixtures/devices/system/cpu/cpufreq/policy0/scaling_available_governors
|
||||
Lines: 1
|
||||
performance powersave
|
||||
Mode: 444
|
||||
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Path: fixtures/devices/system/cpu/cpufreq/policy0/scaling_cur_freq
|
||||
Lines: 1
|
||||
1219917
|
||||
Mode: 444
|
||||
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Path: fixtures/devices/system/cpu/cpufreq/policy0/scaling_driver
|
||||
Lines: 1
|
||||
intel_pstate
|
||||
Mode: 444
|
||||
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Path: fixtures/devices/system/cpu/cpufreq/policy0/scaling_governor
|
||||
Lines: 1
|
||||
powersave
|
||||
Mode: 644
|
||||
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Path: fixtures/devices/system/cpu/cpufreq/policy0/scaling_max_freq
|
||||
Lines: 1
|
||||
2400000
|
||||
Mode: 644
|
||||
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Path: fixtures/devices/system/cpu/cpufreq/policy0/scaling_min_freq
|
||||
Lines: 1
|
||||
800000
|
||||
Mode: 644
|
||||
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Path: fixtures/devices/system/cpu/cpufreq/policy0/scaling_setspeed
|
||||
Lines: 1
|
||||
<unsupported>
|
||||
Mode: 644
|
||||
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Directory: fixtures/devices/system/cpu/cpufreq/policy1
|
||||
Mode: 755
|
||||
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Directory: fixtures/fs
|
||||
Mode: 755
|
||||
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
|
|
@ -1,108 +0,0 @@
|
|||
// Copyright 2017 The Prometheus Authors
|
||||
// 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 sysfs
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestNewFS(t *testing.T) {
|
||||
if _, err := NewFS("foobar"); err == nil {
|
||||
t.Error("want NewFS to fail for non-existing mount point")
|
||||
}
|
||||
|
||||
if _, err := NewFS("doc.go"); err == nil {
|
||||
t.Error("want NewFS to fail if mount point is not a directory")
|
||||
}
|
||||
}
|
||||
|
||||
func TestFSXFSStats(t *testing.T) {
|
||||
stats, err := FS("fixtures").XFSStats()
|
||||
if err != nil {
|
||||
t.Fatalf("failed to parse XFS stats: %v", err)
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
allocated uint32
|
||||
}{
|
||||
{
|
||||
name: "sda1",
|
||||
allocated: 1,
|
||||
},
|
||||
{
|
||||
name: "sdb1",
|
||||
allocated: 2,
|
||||
},
|
||||
}
|
||||
|
||||
const expect = 2
|
||||
|
||||
if l := len(stats); l != expect {
|
||||
t.Fatalf("unexpected number of XFS stats: %d", l)
|
||||
}
|
||||
if l := len(tests); l != expect {
|
||||
t.Fatalf("unexpected number of tests: %d", l)
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
if want, got := tt.name, stats[i].Name; want != got {
|
||||
t.Errorf("unexpected stats name:\nwant: %q\nhave: %q", want, got)
|
||||
}
|
||||
|
||||
if want, got := tt.allocated, stats[i].ExtentAllocation.ExtentsAllocated; want != got {
|
||||
t.Errorf("unexpected extents allocated:\nwant: %d\nhave: %d", want, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFSBcacheStats(t *testing.T) {
|
||||
stats, err := FS("fixtures").BcacheStats()
|
||||
if err != nil {
|
||||
t.Fatalf("failed to parse bcache stats: %v", err)
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
bdevs int
|
||||
caches int
|
||||
}{
|
||||
{
|
||||
name: "deaddd54-c735-46d5-868e-f331c5fd7c74",
|
||||
bdevs: 1,
|
||||
caches: 1,
|
||||
},
|
||||
}
|
||||
|
||||
const expect = 1
|
||||
|
||||
if l := len(stats); l != expect {
|
||||
t.Fatalf("unexpected number of bcache stats: %d", l)
|
||||
}
|
||||
if l := len(tests); l != expect {
|
||||
t.Fatalf("unexpected number of tests: %d", l)
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
if want, got := tt.name, stats[i].Name; want != got {
|
||||
t.Errorf("unexpected stats name:\nwant: %q\nhave: %q", want, got)
|
||||
}
|
||||
|
||||
if want, got := tt.bdevs, len(stats[i].Bdevs); want != got {
|
||||
t.Errorf("unexpected value allocated:\nwant: %d\nhave: %d", want, got)
|
||||
}
|
||||
|
||||
if want, got := tt.caches, len(stats[i].Caches); want != got {
|
||||
t.Errorf("unexpected value allocated:\nwant: %d\nhave: %d", want, got)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -11,6 +11,8 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// +build !windows
|
||||
|
||||
package sysfs
|
||||
|
||||
import (
|
||||
|
@ -20,7 +22,8 @@ import (
|
|||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/prometheus/procfs/internal/util"
|
||||
)
|
||||
|
||||
// NetClassIface contains info from files in /sys/class/net/<iface>
|
||||
|
@ -109,7 +112,7 @@ func (nc NetClass) parseNetClassIface(devicePath string) (*NetClassIface, error)
|
|||
panic(fmt.Errorf("field %s does not have a filename tag", fieldType.Name))
|
||||
}
|
||||
|
||||
fileContents, err := sysReadFile(devicePath + "/" + fieldType.Tag.Get("fileName"))
|
||||
value, err := util.SysReadFile(devicePath + "/" + fieldType.Tag.Get("fileName"))
|
||||
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) || err.Error() == "operation not supported" || err.Error() == "invalid argument" {
|
||||
|
@ -117,7 +120,6 @@ func (nc NetClass) parseNetClassIface(devicePath string) (*NetClassIface, error)
|
|||
}
|
||||
return nil, fmt.Errorf("could not access file %s: %s", fieldType.Tag.Get("fileName"), err)
|
||||
}
|
||||
value := strings.TrimSpace(string(fileContents))
|
||||
|
||||
switch fieldValue.Kind() {
|
||||
case reflect.String:
|
||||
|
@ -149,26 +151,3 @@ func (nc NetClass) parseNetClassIface(devicePath string) (*NetClassIface, error)
|
|||
|
||||
return &interfaceClass, nil
|
||||
}
|
||||
|
||||
// sysReadFile is a simplified ioutil.ReadFile that invokes syscall.Read directly.
|
||||
// https://github.com/prometheus/node_exporter/pull/728/files
|
||||
func sysReadFile(file string) ([]byte, error) {
|
||||
f, err := os.Open(file)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
// On some machines, hwmon drivers are broken and return EAGAIN. This causes
|
||||
// Go's ioutil.ReadFile implementation to poll forever.
|
||||
//
|
||||
// Since we either want to read data or bail immediately, do the simplest
|
||||
// possible read using syscall directly.
|
||||
b := make([]byte, 128)
|
||||
n, err := syscall.Read(int(f.Fd()), b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return b[:n], nil
|
||||
}
|
||||
|
|
|
@ -1,88 +0,0 @@
|
|||
// Copyright 2018 The Prometheus Authors
|
||||
// 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 sysfs
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestNewNetClass(t *testing.T) {
|
||||
fs, err := NewFS("fixtures")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
nc, err := fs.NewNetClass()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
var (
|
||||
addrAssignType int64 = 3
|
||||
addrLen int64 = 6
|
||||
carrier int64 = 1
|
||||
carrierChanges int64 = 2
|
||||
carrierDownCount int64 = 1
|
||||
carrierUpCount int64 = 1
|
||||
devID int64 = 32
|
||||
dormant int64 = 1
|
||||
flags int64 = 4867
|
||||
ifIndex int64 = 2
|
||||
ifLink int64 = 2
|
||||
linkMode int64 = 1
|
||||
mtu int64 = 1500
|
||||
nameAssignType int64 = 2
|
||||
netDevGroup int64 = 0
|
||||
speed int64 = 1000
|
||||
txQueueLen int64 = 1000
|
||||
netType int64 = 1
|
||||
)
|
||||
|
||||
netClass := NetClass{
|
||||
"eth0": {
|
||||
Address: "01:01:01:01:01:01",
|
||||
AddrAssignType: &addrAssignType,
|
||||
AddrLen: &addrLen,
|
||||
Broadcast: "ff:ff:ff:ff:ff:ff",
|
||||
Carrier: &carrier,
|
||||
CarrierChanges: &carrierChanges,
|
||||
CarrierDownCount: &carrierDownCount,
|
||||
CarrierUpCount: &carrierUpCount,
|
||||
DevID: &devID,
|
||||
Dormant: &dormant,
|
||||
Duplex: "full",
|
||||
Flags: &flags,
|
||||
IfAlias: "",
|
||||
IfIndex: &ifIndex,
|
||||
IfLink: &ifLink,
|
||||
LinkMode: &linkMode,
|
||||
MTU: &mtu,
|
||||
Name: "eth0",
|
||||
NameAssignType: &nameAssignType,
|
||||
NetDevGroup: &netDevGroup,
|
||||
OperState: "up",
|
||||
PhysPortID: "",
|
||||
PhysPortName: "",
|
||||
PhysSwitchID: "",
|
||||
Speed: &speed,
|
||||
TxQueueLen: &txQueueLen,
|
||||
Type: &netType,
|
||||
},
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(netClass, nc) {
|
||||
t.Errorf("Result not correct: want %v, have %v", netClass, nc)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,141 @@
|
|||
// Copyright 2018 The Prometheus Authors
|
||||
// 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.
|
||||
|
||||
// +build !windows
|
||||
|
||||
package sysfs
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/prometheus/procfs/internal/util"
|
||||
)
|
||||
|
||||
// SystemCPUCpufreqStats contains stats from devices/system/cpu/cpu[0-9]*/cpufreq/...
|
||||
type SystemCPUCpufreqStats struct {
|
||||
Name string
|
||||
CurrentFrequency uint64
|
||||
MinimumFrequency uint64
|
||||
MaximumFrequency uint64
|
||||
TransitionLatency uint64
|
||||
AvailableGovernors string
|
||||
Driver string
|
||||
Govenor string
|
||||
RelatedCpus string
|
||||
SetSpeed string
|
||||
}
|
||||
|
||||
// TODO: Add topology support.
|
||||
|
||||
// TODO: Add thermal_throttle support.
|
||||
|
||||
// NewSystemCpufreq returns CPU frequency metrics for all CPUs.
|
||||
func NewSystemCpufreq() ([]SystemCPUCpufreqStats, error) {
|
||||
fs, err := NewFS(DefaultMountPoint)
|
||||
if err != nil {
|
||||
return []SystemCPUCpufreqStats{}, err
|
||||
}
|
||||
|
||||
return fs.NewSystemCpufreq()
|
||||
}
|
||||
|
||||
// NewSystemCpufreq returns CPU frequency metrics for all CPUs.
|
||||
func (fs FS) NewSystemCpufreq() ([]SystemCPUCpufreqStats, error) {
|
||||
var cpufreq = &SystemCPUCpufreqStats{}
|
||||
|
||||
cpus, err := filepath.Glob(fs.Path("devices/system/cpu/cpu[0-9]*"))
|
||||
if err != nil {
|
||||
return []SystemCPUCpufreqStats{}, err
|
||||
}
|
||||
|
||||
systemCpufreq := []SystemCPUCpufreqStats{}
|
||||
for _, cpu := range cpus {
|
||||
cpuName := filepath.Base(cpu)
|
||||
cpuNum := strings.TrimPrefix(cpuName, "cpu")
|
||||
|
||||
cpuCpufreqPath := filepath.Join(cpu, "cpufreq")
|
||||
if _, err := os.Stat(cpuCpufreqPath); os.IsNotExist(err) {
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
return []SystemCPUCpufreqStats{}, err
|
||||
}
|
||||
|
||||
if _, err = os.Stat(filepath.Join(cpuCpufreqPath, "scaling_cur_freq")); err == nil {
|
||||
cpufreq, err = parseCpufreqCpuinfo("scaling", cpuCpufreqPath)
|
||||
} else if _, err = os.Stat(filepath.Join(cpuCpufreqPath, "cpuinfo_cur_freq")); err == nil {
|
||||
// Older kernels have metrics named `cpuinfo_...`.
|
||||
cpufreq, err = parseCpufreqCpuinfo("cpuinfo", cpuCpufreqPath)
|
||||
} else {
|
||||
return []SystemCPUCpufreqStats{}, fmt.Errorf("CPU %v is missing cpufreq", cpu)
|
||||
}
|
||||
if err != nil {
|
||||
return []SystemCPUCpufreqStats{}, err
|
||||
}
|
||||
cpufreq.Name = cpuNum
|
||||
systemCpufreq = append(systemCpufreq, *cpufreq)
|
||||
}
|
||||
|
||||
return systemCpufreq, nil
|
||||
}
|
||||
|
||||
func parseCpufreqCpuinfo(prefix string, cpuPath string) (*SystemCPUCpufreqStats, error) {
|
||||
uintFiles := []string{
|
||||
prefix + "_cur_freq",
|
||||
prefix + "_max_freq",
|
||||
prefix + "_min_freq",
|
||||
"cpuinfo_transition_latency",
|
||||
}
|
||||
uintOut := make([]uint64, len(uintFiles))
|
||||
|
||||
for i, f := range uintFiles {
|
||||
v, err := util.ReadUintFromFile(filepath.Join(cpuPath, f))
|
||||
if err != nil {
|
||||
return &SystemCPUCpufreqStats{}, err
|
||||
}
|
||||
|
||||
uintOut[i] = v
|
||||
}
|
||||
|
||||
stringFiles := []string{
|
||||
"scaling_available_governors",
|
||||
"scaling_driver",
|
||||
"scaling_governor",
|
||||
"related_cpus",
|
||||
"scaling_setspeed",
|
||||
}
|
||||
stringOut := make([]string, len(stringFiles))
|
||||
var err error
|
||||
|
||||
for i, f := range stringFiles {
|
||||
stringOut[i], err = util.SysReadFile(filepath.Join(cpuPath, f))
|
||||
if err != nil {
|
||||
return &SystemCPUCpufreqStats{}, err
|
||||
}
|
||||
}
|
||||
|
||||
return &SystemCPUCpufreqStats{
|
||||
CurrentFrequency: uintOut[0],
|
||||
MaximumFrequency: uintOut[1],
|
||||
MinimumFrequency: uintOut[2],
|
||||
TransitionLatency: uintOut[3],
|
||||
AvailableGovernors: stringOut[0],
|
||||
Driver: stringOut[1],
|
||||
Govenor: stringOut[2],
|
||||
RelatedCpus: stringOut[3],
|
||||
SetSpeed: stringOut[4],
|
||||
}, nil
|
||||
}
|
|
@ -1,66 +0,0 @@
|
|||
// Copyright 2017 Prometheus Team
|
||||
// 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 procfs
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestXfrmStats(t *testing.T) {
|
||||
xfrmStats, err := FS("fixtures").NewXfrmStat()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
for _, test := range []struct {
|
||||
name string
|
||||
want int
|
||||
got int
|
||||
}{
|
||||
{name: "XfrmInError", want: 1, got: xfrmStats.XfrmInError},
|
||||
{name: "XfrmInBufferError", want: 2, got: xfrmStats.XfrmInBufferError},
|
||||
{name: "XfrmInHdrError", want: 4, got: xfrmStats.XfrmInHdrError},
|
||||
{name: "XfrmInNoStates", want: 3, got: xfrmStats.XfrmInNoStates},
|
||||
{name: "XfrmInStateProtoError", want: 40, got: xfrmStats.XfrmInStateProtoError},
|
||||
{name: "XfrmInStateModeError", want: 100, got: xfrmStats.XfrmInStateModeError},
|
||||
{name: "XfrmInStateSeqError", want: 6000, got: xfrmStats.XfrmInStateSeqError},
|
||||
{name: "XfrmInStateExpired", want: 4, got: xfrmStats.XfrmInStateExpired},
|
||||
{name: "XfrmInStateMismatch", want: 23451, got: xfrmStats.XfrmInStateMismatch},
|
||||
{name: "XfrmInStateInvalid", want: 55555, got: xfrmStats.XfrmInStateInvalid},
|
||||
{name: "XfrmInTmplMismatch", want: 51, got: xfrmStats.XfrmInTmplMismatch},
|
||||
{name: "XfrmInNoPols", want: 65432, got: xfrmStats.XfrmInNoPols},
|
||||
{name: "XfrmInPolBlock", want: 100, got: xfrmStats.XfrmInPolBlock},
|
||||
{name: "XfrmInPolError", want: 10000, got: xfrmStats.XfrmInPolError},
|
||||
{name: "XfrmOutError", want: 1000000, got: xfrmStats.XfrmOutError},
|
||||
{name: "XfrmOutBundleGenError", want: 43321, got: xfrmStats.XfrmOutBundleGenError},
|
||||
{name: "XfrmOutBundleCheckError", want: 555, got: xfrmStats.XfrmOutBundleCheckError},
|
||||
{name: "XfrmOutNoStates", want: 869, got: xfrmStats.XfrmOutNoStates},
|
||||
{name: "XfrmOutStateProtoError", want: 4542, got: xfrmStats.XfrmOutStateProtoError},
|
||||
{name: "XfrmOutStateModeError", want: 4, got: xfrmStats.XfrmOutStateModeError},
|
||||
{name: "XfrmOutStateSeqError", want: 543, got: xfrmStats.XfrmOutStateSeqError},
|
||||
{name: "XfrmOutStateExpired", want: 565, got: xfrmStats.XfrmOutStateExpired},
|
||||
{name: "XfrmOutPolBlock", want: 43456, got: xfrmStats.XfrmOutPolBlock},
|
||||
{name: "XfrmOutPolDead", want: 7656, got: xfrmStats.XfrmOutPolDead},
|
||||
{name: "XfrmOutPolError", want: 1454, got: xfrmStats.XfrmOutPolError},
|
||||
{name: "XfrmFwdHdrError", want: 6654, got: xfrmStats.XfrmFwdHdrError},
|
||||
{name: "XfrmOutStateInvaliad", want: 28765, got: xfrmStats.XfrmOutStateInvalid},
|
||||
{name: "XfrmAcquireError", want: 24532, got: xfrmStats.XfrmAcquireError},
|
||||
{name: "XfrmInStateInvalid", want: 55555, got: xfrmStats.XfrmInStateInvalid},
|
||||
{name: "XfrmOutError", want: 1000000, got: xfrmStats.XfrmOutError},
|
||||
} {
|
||||
if test.want != test.got {
|
||||
t.Errorf("Want %s %d, have %d", test.name, test.want, test.got)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,442 +0,0 @@
|
|||
// Copyright 2017 The Prometheus Authors
|
||||
// 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 xfs_test
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/prometheus/procfs"
|
||||
"github.com/prometheus/procfs/xfs"
|
||||
)
|
||||
|
||||
func TestParseStats(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
s string
|
||||
fs bool
|
||||
stats *xfs.Stats
|
||||
invalid bool
|
||||
}{
|
||||
{
|
||||
name: "empty file OK",
|
||||
},
|
||||
{
|
||||
name: "short or empty lines and unknown labels ignored",
|
||||
s: "one\n\ntwo 1 2 3\n",
|
||||
stats: &xfs.Stats{},
|
||||
},
|
||||
{
|
||||
name: "bad uint32",
|
||||
s: "extent_alloc XXX",
|
||||
invalid: true,
|
||||
},
|
||||
{
|
||||
name: "bad uint64",
|
||||
s: "xpc XXX",
|
||||
invalid: true,
|
||||
},
|
||||
{
|
||||
name: "extent_alloc bad",
|
||||
s: "extent_alloc 1",
|
||||
invalid: true,
|
||||
},
|
||||
{
|
||||
name: "extent_alloc OK",
|
||||
s: "extent_alloc 1 2 3 4",
|
||||
stats: &xfs.Stats{
|
||||
ExtentAllocation: xfs.ExtentAllocationStats{
|
||||
ExtentsAllocated: 1,
|
||||
BlocksAllocated: 2,
|
||||
ExtentsFreed: 3,
|
||||
BlocksFreed: 4,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "abt bad",
|
||||
s: "abt 1",
|
||||
invalid: true,
|
||||
},
|
||||
{
|
||||
name: "abt OK",
|
||||
s: "abt 1 2 3 4",
|
||||
stats: &xfs.Stats{
|
||||
AllocationBTree: xfs.BTreeStats{
|
||||
Lookups: 1,
|
||||
Compares: 2,
|
||||
RecordsInserted: 3,
|
||||
RecordsDeleted: 4,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "blk_map bad",
|
||||
s: "blk_map 1",
|
||||
invalid: true,
|
||||
},
|
||||
{
|
||||
name: "blk_map OK",
|
||||
s: "blk_map 1 2 3 4 5 6 7",
|
||||
stats: &xfs.Stats{
|
||||
BlockMapping: xfs.BlockMappingStats{
|
||||
Reads: 1,
|
||||
Writes: 2,
|
||||
Unmaps: 3,
|
||||
ExtentListInsertions: 4,
|
||||
ExtentListDeletions: 5,
|
||||
ExtentListLookups: 6,
|
||||
ExtentListCompares: 7,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "bmbt bad",
|
||||
s: "bmbt 1",
|
||||
invalid: true,
|
||||
},
|
||||
{
|
||||
name: "bmbt OK",
|
||||
s: "bmbt 1 2 3 4",
|
||||
stats: &xfs.Stats{
|
||||
BlockMapBTree: xfs.BTreeStats{
|
||||
Lookups: 1,
|
||||
Compares: 2,
|
||||
RecordsInserted: 3,
|
||||
RecordsDeleted: 4,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "dir bad",
|
||||
s: "dir 1",
|
||||
invalid: true,
|
||||
},
|
||||
{
|
||||
name: "dir OK",
|
||||
s: "dir 1 2 3 4",
|
||||
stats: &xfs.Stats{
|
||||
DirectoryOperation: xfs.DirectoryOperationStats{
|
||||
Lookups: 1,
|
||||
Creates: 2,
|
||||
Removes: 3,
|
||||
Getdents: 4,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "trans bad",
|
||||
s: "trans 1",
|
||||
invalid: true,
|
||||
},
|
||||
{
|
||||
name: "trans OK",
|
||||
s: "trans 1 2 3",
|
||||
stats: &xfs.Stats{
|
||||
Transaction: xfs.TransactionStats{
|
||||
Sync: 1,
|
||||
Async: 2,
|
||||
Empty: 3,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ig bad",
|
||||
s: "ig 1",
|
||||
invalid: true,
|
||||
},
|
||||
{
|
||||
name: "ig OK",
|
||||
s: "ig 1 2 3 4 5 6 7",
|
||||
stats: &xfs.Stats{
|
||||
InodeOperation: xfs.InodeOperationStats{
|
||||
Attempts: 1,
|
||||
Found: 2,
|
||||
Recycle: 3,
|
||||
Missed: 4,
|
||||
Duplicate: 5,
|
||||
Reclaims: 6,
|
||||
AttributeChange: 7,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "log bad",
|
||||
s: "log 1",
|
||||
invalid: true,
|
||||
},
|
||||
{
|
||||
name: "log OK",
|
||||
s: "log 1 2 3 4 5",
|
||||
stats: &xfs.Stats{
|
||||
LogOperation: xfs.LogOperationStats{
|
||||
Writes: 1,
|
||||
Blocks: 2,
|
||||
NoInternalBuffers: 3,
|
||||
Force: 4,
|
||||
ForceSleep: 5,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "rw bad",
|
||||
s: "rw 1",
|
||||
invalid: true,
|
||||
},
|
||||
{
|
||||
name: "rw OK",
|
||||
s: "rw 1 2",
|
||||
stats: &xfs.Stats{
|
||||
ReadWrite: xfs.ReadWriteStats{
|
||||
Read: 1,
|
||||
Write: 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "attr bad",
|
||||
s: "attr 1",
|
||||
invalid: true,
|
||||
},
|
||||
{
|
||||
name: "attr OK",
|
||||
s: "attr 1 2 3 4",
|
||||
stats: &xfs.Stats{
|
||||
AttributeOperation: xfs.AttributeOperationStats{
|
||||
Get: 1,
|
||||
Set: 2,
|
||||
Remove: 3,
|
||||
List: 4,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "icluster bad",
|
||||
s: "icluster 1",
|
||||
invalid: true,
|
||||
},
|
||||
{
|
||||
name: "icluster OK",
|
||||
s: "icluster 1 2 3",
|
||||
stats: &xfs.Stats{
|
||||
InodeClustering: xfs.InodeClusteringStats{
|
||||
Iflush: 1,
|
||||
Flush: 2,
|
||||
FlushInode: 3,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "vnodes bad",
|
||||
s: "vnodes 1",
|
||||
invalid: true,
|
||||
},
|
||||
{
|
||||
name: "vnodes (missing free) OK",
|
||||
s: "vnodes 1 2 3 4 5 6 7",
|
||||
stats: &xfs.Stats{
|
||||
Vnode: xfs.VnodeStats{
|
||||
Active: 1,
|
||||
Allocate: 2,
|
||||
Get: 3,
|
||||
Hold: 4,
|
||||
Release: 5,
|
||||
Reclaim: 6,
|
||||
Remove: 7,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "vnodes (with free) OK",
|
||||
s: "vnodes 1 2 3 4 5 6 7 8",
|
||||
stats: &xfs.Stats{
|
||||
Vnode: xfs.VnodeStats{
|
||||
Active: 1,
|
||||
Allocate: 2,
|
||||
Get: 3,
|
||||
Hold: 4,
|
||||
Release: 5,
|
||||
Reclaim: 6,
|
||||
Remove: 7,
|
||||
Free: 8,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "buf bad",
|
||||
s: "buf 1",
|
||||
invalid: true,
|
||||
},
|
||||
{
|
||||
name: "buf OK",
|
||||
s: "buf 1 2 3 4 5 6 7 8 9",
|
||||
stats: &xfs.Stats{
|
||||
Buffer: xfs.BufferStats{
|
||||
Get: 1,
|
||||
Create: 2,
|
||||
GetLocked: 3,
|
||||
GetLockedWaited: 4,
|
||||
BusyLocked: 5,
|
||||
MissLocked: 6,
|
||||
PageRetries: 7,
|
||||
PageFound: 8,
|
||||
GetRead: 9,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "xpc bad",
|
||||
s: "xpc 1",
|
||||
invalid: true,
|
||||
},
|
||||
{
|
||||
name: "xpc OK",
|
||||
s: "xpc 1 2 3",
|
||||
stats: &xfs.Stats{
|
||||
ExtendedPrecision: xfs.ExtendedPrecisionStats{
|
||||
FlushBytes: 1,
|
||||
WriteBytes: 2,
|
||||
ReadBytes: 3,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "fixtures OK",
|
||||
fs: true,
|
||||
stats: &xfs.Stats{
|
||||
ExtentAllocation: xfs.ExtentAllocationStats{
|
||||
ExtentsAllocated: 92447,
|
||||
BlocksAllocated: 97589,
|
||||
ExtentsFreed: 92448,
|
||||
BlocksFreed: 93751,
|
||||
},
|
||||
AllocationBTree: xfs.BTreeStats{
|
||||
Lookups: 0,
|
||||
Compares: 0,
|
||||
RecordsInserted: 0,
|
||||
RecordsDeleted: 0,
|
||||
},
|
||||
BlockMapping: xfs.BlockMappingStats{
|
||||
Reads: 1767055,
|
||||
Writes: 188820,
|
||||
Unmaps: 184891,
|
||||
ExtentListInsertions: 92447,
|
||||
ExtentListDeletions: 92448,
|
||||
ExtentListLookups: 2140766,
|
||||
ExtentListCompares: 0,
|
||||
},
|
||||
BlockMapBTree: xfs.BTreeStats{
|
||||
Lookups: 0,
|
||||
Compares: 0,
|
||||
RecordsInserted: 0,
|
||||
RecordsDeleted: 0,
|
||||
},
|
||||
DirectoryOperation: xfs.DirectoryOperationStats{
|
||||
Lookups: 185039,
|
||||
Creates: 92447,
|
||||
Removes: 92444,
|
||||
Getdents: 136422,
|
||||
},
|
||||
Transaction: xfs.TransactionStats{
|
||||
Sync: 706,
|
||||
Async: 944304,
|
||||
Empty: 0,
|
||||
},
|
||||
InodeOperation: xfs.InodeOperationStats{
|
||||
Attempts: 185045,
|
||||
Found: 58807,
|
||||
Recycle: 0,
|
||||
Missed: 126238,
|
||||
Duplicate: 0,
|
||||
Reclaims: 33637,
|
||||
AttributeChange: 22,
|
||||
},
|
||||
LogOperation: xfs.LogOperationStats{
|
||||
Writes: 2883,
|
||||
Blocks: 113448,
|
||||
NoInternalBuffers: 9,
|
||||
Force: 17360,
|
||||
ForceSleep: 739,
|
||||
},
|
||||
ReadWrite: xfs.ReadWriteStats{
|
||||
Read: 107739,
|
||||
Write: 94045,
|
||||
},
|
||||
AttributeOperation: xfs.AttributeOperationStats{
|
||||
Get: 4,
|
||||
Set: 0,
|
||||
Remove: 0,
|
||||
List: 0,
|
||||
},
|
||||
InodeClustering: xfs.InodeClusteringStats{
|
||||
Iflush: 8677,
|
||||
Flush: 7849,
|
||||
FlushInode: 135802,
|
||||
},
|
||||
Vnode: xfs.VnodeStats{
|
||||
Active: 92601,
|
||||
Allocate: 0,
|
||||
Get: 0,
|
||||
Hold: 0,
|
||||
Release: 92444,
|
||||
Reclaim: 92444,
|
||||
Remove: 92444,
|
||||
Free: 0,
|
||||
},
|
||||
Buffer: xfs.BufferStats{
|
||||
Get: 2666287,
|
||||
Create: 7122,
|
||||
GetLocked: 2659202,
|
||||
GetLockedWaited: 3599,
|
||||
BusyLocked: 2,
|
||||
MissLocked: 7085,
|
||||
PageRetries: 0,
|
||||
PageFound: 10297,
|
||||
GetRead: 7085,
|
||||
},
|
||||
ExtendedPrecision: xfs.ExtendedPrecisionStats{
|
||||
FlushBytes: 399724544,
|
||||
WriteBytes: 92823103,
|
||||
ReadBytes: 86219234,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
var (
|
||||
stats *xfs.Stats
|
||||
err error
|
||||
)
|
||||
|
||||
if tt.s != "" {
|
||||
stats, err = xfs.ParseStats(strings.NewReader(tt.s))
|
||||
}
|
||||
if tt.fs {
|
||||
stats, err = procfs.FS("../fixtures").XFSStats()
|
||||
}
|
||||
|
||||
if tt.invalid && err == nil {
|
||||
t.Error("expected an error, but none occurred")
|
||||
}
|
||||
if !tt.invalid && err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
if want, have := tt.stats, stats; !reflect.DeepEqual(want, have) {
|
||||
t.Errorf("unexpected XFS stats:\nwant:\n%v\nhave:\n%v", want, have)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,3 +1,43 @@
|
|||
# 1.1.1
|
||||
This is a bug fix release.
|
||||
* fix the build break on Solaris
|
||||
* don't drop a whole trace in JSONFormatter when a field param is a function pointer which can not be serialized
|
||||
|
||||
# 1.1.0
|
||||
This new release introduces:
|
||||
* several fixes:
|
||||
* a fix for a race condition on entry formatting
|
||||
* proper cleanup of previously used entries before putting them back in the pool
|
||||
* the extra new line at the end of message in text formatter has been removed
|
||||
* a new global public API to check if a level is activated: IsLevelEnabled
|
||||
* the following methods have been added to the Logger object
|
||||
* IsLevelEnabled
|
||||
* SetFormatter
|
||||
* SetOutput
|
||||
* ReplaceHooks
|
||||
* introduction of go module
|
||||
* an indent configuration for the json formatter
|
||||
* output colour support for windows
|
||||
* the field sort function is now configurable for text formatter
|
||||
* the CLICOLOR and CLICOLOR\_FORCE environment variable support in text formater
|
||||
|
||||
# 1.0.6
|
||||
|
||||
This new release introduces:
|
||||
* a new api WithTime which allows to easily force the time of the log entry
|
||||
which is mostly useful for logger wrapper
|
||||
* a fix reverting the immutability of the entry given as parameter to the hooks
|
||||
a new configuration field of the json formatter in order to put all the fields
|
||||
in a nested dictionnary
|
||||
* a new SetOutput method in the Logger
|
||||
* a new configuration of the textformatter to configure the name of the default keys
|
||||
* a new configuration of the text formatter to disable the level truncation
|
||||
|
||||
# 1.0.5
|
||||
|
||||
* Fix hooks race (#707)
|
||||
* Fix panic deadlock (#695)
|
||||
|
||||
# 1.0.4
|
||||
|
||||
* Fix race when adding hooks (#612)
|
||||
|
|
|
@ -220,7 +220,7 @@ Logrus comes with [built-in hooks](hooks/). Add those, or your custom hook, in
|
|||
```go
|
||||
import (
|
||||
log "github.com/sirupsen/logrus"
|
||||
"gopkg.in/gemnasium/logrus-airbrake-hook.v2" // the package is named "aibrake"
|
||||
"gopkg.in/gemnasium/logrus-airbrake-hook.v2" // the package is named "airbrake"
|
||||
logrus_syslog "github.com/sirupsen/logrus/hooks/syslog"
|
||||
"log/syslog"
|
||||
)
|
||||
|
@ -241,58 +241,8 @@ func init() {
|
|||
```
|
||||
Note: Syslog hook also support connecting to local syslog (Ex. "/dev/log" or "/var/run/syslog" or "/var/run/log"). For the detail, please check the [syslog hook README](hooks/syslog/README.md).
|
||||
|
||||
| Hook | Description |
|
||||
| ----- | ----------- |
|
||||
| [Airbrake "legacy"](https://github.com/gemnasium/logrus-airbrake-legacy-hook) | Send errors to an exception tracking service compatible with the Airbrake API V2. Uses [`airbrake-go`](https://github.com/tobi/airbrake-go) behind the scenes. |
|
||||
| [Airbrake](https://github.com/gemnasium/logrus-airbrake-hook) | Send errors to the Airbrake API V3. Uses the official [`gobrake`](https://github.com/airbrake/gobrake) behind the scenes. |
|
||||
| [Amazon Kinesis](https://github.com/evalphobia/logrus_kinesis) | Hook for logging to [Amazon Kinesis](https://aws.amazon.com/kinesis/) |
|
||||
| [Amqp-Hook](https://github.com/vladoatanasov/logrus_amqp) | Hook for logging to Amqp broker (Like RabbitMQ) |
|
||||
| [AzureTableHook](https://github.com/kpfaulkner/azuretablehook/) | Hook for logging to Azure Table Storage|
|
||||
| [Bugsnag](https://github.com/Shopify/logrus-bugsnag/blob/master/bugsnag.go) | Send errors to the Bugsnag exception tracking service. |
|
||||
| [DeferPanic](https://github.com/deferpanic/dp-logrus) | Hook for logging to DeferPanic |
|
||||
| [Discordrus](https://github.com/kz/discordrus) | Hook for logging to [Discord](https://discordapp.com/) |
|
||||
| [ElasticSearch](https://github.com/sohlich/elogrus) | Hook for logging to ElasticSearch|
|
||||
| [Firehose](https://github.com/beaubrewer/logrus_firehose) | Hook for logging to [Amazon Firehose](https://aws.amazon.com/kinesis/firehose/)
|
||||
| [Fluentd](https://github.com/evalphobia/logrus_fluent) | Hook for logging to fluentd |
|
||||
| [Go-Slack](https://github.com/multiplay/go-slack) | Hook for logging to [Slack](https://slack.com) |
|
||||
| [Graylog](https://github.com/gemnasium/logrus-graylog-hook) | Hook for logging to [Graylog](http://graylog2.org/) |
|
||||
| [Hiprus](https://github.com/nubo/hiprus) | Send errors to a channel in hipchat. |
|
||||
| [Honeybadger](https://github.com/agonzalezro/logrus_honeybadger) | Hook for sending exceptions to Honeybadger |
|
||||
| [InfluxDB](https://github.com/Abramovic/logrus_influxdb) | Hook for logging to influxdb |
|
||||
| [Influxus](http://github.com/vlad-doru/influxus) | Hook for concurrently logging to [InfluxDB](http://influxdata.com/) |
|
||||
| [Journalhook](https://github.com/wercker/journalhook) | Hook for logging to `systemd-journald` |
|
||||
| [KafkaLogrus](https://github.com/tracer0tong/kafkalogrus) | Hook for logging to Kafka |
|
||||
| [LFShook](https://github.com/rifflock/lfshook) | Hook for logging to the local filesystem |
|
||||
| [Logbeat](https://github.com/macandmia/logbeat) | Hook for logging to [Opbeat](https://opbeat.com/) |
|
||||
| [Logentries](https://github.com/jcftang/logentriesrus) | Hook for logging to [Logentries](https://logentries.com/) |
|
||||
| [Logentrus](https://github.com/puddingfactory/logentrus) | Hook for logging to [Logentries](https://logentries.com/) |
|
||||
| [Logmatic.io](https://github.com/logmatic/logmatic-go) | Hook for logging to [Logmatic.io](http://logmatic.io/) |
|
||||
| [Logrusly](https://github.com/sebest/logrusly) | Send logs to [Loggly](https://www.loggly.com/) |
|
||||
| [Logstash](https://github.com/bshuster-repo/logrus-logstash-hook) | Hook for logging to [Logstash](https://www.elastic.co/products/logstash) |
|
||||
| [Mail](https://github.com/zbindenren/logrus_mail) | Hook for sending exceptions via mail |
|
||||
| [Mattermost](https://github.com/shuLhan/mattermost-integration/tree/master/hooks/logrus) | Hook for logging to [Mattermost](https://mattermost.com/) |
|
||||
| [Mongodb](https://github.com/weekface/mgorus) | Hook for logging to mongodb |
|
||||
| [NATS-Hook](https://github.com/rybit/nats_logrus_hook) | Hook for logging to [NATS](https://nats.io) |
|
||||
| [Octokit](https://github.com/dorajistyle/logrus-octokit-hook) | Hook for logging to github via octokit |
|
||||
| [Papertrail](https://github.com/polds/logrus-papertrail-hook) | Send errors to the [Papertrail](https://papertrailapp.com) hosted logging service via UDP. |
|
||||
| [PostgreSQL](https://github.com/gemnasium/logrus-postgresql-hook) | Send logs to [PostgreSQL](http://postgresql.org) |
|
||||
| [Promrus](https://github.com/weaveworks/promrus) | Expose number of log messages as [Prometheus](https://prometheus.io/) metrics |
|
||||
| [Pushover](https://github.com/toorop/logrus_pushover) | Send error via [Pushover](https://pushover.net) |
|
||||
| [Raygun](https://github.com/squirkle/logrus-raygun-hook) | Hook for logging to [Raygun.io](http://raygun.io/) |
|
||||
| [Redis-Hook](https://github.com/rogierlommers/logrus-redis-hook) | Hook for logging to a ELK stack (through Redis) |
|
||||
| [Rollrus](https://github.com/heroku/rollrus) | Hook for sending errors to rollbar |
|
||||
| [Scribe](https://github.com/sagar8192/logrus-scribe-hook) | Hook for logging to [Scribe](https://github.com/facebookarchive/scribe)|
|
||||
| [Sentry](https://github.com/evalphobia/logrus_sentry) | Send errors to the Sentry error logging and aggregation service. |
|
||||
| [Slackrus](https://github.com/johntdyer/slackrus) | Hook for Slack chat. |
|
||||
| [Stackdriver](https://github.com/knq/sdhook) | Hook for logging to [Google Stackdriver](https://cloud.google.com/logging/) |
|
||||
| [Sumorus](https://github.com/doublefree/sumorus) | Hook for logging to [SumoLogic](https://www.sumologic.com/)|
|
||||
| [Syslog](https://github.com/sirupsen/logrus/blob/master/hooks/syslog/syslog.go) | Send errors to remote syslog server. Uses standard library `log/syslog` behind the scenes. |
|
||||
| [Syslog TLS](https://github.com/shinji62/logrus-syslog-ng) | Send errors to remote syslog server with TLS support. |
|
||||
| [Telegram](https://github.com/rossmcdonald/telegram_hook) | Hook for logging errors to [Telegram](https://telegram.org/) |
|
||||
| [TraceView](https://github.com/evalphobia/logrus_appneta) | Hook for logging to [AppNeta TraceView](https://www.appneta.com/products/traceview/) |
|
||||
| [Typetalk](https://github.com/dragon3/logrus-typetalk-hook) | Hook for logging to [Typetalk](https://www.typetalk.in/) |
|
||||
| [logz.io](https://github.com/ripcurld00d/logrus-logzio-hook) | Hook for logging to [logz.io](https://logz.io), a Log as a Service using Logstash |
|
||||
| [SQS-Hook](https://github.com/tsarpaul/logrus_sqs) | Hook for logging to [Amazon Simple Queue Service (SQS)](https://aws.amazon.com/sqs/) |
|
||||
A list of currently known of service hook can be found in this wiki [page](https://github.com/sirupsen/logrus/wiki/Hooks)
|
||||
|
||||
|
||||
#### Level logging
|
||||
|
||||
|
@ -370,6 +320,8 @@ The built-in logging formatters are:
|
|||
field to `true`. To force no colored output even if there is a TTY set the
|
||||
`DisableColors` field to `true`. For Windows, see
|
||||
[github.com/mattn/go-colorable](https://github.com/mattn/go-colorable).
|
||||
* When colors are enabled, levels are truncated to 4 characters by default. To disable
|
||||
truncation set the `DisableLevelTruncation` field to `true`.
|
||||
* All options are listed in the [generated docs](https://godoc.org/github.com/sirupsen/logrus#TextFormatter).
|
||||
* `logrus.JSONFormatter`. Logs fields as JSON.
|
||||
* All options are listed in the [generated docs](https://godoc.org/github.com/sirupsen/logrus#JSONFormatter).
|
||||
|
@ -493,7 +445,7 @@ logrus.RegisterExitHandler(handler)
|
|||
|
||||
#### Thread safety
|
||||
|
||||
By default Logger is protected by mutex for concurrent writes, this mutex is invoked when calling hooks and writing logs.
|
||||
By default, Logger is protected by a mutex for concurrent writes. The mutex is held when calling hooks and writing logs.
|
||||
If you are sure such locking is not needed, you can call logger.SetNoLock() to disable the locking.
|
||||
|
||||
Situation when locking is not needed includes:
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"bytes"
|
||||
"fmt"
|
||||
"os"
|
||||
"reflect"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
@ -41,14 +42,17 @@ type Entry struct {
|
|||
// Message passed to Debug, Info, Warn, Error, Fatal or Panic
|
||||
Message string
|
||||
|
||||
// When formatter is called in entry.log(), an Buffer may be set to entry
|
||||
// When formatter is called in entry.log(), a Buffer may be set to entry
|
||||
Buffer *bytes.Buffer
|
||||
|
||||
// err may contain a field formatting error
|
||||
err string
|
||||
}
|
||||
|
||||
func NewEntry(logger *Logger) *Entry {
|
||||
return &Entry{
|
||||
Logger: logger,
|
||||
// Default is three fields, give a little extra room
|
||||
// Default is five fields, give a little extra room
|
||||
Data: make(Fields, 5),
|
||||
}
|
||||
}
|
||||
|
@ -80,46 +84,52 @@ func (entry *Entry) WithFields(fields Fields) *Entry {
|
|||
for k, v := range entry.Data {
|
||||
data[k] = v
|
||||
}
|
||||
var field_err string
|
||||
for k, v := range fields {
|
||||
data[k] = v
|
||||
if t := reflect.TypeOf(v); t != nil && t.Kind() == reflect.Func {
|
||||
field_err = fmt.Sprintf("can not add field %q", k)
|
||||
if entry.err != "" {
|
||||
field_err = entry.err + ", " + field_err
|
||||
}
|
||||
} else {
|
||||
data[k] = v
|
||||
}
|
||||
}
|
||||
return &Entry{Logger: entry.Logger, Data: data}
|
||||
return &Entry{Logger: entry.Logger, Data: data, Time: entry.Time, err: field_err}
|
||||
}
|
||||
|
||||
// Overrides the time of the Entry.
|
||||
func (entry *Entry) WithTime(t time.Time) *Entry {
|
||||
return &Entry{Logger: entry.Logger, Data: entry.Data, Time: t}
|
||||
}
|
||||
|
||||
// This function is not declared with a pointer value because otherwise
|
||||
// race conditions will occur when using multiple goroutines
|
||||
func (entry Entry) log(level Level, msg string) {
|
||||
var buffer *bytes.Buffer
|
||||
entry.Time = time.Now()
|
||||
|
||||
// Default to now, but allow users to override if they want.
|
||||
//
|
||||
// We don't have to worry about polluting future calls to Entry#log()
|
||||
// with this assignment because this function is declared with a
|
||||
// non-pointer receiver.
|
||||
if entry.Time.IsZero() {
|
||||
entry.Time = time.Now()
|
||||
}
|
||||
|
||||
entry.Level = level
|
||||
entry.Message = msg
|
||||
|
||||
entry.Logger.mu.Lock()
|
||||
err := entry.Logger.Hooks.Fire(level, &entry)
|
||||
entry.Logger.mu.Unlock()
|
||||
if err != nil {
|
||||
entry.Logger.mu.Lock()
|
||||
fmt.Fprintf(os.Stderr, "Failed to fire hook: %v\n", err)
|
||||
entry.Logger.mu.Unlock()
|
||||
}
|
||||
entry.fireHooks()
|
||||
|
||||
buffer = bufferPool.Get().(*bytes.Buffer)
|
||||
buffer.Reset()
|
||||
defer bufferPool.Put(buffer)
|
||||
entry.Buffer = buffer
|
||||
serialized, err := entry.Logger.Formatter.Format(&entry)
|
||||
|
||||
entry.write()
|
||||
|
||||
entry.Buffer = nil
|
||||
if err != nil {
|
||||
entry.Logger.mu.Lock()
|
||||
fmt.Fprintf(os.Stderr, "Failed to obtain reader, %v\n", err)
|
||||
entry.Logger.mu.Unlock()
|
||||
} else {
|
||||
entry.Logger.mu.Lock()
|
||||
_, err = entry.Logger.Out.Write(serialized)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to write to log, %v\n", err)
|
||||
}
|
||||
entry.Logger.mu.Unlock()
|
||||
}
|
||||
|
||||
// To avoid Entry#log() returning a value that only would make sense for
|
||||
// panic() to use in Entry#Panic(), we avoid the allocation by checking
|
||||
|
@ -129,8 +139,31 @@ func (entry Entry) log(level Level, msg string) {
|
|||
}
|
||||
}
|
||||
|
||||
func (entry *Entry) fireHooks() {
|
||||
entry.Logger.mu.Lock()
|
||||
defer entry.Logger.mu.Unlock()
|
||||
err := entry.Logger.Hooks.Fire(entry.Level, entry)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to fire hook: %v\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (entry *Entry) write() {
|
||||
entry.Logger.mu.Lock()
|
||||
defer entry.Logger.mu.Unlock()
|
||||
serialized, err := entry.Logger.Formatter.Format(entry)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to obtain reader, %v\n", err)
|
||||
} else {
|
||||
_, err = entry.Logger.Out.Write(serialized)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to write to log, %v\n", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (entry *Entry) Debug(args ...interface{}) {
|
||||
if entry.Logger.level() >= DebugLevel {
|
||||
if entry.Logger.IsLevelEnabled(DebugLevel) {
|
||||
entry.log(DebugLevel, fmt.Sprint(args...))
|
||||
}
|
||||
}
|
||||
|
@ -140,13 +173,13 @@ func (entry *Entry) Print(args ...interface{}) {
|
|||
}
|
||||
|
||||
func (entry *Entry) Info(args ...interface{}) {
|
||||
if entry.Logger.level() >= InfoLevel {
|
||||
if entry.Logger.IsLevelEnabled(InfoLevel) {
|
||||
entry.log(InfoLevel, fmt.Sprint(args...))
|
||||
}
|
||||
}
|
||||
|
||||
func (entry *Entry) Warn(args ...interface{}) {
|
||||
if entry.Logger.level() >= WarnLevel {
|
||||
if entry.Logger.IsLevelEnabled(WarnLevel) {
|
||||
entry.log(WarnLevel, fmt.Sprint(args...))
|
||||
}
|
||||
}
|
||||
|
@ -156,20 +189,20 @@ func (entry *Entry) Warning(args ...interface{}) {
|
|||
}
|
||||
|
||||
func (entry *Entry) Error(args ...interface{}) {
|
||||
if entry.Logger.level() >= ErrorLevel {
|
||||
if entry.Logger.IsLevelEnabled(ErrorLevel) {
|
||||
entry.log(ErrorLevel, fmt.Sprint(args...))
|
||||
}
|
||||
}
|
||||
|
||||
func (entry *Entry) Fatal(args ...interface{}) {
|
||||
if entry.Logger.level() >= FatalLevel {
|
||||
if entry.Logger.IsLevelEnabled(FatalLevel) {
|
||||
entry.log(FatalLevel, fmt.Sprint(args...))
|
||||
}
|
||||
Exit(1)
|
||||
}
|
||||
|
||||
func (entry *Entry) Panic(args ...interface{}) {
|
||||
if entry.Logger.level() >= PanicLevel {
|
||||
if entry.Logger.IsLevelEnabled(PanicLevel) {
|
||||
entry.log(PanicLevel, fmt.Sprint(args...))
|
||||
}
|
||||
panic(fmt.Sprint(args...))
|
||||
|
@ -178,13 +211,13 @@ func (entry *Entry) Panic(args ...interface{}) {
|
|||
// Entry Printf family functions
|
||||
|
||||
func (entry *Entry) Debugf(format string, args ...interface{}) {
|
||||
if entry.Logger.level() >= DebugLevel {
|
||||
if entry.Logger.IsLevelEnabled(DebugLevel) {
|
||||
entry.Debug(fmt.Sprintf(format, args...))
|
||||
}
|
||||
}
|
||||
|
||||
func (entry *Entry) Infof(format string, args ...interface{}) {
|
||||
if entry.Logger.level() >= InfoLevel {
|
||||
if entry.Logger.IsLevelEnabled(InfoLevel) {
|
||||
entry.Info(fmt.Sprintf(format, args...))
|
||||
}
|
||||
}
|
||||
|
@ -194,7 +227,7 @@ func (entry *Entry) Printf(format string, args ...interface{}) {
|
|||
}
|
||||
|
||||
func (entry *Entry) Warnf(format string, args ...interface{}) {
|
||||
if entry.Logger.level() >= WarnLevel {
|
||||
if entry.Logger.IsLevelEnabled(WarnLevel) {
|
||||
entry.Warn(fmt.Sprintf(format, args...))
|
||||
}
|
||||
}
|
||||
|
@ -204,20 +237,20 @@ func (entry *Entry) Warningf(format string, args ...interface{}) {
|
|||
}
|
||||
|
||||
func (entry *Entry) Errorf(format string, args ...interface{}) {
|
||||
if entry.Logger.level() >= ErrorLevel {
|
||||
if entry.Logger.IsLevelEnabled(ErrorLevel) {
|
||||
entry.Error(fmt.Sprintf(format, args...))
|
||||
}
|
||||
}
|
||||
|
||||
func (entry *Entry) Fatalf(format string, args ...interface{}) {
|
||||
if entry.Logger.level() >= FatalLevel {
|
||||
if entry.Logger.IsLevelEnabled(FatalLevel) {
|
||||
entry.Fatal(fmt.Sprintf(format, args...))
|
||||
}
|
||||
Exit(1)
|
||||
}
|
||||
|
||||
func (entry *Entry) Panicf(format string, args ...interface{}) {
|
||||
if entry.Logger.level() >= PanicLevel {
|
||||
if entry.Logger.IsLevelEnabled(PanicLevel) {
|
||||
entry.Panic(fmt.Sprintf(format, args...))
|
||||
}
|
||||
}
|
||||
|
@ -225,13 +258,13 @@ func (entry *Entry) Panicf(format string, args ...interface{}) {
|
|||
// Entry Println family functions
|
||||
|
||||
func (entry *Entry) Debugln(args ...interface{}) {
|
||||
if entry.Logger.level() >= DebugLevel {
|
||||
if entry.Logger.IsLevelEnabled(DebugLevel) {
|
||||
entry.Debug(entry.sprintlnn(args...))
|
||||
}
|
||||
}
|
||||
|
||||
func (entry *Entry) Infoln(args ...interface{}) {
|
||||
if entry.Logger.level() >= InfoLevel {
|
||||
if entry.Logger.IsLevelEnabled(InfoLevel) {
|
||||
entry.Info(entry.sprintlnn(args...))
|
||||
}
|
||||
}
|
||||
|
@ -241,7 +274,7 @@ func (entry *Entry) Println(args ...interface{}) {
|
|||
}
|
||||
|
||||
func (entry *Entry) Warnln(args ...interface{}) {
|
||||
if entry.Logger.level() >= WarnLevel {
|
||||
if entry.Logger.IsLevelEnabled(WarnLevel) {
|
||||
entry.Warn(entry.sprintlnn(args...))
|
||||
}
|
||||
}
|
||||
|
@ -251,20 +284,20 @@ func (entry *Entry) Warningln(args ...interface{}) {
|
|||
}
|
||||
|
||||
func (entry *Entry) Errorln(args ...interface{}) {
|
||||
if entry.Logger.level() >= ErrorLevel {
|
||||
if entry.Logger.IsLevelEnabled(ErrorLevel) {
|
||||
entry.Error(entry.sprintlnn(args...))
|
||||
}
|
||||
}
|
||||
|
||||
func (entry *Entry) Fatalln(args ...interface{}) {
|
||||
if entry.Logger.level() >= FatalLevel {
|
||||
if entry.Logger.IsLevelEnabled(FatalLevel) {
|
||||
entry.Fatal(entry.sprintlnn(args...))
|
||||
}
|
||||
Exit(1)
|
||||
}
|
||||
|
||||
func (entry *Entry) Panicln(args ...interface{}) {
|
||||
if entry.Logger.level() >= PanicLevel {
|
||||
if entry.Logger.IsLevelEnabled(PanicLevel) {
|
||||
entry.Panic(entry.sprintlnn(args...))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package logrus
|
|||
|
||||
import (
|
||||
"io"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -15,37 +16,32 @@ func StandardLogger() *Logger {
|
|||
|
||||
// SetOutput sets the standard logger output.
|
||||
func SetOutput(out io.Writer) {
|
||||
std.mu.Lock()
|
||||
defer std.mu.Unlock()
|
||||
std.Out = out
|
||||
std.SetOutput(out)
|
||||
}
|
||||
|
||||
// SetFormatter sets the standard logger formatter.
|
||||
func SetFormatter(formatter Formatter) {
|
||||
std.mu.Lock()
|
||||
defer std.mu.Unlock()
|
||||
std.Formatter = formatter
|
||||
std.SetFormatter(formatter)
|
||||
}
|
||||
|
||||
// SetLevel sets the standard logger level.
|
||||
func SetLevel(level Level) {
|
||||
std.mu.Lock()
|
||||
defer std.mu.Unlock()
|
||||
std.SetLevel(level)
|
||||
}
|
||||
|
||||
// GetLevel returns the standard logger level.
|
||||
func GetLevel() Level {
|
||||
std.mu.Lock()
|
||||
defer std.mu.Unlock()
|
||||
return std.level()
|
||||
return std.GetLevel()
|
||||
}
|
||||
|
||||
// IsLevelEnabled checks if the log level of the standard logger is greater than the level param
|
||||
func IsLevelEnabled(level Level) bool {
|
||||
return std.IsLevelEnabled(level)
|
||||
}
|
||||
|
||||
// AddHook adds a hook to the standard logger hooks.
|
||||
func AddHook(hook Hook) {
|
||||
std.mu.Lock()
|
||||
defer std.mu.Unlock()
|
||||
std.Hooks.Add(hook)
|
||||
std.AddHook(hook)
|
||||
}
|
||||
|
||||
// WithError creates an entry from the standard logger and adds an error to it, using the value defined in ErrorKey as key.
|
||||
|
@ -72,6 +68,15 @@ func WithFields(fields Fields) *Entry {
|
|||
return std.WithFields(fields)
|
||||
}
|
||||
|
||||
// WithTime creats an entry from the standard logger and overrides the time of
|
||||
// logs generated with it.
|
||||
//
|
||||
// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal
|
||||
// or Panic on the Entry it returns.
|
||||
func WithTime(t time.Time) *Entry {
|
||||
return std.WithTime(t)
|
||||
}
|
||||
|
||||
// Debug logs a message at level Debug on the standard logger.
|
||||
func Debug(args ...interface{}) {
|
||||
std.Debug(args...)
|
||||
|
@ -107,7 +112,7 @@ func Panic(args ...interface{}) {
|
|||
std.Panic(args...)
|
||||
}
|
||||
|
||||
// Fatal logs a message at level Fatal on the standard logger.
|
||||
// Fatal logs a message at level Fatal on the standard logger then the process will exit with status set to 1.
|
||||
func Fatal(args ...interface{}) {
|
||||
std.Fatal(args...)
|
||||
}
|
||||
|
@ -147,7 +152,7 @@ func Panicf(format string, args ...interface{}) {
|
|||
std.Panicf(format, args...)
|
||||
}
|
||||
|
||||
// Fatalf logs a message at level Fatal on the standard logger.
|
||||
// Fatalf logs a message at level Fatal on the standard logger then the process will exit with status set to 1.
|
||||
func Fatalf(format string, args ...interface{}) {
|
||||
std.Fatalf(format, args...)
|
||||
}
|
||||
|
@ -187,7 +192,7 @@ func Panicln(args ...interface{}) {
|
|||
std.Panicln(args...)
|
||||
}
|
||||
|
||||
// Fatalln logs a message at level Fatal on the standard logger.
|
||||
// Fatalln logs a message at level Fatal on the standard logger then the process will exit with status set to 1.
|
||||
func Fatalln(args ...interface{}) {
|
||||
std.Fatalln(args...)
|
||||
}
|
||||
|
|
|
@ -2,7 +2,14 @@ package logrus
|
|||
|
||||
import "time"
|
||||
|
||||
const defaultTimestampFormat = time.RFC3339
|
||||
// Default key names for the default fields
|
||||
const (
|
||||
defaultTimestampFormat = time.RFC3339
|
||||
FieldKeyMsg = "msg"
|
||||
FieldKeyLevel = "level"
|
||||
FieldKeyTime = "time"
|
||||
FieldKeyLogrusError = "logrus_error"
|
||||
)
|
||||
|
||||
// The Formatter interface is used to implement a custom Formatter. It takes an
|
||||
// `Entry`. It exposes all the fields, including the default ones:
|
||||
|
@ -30,16 +37,28 @@ type Formatter interface {
|
|||
//
|
||||
// It's not exported because it's still using Data in an opinionated way. It's to
|
||||
// avoid code duplication between the two default formatters.
|
||||
func prefixFieldClashes(data Fields) {
|
||||
if t, ok := data["time"]; ok {
|
||||
data["fields.time"] = t
|
||||
func prefixFieldClashes(data Fields, fieldMap FieldMap) {
|
||||
timeKey := fieldMap.resolve(FieldKeyTime)
|
||||
if t, ok := data[timeKey]; ok {
|
||||
data["fields."+timeKey] = t
|
||||
delete(data, timeKey)
|
||||
}
|
||||
|
||||
if m, ok := data["msg"]; ok {
|
||||
data["fields.msg"] = m
|
||||
msgKey := fieldMap.resolve(FieldKeyMsg)
|
||||
if m, ok := data[msgKey]; ok {
|
||||
data["fields."+msgKey] = m
|
||||
delete(data, msgKey)
|
||||
}
|
||||
|
||||
if l, ok := data["level"]; ok {
|
||||
data["fields.level"] = l
|
||||
levelKey := fieldMap.resolve(FieldKeyLevel)
|
||||
if l, ok := data[levelKey]; ok {
|
||||
data["fields."+levelKey] = l
|
||||
delete(data, levelKey)
|
||||
}
|
||||
|
||||
logrusErrKey := fieldMap.resolve(FieldKeyLogrusError)
|
||||
if l, ok := data[logrusErrKey]; ok {
|
||||
data["fields."+logrusErrKey] = l
|
||||
delete(data, logrusErrKey)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
module github.com/sirupsen/logrus
|
||||
|
||||
require (
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/konsorten/go-windows-terminal-sequences v0.0.0-20180402223658-b729f2633dfe
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/stretchr/testify v1.2.2
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33
|
||||
)
|
|
@ -0,0 +1,12 @@
|
|||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/konsorten/go-windows-terminal-sequences v0.0.0-20180402223658-b729f2633dfe h1:CHRGQ8V7OlCYtwaKPJi3iA7J+YdNKdo8j7nG5IgDhjs=
|
||||
github.com/konsorten/go-windows-terminal-sequences v0.0.0-20180402223658-b729f2633dfe/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793 h1:u+LnwYTOOW7Ukr/fppxEb1Nwz0AtPflrblfvUudpo+I=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33 h1:I6FyU15t786LL7oL/hn43zqTuEGr4PN7F4XJ1p4E3Y8=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
@ -1,6 +1,7 @@
|
|||
package logrus
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
)
|
||||
|
@ -10,13 +11,6 @@ type fieldKey string
|
|||
// FieldMap allows customization of the key names for default fields.
|
||||
type FieldMap map[fieldKey]string
|
||||
|
||||
// Default key names for the default fields
|
||||
const (
|
||||
FieldKeyMsg = "msg"
|
||||
FieldKeyLevel = "level"
|
||||
FieldKeyTime = "time"
|
||||
)
|
||||
|
||||
func (f FieldMap) resolve(key fieldKey) string {
|
||||
if k, ok := f[key]; ok {
|
||||
return k
|
||||
|
@ -33,6 +27,9 @@ type JSONFormatter struct {
|
|||
// DisableTimestamp allows disabling automatic timestamps in output
|
||||
DisableTimestamp bool
|
||||
|
||||
// DataKey allows users to put all the log entry parameters into a nested dictionary at a given key.
|
||||
DataKey string
|
||||
|
||||
// FieldMap allows users to customize the names of keys for default fields.
|
||||
// As an example:
|
||||
// formatter := &JSONFormatter{
|
||||
|
@ -43,6 +40,9 @@ type JSONFormatter struct {
|
|||
// },
|
||||
// }
|
||||
FieldMap FieldMap
|
||||
|
||||
// PrettyPrint will indent all json logs
|
||||
PrettyPrint bool
|
||||
}
|
||||
|
||||
// Format renders a single log entry
|
||||
|
@ -58,22 +58,43 @@ func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
|
|||
data[k] = v
|
||||
}
|
||||
}
|
||||
prefixFieldClashes(data)
|
||||
|
||||
if f.DataKey != "" {
|
||||
newData := make(Fields, 4)
|
||||
newData[f.DataKey] = data
|
||||
data = newData
|
||||
}
|
||||
|
||||
prefixFieldClashes(data, f.FieldMap)
|
||||
|
||||
timestampFormat := f.TimestampFormat
|
||||
if timestampFormat == "" {
|
||||
timestampFormat = defaultTimestampFormat
|
||||
}
|
||||
|
||||
if entry.err != "" {
|
||||
data[f.FieldMap.resolve(FieldKeyLogrusError)] = entry.err
|
||||
}
|
||||
if !f.DisableTimestamp {
|
||||
data[f.FieldMap.resolve(FieldKeyTime)] = entry.Time.Format(timestampFormat)
|
||||
}
|
||||
data[f.FieldMap.resolve(FieldKeyMsg)] = entry.Message
|
||||
data[f.FieldMap.resolve(FieldKeyLevel)] = entry.Level.String()
|
||||
|
||||
serialized, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
var b *bytes.Buffer
|
||||
if entry.Buffer != nil {
|
||||
b = entry.Buffer
|
||||
} else {
|
||||
b = &bytes.Buffer{}
|
||||
}
|
||||
|
||||
encoder := json.NewEncoder(b)
|
||||
if f.PrettyPrint {
|
||||
encoder.SetIndent("", " ")
|
||||
}
|
||||
if err := encoder.Encode(data); err != nil {
|
||||
return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err)
|
||||
}
|
||||
return append(serialized, '\n'), nil
|
||||
|
||||
return b.Bytes(), nil
|
||||
}
|
||||
|
|
|
@ -5,12 +5,13 @@ import (
|
|||
"os"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Logger struct {
|
||||
// The logs are `io.Copy`'d to this in a mutex. It's common to set this to a
|
||||
// file, or leave it default which is `os.Stderr`. You can also set this to
|
||||
// something more adventorous, such as logging to Kafka.
|
||||
// something more adventurous, such as logging to Kafka.
|
||||
Out io.Writer
|
||||
// Hooks for the logger instance. These allow firing events based on logging
|
||||
// levels and log entries. For example, to send errors to an error tracking
|
||||
|
@ -84,11 +85,12 @@ func (logger *Logger) newEntry() *Entry {
|
|||
}
|
||||
|
||||
func (logger *Logger) releaseEntry(entry *Entry) {
|
||||
entry.Data = map[string]interface{}{}
|
||||
logger.entryPool.Put(entry)
|
||||
}
|
||||
|
||||
// Adds a field to the log entry, note that it doesn't log until you call
|
||||
// Debug, Print, Info, Warn, Fatal or Panic. It only creates a log entry.
|
||||
// Debug, Print, Info, Warn, Error, Fatal or Panic. It only creates a log entry.
|
||||
// If you want multiple fields, use `WithFields`.
|
||||
func (logger *Logger) WithField(key string, value interface{}) *Entry {
|
||||
entry := logger.newEntry()
|
||||
|
@ -112,8 +114,15 @@ func (logger *Logger) WithError(err error) *Entry {
|
|||
return entry.WithError(err)
|
||||
}
|
||||
|
||||
// Overrides the time of the log entry.
|
||||
func (logger *Logger) WithTime(t time.Time) *Entry {
|
||||
entry := logger.newEntry()
|
||||
defer logger.releaseEntry(entry)
|
||||
return entry.WithTime(t)
|
||||
}
|
||||
|
||||
func (logger *Logger) Debugf(format string, args ...interface{}) {
|
||||
if logger.level() >= DebugLevel {
|
||||
if logger.IsLevelEnabled(DebugLevel) {
|
||||
entry := logger.newEntry()
|
||||
entry.Debugf(format, args...)
|
||||
logger.releaseEntry(entry)
|
||||
|
@ -121,7 +130,7 @@ func (logger *Logger) Debugf(format string, args ...interface{}) {
|
|||
}
|
||||
|
||||
func (logger *Logger) Infof(format string, args ...interface{}) {
|
||||
if logger.level() >= InfoLevel {
|
||||
if logger.IsLevelEnabled(InfoLevel) {
|
||||
entry := logger.newEntry()
|
||||
entry.Infof(format, args...)
|
||||
logger.releaseEntry(entry)
|
||||
|
@ -135,7 +144,7 @@ func (logger *Logger) Printf(format string, args ...interface{}) {
|
|||
}
|
||||
|
||||
func (logger *Logger) Warnf(format string, args ...interface{}) {
|
||||
if logger.level() >= WarnLevel {
|
||||
if logger.IsLevelEnabled(WarnLevel) {
|
||||
entry := logger.newEntry()
|
||||
entry.Warnf(format, args...)
|
||||
logger.releaseEntry(entry)
|
||||
|
@ -143,7 +152,7 @@ func (logger *Logger) Warnf(format string, args ...interface{}) {
|
|||
}
|
||||
|
||||
func (logger *Logger) Warningf(format string, args ...interface{}) {
|
||||
if logger.level() >= WarnLevel {
|
||||
if logger.IsLevelEnabled(WarnLevel) {
|
||||
entry := logger.newEntry()
|
||||
entry.Warnf(format, args...)
|
||||
logger.releaseEntry(entry)
|
||||
|
@ -151,7 +160,7 @@ func (logger *Logger) Warningf(format string, args ...interface{}) {
|
|||
}
|
||||
|
||||
func (logger *Logger) Errorf(format string, args ...interface{}) {
|
||||
if logger.level() >= ErrorLevel {
|
||||
if logger.IsLevelEnabled(ErrorLevel) {
|
||||
entry := logger.newEntry()
|
||||
entry.Errorf(format, args...)
|
||||
logger.releaseEntry(entry)
|
||||
|
@ -159,7 +168,7 @@ func (logger *Logger) Errorf(format string, args ...interface{}) {
|
|||
}
|
||||
|
||||
func (logger *Logger) Fatalf(format string, args ...interface{}) {
|
||||
if logger.level() >= FatalLevel {
|
||||
if logger.IsLevelEnabled(FatalLevel) {
|
||||
entry := logger.newEntry()
|
||||
entry.Fatalf(format, args...)
|
||||
logger.releaseEntry(entry)
|
||||
|
@ -168,7 +177,7 @@ func (logger *Logger) Fatalf(format string, args ...interface{}) {
|
|||
}
|
||||
|
||||
func (logger *Logger) Panicf(format string, args ...interface{}) {
|
||||
if logger.level() >= PanicLevel {
|
||||
if logger.IsLevelEnabled(PanicLevel) {
|
||||
entry := logger.newEntry()
|
||||
entry.Panicf(format, args...)
|
||||
logger.releaseEntry(entry)
|
||||
|
@ -176,7 +185,7 @@ func (logger *Logger) Panicf(format string, args ...interface{}) {
|
|||
}
|
||||
|
||||
func (logger *Logger) Debug(args ...interface{}) {
|
||||
if logger.level() >= DebugLevel {
|
||||
if logger.IsLevelEnabled(DebugLevel) {
|
||||
entry := logger.newEntry()
|
||||
entry.Debug(args...)
|
||||
logger.releaseEntry(entry)
|
||||
|
@ -184,7 +193,7 @@ func (logger *Logger) Debug(args ...interface{}) {
|
|||
}
|
||||
|
||||
func (logger *Logger) Info(args ...interface{}) {
|
||||
if logger.level() >= InfoLevel {
|
||||
if logger.IsLevelEnabled(InfoLevel) {
|
||||
entry := logger.newEntry()
|
||||
entry.Info(args...)
|
||||
logger.releaseEntry(entry)
|
||||
|
@ -198,7 +207,7 @@ func (logger *Logger) Print(args ...interface{}) {
|
|||
}
|
||||
|
||||
func (logger *Logger) Warn(args ...interface{}) {
|
||||
if logger.level() >= WarnLevel {
|
||||
if logger.IsLevelEnabled(WarnLevel) {
|
||||
entry := logger.newEntry()
|
||||
entry.Warn(args...)
|
||||
logger.releaseEntry(entry)
|
||||
|
@ -206,7 +215,7 @@ func (logger *Logger) Warn(args ...interface{}) {
|
|||
}
|
||||
|
||||
func (logger *Logger) Warning(args ...interface{}) {
|
||||
if logger.level() >= WarnLevel {
|
||||
if logger.IsLevelEnabled(WarnLevel) {
|
||||
entry := logger.newEntry()
|
||||
entry.Warn(args...)
|
||||
logger.releaseEntry(entry)
|
||||
|
@ -214,7 +223,7 @@ func (logger *Logger) Warning(args ...interface{}) {
|
|||
}
|
||||
|
||||
func (logger *Logger) Error(args ...interface{}) {
|
||||
if logger.level() >= ErrorLevel {
|
||||
if logger.IsLevelEnabled(ErrorLevel) {
|
||||
entry := logger.newEntry()
|
||||
entry.Error(args...)
|
||||
logger.releaseEntry(entry)
|
||||
|
@ -222,7 +231,7 @@ func (logger *Logger) Error(args ...interface{}) {
|
|||
}
|
||||
|
||||
func (logger *Logger) Fatal(args ...interface{}) {
|
||||
if logger.level() >= FatalLevel {
|
||||
if logger.IsLevelEnabled(FatalLevel) {
|
||||
entry := logger.newEntry()
|
||||
entry.Fatal(args...)
|
||||
logger.releaseEntry(entry)
|
||||
|
@ -231,7 +240,7 @@ func (logger *Logger) Fatal(args ...interface{}) {
|
|||
}
|
||||
|
||||
func (logger *Logger) Panic(args ...interface{}) {
|
||||
if logger.level() >= PanicLevel {
|
||||
if logger.IsLevelEnabled(PanicLevel) {
|
||||
entry := logger.newEntry()
|
||||
entry.Panic(args...)
|
||||
logger.releaseEntry(entry)
|
||||
|
@ -239,7 +248,7 @@ func (logger *Logger) Panic(args ...interface{}) {
|
|||
}
|
||||
|
||||
func (logger *Logger) Debugln(args ...interface{}) {
|
||||
if logger.level() >= DebugLevel {
|
||||
if logger.IsLevelEnabled(DebugLevel) {
|
||||
entry := logger.newEntry()
|
||||
entry.Debugln(args...)
|
||||
logger.releaseEntry(entry)
|
||||
|
@ -247,7 +256,7 @@ func (logger *Logger) Debugln(args ...interface{}) {
|
|||
}
|
||||
|
||||
func (logger *Logger) Infoln(args ...interface{}) {
|
||||
if logger.level() >= InfoLevel {
|
||||
if logger.IsLevelEnabled(InfoLevel) {
|
||||
entry := logger.newEntry()
|
||||
entry.Infoln(args...)
|
||||
logger.releaseEntry(entry)
|
||||
|
@ -261,7 +270,7 @@ func (logger *Logger) Println(args ...interface{}) {
|
|||
}
|
||||
|
||||
func (logger *Logger) Warnln(args ...interface{}) {
|
||||
if logger.level() >= WarnLevel {
|
||||
if logger.IsLevelEnabled(WarnLevel) {
|
||||
entry := logger.newEntry()
|
||||
entry.Warnln(args...)
|
||||
logger.releaseEntry(entry)
|
||||
|
@ -269,7 +278,7 @@ func (logger *Logger) Warnln(args ...interface{}) {
|
|||
}
|
||||
|
||||
func (logger *Logger) Warningln(args ...interface{}) {
|
||||
if logger.level() >= WarnLevel {
|
||||
if logger.IsLevelEnabled(WarnLevel) {
|
||||
entry := logger.newEntry()
|
||||
entry.Warnln(args...)
|
||||
logger.releaseEntry(entry)
|
||||
|
@ -277,7 +286,7 @@ func (logger *Logger) Warningln(args ...interface{}) {
|
|||
}
|
||||
|
||||
func (logger *Logger) Errorln(args ...interface{}) {
|
||||
if logger.level() >= ErrorLevel {
|
||||
if logger.IsLevelEnabled(ErrorLevel) {
|
||||
entry := logger.newEntry()
|
||||
entry.Errorln(args...)
|
||||
logger.releaseEntry(entry)
|
||||
|
@ -285,7 +294,7 @@ func (logger *Logger) Errorln(args ...interface{}) {
|
|||
}
|
||||
|
||||
func (logger *Logger) Fatalln(args ...interface{}) {
|
||||
if logger.level() >= FatalLevel {
|
||||
if logger.IsLevelEnabled(FatalLevel) {
|
||||
entry := logger.newEntry()
|
||||
entry.Fatalln(args...)
|
||||
logger.releaseEntry(entry)
|
||||
|
@ -294,7 +303,7 @@ func (logger *Logger) Fatalln(args ...interface{}) {
|
|||
}
|
||||
|
||||
func (logger *Logger) Panicln(args ...interface{}) {
|
||||
if logger.level() >= PanicLevel {
|
||||
if logger.IsLevelEnabled(PanicLevel) {
|
||||
entry := logger.newEntry()
|
||||
entry.Panicln(args...)
|
||||
logger.releaseEntry(entry)
|
||||
|
@ -312,12 +321,47 @@ func (logger *Logger) level() Level {
|
|||
return Level(atomic.LoadUint32((*uint32)(&logger.Level)))
|
||||
}
|
||||
|
||||
// SetLevel sets the logger level.
|
||||
func (logger *Logger) SetLevel(level Level) {
|
||||
atomic.StoreUint32((*uint32)(&logger.Level), uint32(level))
|
||||
}
|
||||
|
||||
// GetLevel returns the logger level.
|
||||
func (logger *Logger) GetLevel() Level {
|
||||
return logger.level()
|
||||
}
|
||||
|
||||
// AddHook adds a hook to the logger hooks.
|
||||
func (logger *Logger) AddHook(hook Hook) {
|
||||
logger.mu.Lock()
|
||||
defer logger.mu.Unlock()
|
||||
logger.Hooks.Add(hook)
|
||||
}
|
||||
|
||||
// IsLevelEnabled checks if the log level of the logger is greater than the level param
|
||||
func (logger *Logger) IsLevelEnabled(level Level) bool {
|
||||
return logger.level() >= level
|
||||
}
|
||||
|
||||
// SetFormatter sets the logger formatter.
|
||||
func (logger *Logger) SetFormatter(formatter Formatter) {
|
||||
logger.mu.Lock()
|
||||
defer logger.mu.Unlock()
|
||||
logger.Formatter = formatter
|
||||
}
|
||||
|
||||
// SetOutput sets the logger output.
|
||||
func (logger *Logger) SetOutput(output io.Writer) {
|
||||
logger.mu.Lock()
|
||||
defer logger.mu.Unlock()
|
||||
logger.Out = output
|
||||
}
|
||||
|
||||
// ReplaceHooks replaces the logger hooks and returns the old ones
|
||||
func (logger *Logger) ReplaceHooks(hooks LevelHooks) LevelHooks {
|
||||
logger.mu.Lock()
|
||||
oldHooks := logger.Hooks
|
||||
logger.Hooks = hooks
|
||||
logger.mu.Unlock()
|
||||
return oldHooks
|
||||
}
|
||||
|
|
|
@ -140,4 +140,11 @@ type FieldLogger interface {
|
|||
Errorln(args ...interface{})
|
||||
Fatalln(args ...interface{})
|
||||
Panicln(args ...interface{})
|
||||
|
||||
// IsDebugEnabled() bool
|
||||
// IsInfoEnabled() bool
|
||||
// IsWarnEnabled() bool
|
||||
// IsErrorEnabled() bool
|
||||
// IsFatalEnabled() bool
|
||||
// IsPanicEnabled() bool
|
||||
}
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
// +build darwin freebsd openbsd netbsd dragonfly
|
||||
// +build !appengine
|
||||
|
||||
package logrus
|
||||
|
||||
import "golang.org/x/sys/unix"
|
||||
|
||||
const ioctlReadTermios = unix.TIOCGETA
|
||||
|
||||
type Termios unix.Termios
|
|
@ -0,0 +1,11 @@
|
|||
// +build js
|
||||
|
||||
package logrus
|
||||
|
||||
import (
|
||||
"io"
|
||||
)
|
||||
|
||||
func checkIfTerminal(w io.Writer) bool {
|
||||
return false
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
// +build !appengine
|
||||
// +build !appengine,!js,!windows
|
||||
|
||||
package logrus
|
||||
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
// +build !appengine,!js,windows
|
||||
|
||||
package logrus
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func checkIfTerminal(w io.Writer) bool {
|
||||
switch v := w.(type) {
|
||||
case *os.File:
|
||||
var mode uint32
|
||||
err := syscall.GetConsoleMode(syscall.Handle(v.Fd()), &mode)
|
||||
return err == nil
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
// Based on ssh/terminal:
|
||||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build !appengine
|
||||
|
||||
package logrus
|
||||
|
||||
import "golang.org/x/sys/unix"
|
||||
|
||||
const ioctlReadTermios = unix.TCGETS
|
||||
|
||||
type Termios unix.Termios
|
|
@ -0,0 +1,8 @@
|
|||
// +build !windows
|
||||
|
||||
package logrus
|
||||
|
||||
import "io"
|
||||
|
||||
func initTerminal(w io.Writer) {
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
// +build !appengine,!js,windows
|
||||
|
||||
package logrus
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
"syscall"
|
||||
|
||||
sequences "github.com/konsorten/go-windows-terminal-sequences"
|
||||
)
|
||||
|
||||
func initTerminal(w io.Writer) {
|
||||
switch v := w.(type) {
|
||||
case *os.File:
|
||||
sequences.EnableVirtualTerminalProcessing(syscall.Handle(v.Fd()), true)
|
||||
}
|
||||
}
|
|
@ -3,6 +3,7 @@ package logrus
|
|||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
|
@ -20,6 +21,7 @@ const (
|
|||
|
||||
var (
|
||||
baseTimestamp time.Time
|
||||
emptyFieldMap FieldMap
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
@ -34,6 +36,9 @@ type TextFormatter struct {
|
|||
// Force disabling colors.
|
||||
DisableColors bool
|
||||
|
||||
// Override coloring based on CLICOLOR and CLICOLOR_FORCE. - https://bixense.com/clicolors/
|
||||
EnvironmentOverrideColors bool
|
||||
|
||||
// Disable timestamp logging. useful when output is redirected to logging
|
||||
// system that already adds timestamps.
|
||||
DisableTimestamp bool
|
||||
|
@ -50,60 +55,124 @@ type TextFormatter struct {
|
|||
// be desired.
|
||||
DisableSorting bool
|
||||
|
||||
// The keys sorting function, when uninitialized it uses sort.Strings.
|
||||
SortingFunc func([]string)
|
||||
|
||||
// Disables the truncation of the level text to 4 characters.
|
||||
DisableLevelTruncation bool
|
||||
|
||||
// QuoteEmptyFields will wrap empty fields in quotes if true
|
||||
QuoteEmptyFields bool
|
||||
|
||||
// Whether the logger's out is to a terminal
|
||||
isTerminal bool
|
||||
|
||||
sync.Once
|
||||
// FieldMap allows users to customize the names of keys for default fields.
|
||||
// As an example:
|
||||
// formatter := &TextFormatter{
|
||||
// FieldMap: FieldMap{
|
||||
// FieldKeyTime: "@timestamp",
|
||||
// FieldKeyLevel: "@level",
|
||||
// FieldKeyMsg: "@message"}}
|
||||
FieldMap FieldMap
|
||||
|
||||
terminalInitOnce sync.Once
|
||||
}
|
||||
|
||||
func (f *TextFormatter) init(entry *Entry) {
|
||||
if entry.Logger != nil {
|
||||
f.isTerminal = checkIfTerminal(entry.Logger.Out)
|
||||
|
||||
if f.isTerminal {
|
||||
initTerminal(entry.Logger.Out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (f *TextFormatter) isColored() bool {
|
||||
isColored := f.ForceColors || f.isTerminal
|
||||
|
||||
if f.EnvironmentOverrideColors {
|
||||
if force, ok := os.LookupEnv("CLICOLOR_FORCE"); ok && force != "0" {
|
||||
isColored = true
|
||||
} else if ok && force == "0" {
|
||||
isColored = false
|
||||
} else if os.Getenv("CLICOLOR") == "0" {
|
||||
isColored = false
|
||||
}
|
||||
}
|
||||
|
||||
return isColored && !f.DisableColors
|
||||
}
|
||||
|
||||
// Format renders a single log entry
|
||||
func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
|
||||
var b *bytes.Buffer
|
||||
prefixFieldClashes(entry.Data, f.FieldMap)
|
||||
|
||||
keys := make([]string, 0, len(entry.Data))
|
||||
for k := range entry.Data {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
|
||||
if !f.DisableSorting {
|
||||
sort.Strings(keys)
|
||||
fixedKeys := make([]string, 0, 4+len(entry.Data))
|
||||
if !f.DisableTimestamp {
|
||||
fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyTime))
|
||||
}
|
||||
fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyLevel))
|
||||
if entry.Message != "" {
|
||||
fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyMsg))
|
||||
}
|
||||
if entry.err != "" {
|
||||
fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyLogrusError))
|
||||
}
|
||||
|
||||
if !f.DisableSorting {
|
||||
if f.SortingFunc == nil {
|
||||
sort.Strings(keys)
|
||||
fixedKeys = append(fixedKeys, keys...)
|
||||
} else {
|
||||
if !f.isColored() {
|
||||
fixedKeys = append(fixedKeys, keys...)
|
||||
f.SortingFunc(fixedKeys)
|
||||
} else {
|
||||
f.SortingFunc(keys)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
fixedKeys = append(fixedKeys, keys...)
|
||||
}
|
||||
|
||||
var b *bytes.Buffer
|
||||
if entry.Buffer != nil {
|
||||
b = entry.Buffer
|
||||
} else {
|
||||
b = &bytes.Buffer{}
|
||||
}
|
||||
|
||||
prefixFieldClashes(entry.Data)
|
||||
|
||||
f.Do(func() { f.init(entry) })
|
||||
|
||||
isColored := (f.ForceColors || f.isTerminal) && !f.DisableColors
|
||||
f.terminalInitOnce.Do(func() { f.init(entry) })
|
||||
|
||||
timestampFormat := f.TimestampFormat
|
||||
if timestampFormat == "" {
|
||||
timestampFormat = defaultTimestampFormat
|
||||
}
|
||||
if isColored {
|
||||
if f.isColored() {
|
||||
f.printColored(b, entry, keys, timestampFormat)
|
||||
} else {
|
||||
if !f.DisableTimestamp {
|
||||
f.appendKeyValue(b, "time", entry.Time.Format(timestampFormat))
|
||||
}
|
||||
f.appendKeyValue(b, "level", entry.Level.String())
|
||||
if entry.Message != "" {
|
||||
f.appendKeyValue(b, "msg", entry.Message)
|
||||
}
|
||||
for _, key := range keys {
|
||||
f.appendKeyValue(b, key, entry.Data[key])
|
||||
for _, key := range fixedKeys {
|
||||
var value interface{}
|
||||
switch key {
|
||||
case f.FieldMap.resolve(FieldKeyTime):
|
||||
value = entry.Time.Format(timestampFormat)
|
||||
case f.FieldMap.resolve(FieldKeyLevel):
|
||||
value = entry.Level.String()
|
||||
case f.FieldMap.resolve(FieldKeyMsg):
|
||||
value = entry.Message
|
||||
case f.FieldMap.resolve(FieldKeyLogrusError):
|
||||
value = entry.err
|
||||
default:
|
||||
value = entry.Data[key]
|
||||
}
|
||||
f.appendKeyValue(b, key, value)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -124,7 +193,14 @@ func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []strin
|
|||
levelColor = blue
|
||||
}
|
||||
|
||||
levelText := strings.ToUpper(entry.Level.String())[0:4]
|
||||
levelText := strings.ToUpper(entry.Level.String())
|
||||
if !f.DisableLevelTruncation {
|
||||
levelText = levelText[0:4]
|
||||
}
|
||||
|
||||
// Remove a single newline if it already exists in the message to keep
|
||||
// the behavior of logrus text_formatter the same as the stdlib log package
|
||||
entry.Message = strings.TrimSuffix(entry.Message, "\n")
|
||||
|
||||
if f.DisableTimestamp {
|
||||
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m %-44s ", levelColor, levelText, entry.Message)
|
||||
|
|
|
@ -108,9 +108,7 @@ func ReadPassword(fd int) ([]byte, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
unix.IoctlSetTermios(fd, ioctlWriteTermios, termios)
|
||||
}()
|
||||
defer unix.IoctlSetTermios(fd, ioctlWriteTermios, termios)
|
||||
|
||||
return readPasswordLine(passwordReader(fd))
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ import (
|
|||
|
||||
// State contains the state of a terminal.
|
||||
type State struct {
|
||||
state *unix.Termios
|
||||
termios unix.Termios
|
||||
}
|
||||
|
||||
// IsTerminal returns true if the given file descriptor is a terminal.
|
||||
|
@ -75,47 +75,43 @@ func ReadPassword(fd int) ([]byte, error) {
|
|||
// restored.
|
||||
// see http://cr.illumos.org/~webrev/andy_js/1060/
|
||||
func MakeRaw(fd int) (*State, error) {
|
||||
oldTermiosPtr, err := unix.IoctlGetTermios(fd, unix.TCGETS)
|
||||
termios, err := unix.IoctlGetTermios(fd, unix.TCGETS)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
oldTermios := *oldTermiosPtr
|
||||
|
||||
newTermios := oldTermios
|
||||
newTermios.Iflag &^= syscall.IGNBRK | syscall.BRKINT | syscall.PARMRK | syscall.ISTRIP | syscall.INLCR | syscall.IGNCR | syscall.ICRNL | syscall.IXON
|
||||
newTermios.Oflag &^= syscall.OPOST
|
||||
newTermios.Lflag &^= syscall.ECHO | syscall.ECHONL | syscall.ICANON | syscall.ISIG | syscall.IEXTEN
|
||||
newTermios.Cflag &^= syscall.CSIZE | syscall.PARENB
|
||||
newTermios.Cflag |= syscall.CS8
|
||||
newTermios.Cc[unix.VMIN] = 1
|
||||
newTermios.Cc[unix.VTIME] = 0
|
||||
oldState := State{termios: *termios}
|
||||
|
||||
if err := unix.IoctlSetTermios(fd, unix.TCSETS, &newTermios); err != nil {
|
||||
termios.Iflag &^= unix.IGNBRK | unix.BRKINT | unix.PARMRK | unix.ISTRIP | unix.INLCR | unix.IGNCR | unix.ICRNL | unix.IXON
|
||||
termios.Oflag &^= unix.OPOST
|
||||
termios.Lflag &^= unix.ECHO | unix.ECHONL | unix.ICANON | unix.ISIG | unix.IEXTEN
|
||||
termios.Cflag &^= unix.CSIZE | unix.PARENB
|
||||
termios.Cflag |= unix.CS8
|
||||
termios.Cc[unix.VMIN] = 1
|
||||
termios.Cc[unix.VTIME] = 0
|
||||
|
||||
if err := unix.IoctlSetTermios(fd, unix.TCSETS, termios); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &State{
|
||||
state: oldTermiosPtr,
|
||||
}, nil
|
||||
return &oldState, nil
|
||||
}
|
||||
|
||||
// Restore restores the terminal connected to the given file descriptor to a
|
||||
// previous state.
|
||||
func Restore(fd int, oldState *State) error {
|
||||
return unix.IoctlSetTermios(fd, unix.TCSETS, oldState.state)
|
||||
return unix.IoctlSetTermios(fd, unix.TCSETS, &oldState.termios)
|
||||
}
|
||||
|
||||
// GetState returns the current state of a terminal which may be useful to
|
||||
// restore the terminal after a signal.
|
||||
func GetState(fd int) (*State, error) {
|
||||
oldTermiosPtr, err := unix.IoctlGetTermios(fd, unix.TCGETS)
|
||||
termios, err := unix.IoctlGetTermios(fd, unix.TCGETS)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &State{
|
||||
state: oldTermiosPtr,
|
||||
}, nil
|
||||
return &State{termios: *termios}, nil
|
||||
}
|
||||
|
||||
// GetSize returns the dimensions of the given terminal.
|
||||
|
|
|
@ -89,9 +89,7 @@ func ReadPassword(fd int) ([]byte, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
windows.SetConsoleMode(windows.Handle(fd), old)
|
||||
}()
|
||||
defer windows.SetConsoleMode(windows.Handle(fd), old)
|
||||
|
||||
var h windows.Handle
|
||||
p, _ := windows.GetCurrentProcess()
|
||||
|
|
|
@ -198,7 +198,7 @@ func (a LoadConstant) Assemble() (RawInstruction, error) {
|
|||
return assembleLoad(a.Dst, 4, opAddrModeImmediate, a.Val)
|
||||
}
|
||||
|
||||
// String returns the the instruction in assembler notation.
|
||||
// String returns the instruction in assembler notation.
|
||||
func (a LoadConstant) String() string {
|
||||
switch a.Dst {
|
||||
case RegA:
|
||||
|
@ -224,7 +224,7 @@ func (a LoadScratch) Assemble() (RawInstruction, error) {
|
|||
return assembleLoad(a.Dst, 4, opAddrModeScratch, uint32(a.N))
|
||||
}
|
||||
|
||||
// String returns the the instruction in assembler notation.
|
||||
// String returns the instruction in assembler notation.
|
||||
func (a LoadScratch) String() string {
|
||||
switch a.Dst {
|
||||
case RegA:
|
||||
|
@ -248,7 +248,7 @@ func (a LoadAbsolute) Assemble() (RawInstruction, error) {
|
|||
return assembleLoad(RegA, a.Size, opAddrModeAbsolute, a.Off)
|
||||
}
|
||||
|
||||
// String returns the the instruction in assembler notation.
|
||||
// String returns the instruction in assembler notation.
|
||||
func (a LoadAbsolute) String() string {
|
||||
switch a.Size {
|
||||
case 1: // byte
|
||||
|
@ -277,7 +277,7 @@ func (a LoadIndirect) Assemble() (RawInstruction, error) {
|
|||
return assembleLoad(RegA, a.Size, opAddrModeIndirect, a.Off)
|
||||
}
|
||||
|
||||
// String returns the the instruction in assembler notation.
|
||||
// String returns the instruction in assembler notation.
|
||||
func (a LoadIndirect) String() string {
|
||||
switch a.Size {
|
||||
case 1: // byte
|
||||
|
@ -306,7 +306,7 @@ func (a LoadMemShift) Assemble() (RawInstruction, error) {
|
|||
return assembleLoad(RegX, 1, opAddrModeMemShift, a.Off)
|
||||
}
|
||||
|
||||
// String returns the the instruction in assembler notation.
|
||||
// String returns the instruction in assembler notation.
|
||||
func (a LoadMemShift) String() string {
|
||||
return fmt.Sprintf("ldx 4*([%d]&0xf)", a.Off)
|
||||
}
|
||||
|
@ -325,7 +325,7 @@ func (a LoadExtension) Assemble() (RawInstruction, error) {
|
|||
return assembleLoad(RegA, 4, opAddrModeAbsolute, uint32(extOffset+a.Num))
|
||||
}
|
||||
|
||||
// String returns the the instruction in assembler notation.
|
||||
// String returns the instruction in assembler notation.
|
||||
func (a LoadExtension) String() string {
|
||||
switch a.Num {
|
||||
case ExtLen:
|
||||
|
@ -392,7 +392,7 @@ func (a StoreScratch) Assemble() (RawInstruction, error) {
|
|||
}, nil
|
||||
}
|
||||
|
||||
// String returns the the instruction in assembler notation.
|
||||
// String returns the instruction in assembler notation.
|
||||
func (a StoreScratch) String() string {
|
||||
switch a.Src {
|
||||
case RegA:
|
||||
|
@ -418,7 +418,7 @@ func (a ALUOpConstant) Assemble() (RawInstruction, error) {
|
|||
}, nil
|
||||
}
|
||||
|
||||
// String returns the the instruction in assembler notation.
|
||||
// String returns the instruction in assembler notation.
|
||||
func (a ALUOpConstant) String() string {
|
||||
switch a.Op {
|
||||
case ALUOpAdd:
|
||||
|
@ -458,7 +458,7 @@ func (a ALUOpX) Assemble() (RawInstruction, error) {
|
|||
}, nil
|
||||
}
|
||||
|
||||
// String returns the the instruction in assembler notation.
|
||||
// String returns the instruction in assembler notation.
|
||||
func (a ALUOpX) String() string {
|
||||
switch a.Op {
|
||||
case ALUOpAdd:
|
||||
|
@ -496,7 +496,7 @@ func (a NegateA) Assemble() (RawInstruction, error) {
|
|||
}, nil
|
||||
}
|
||||
|
||||
// String returns the the instruction in assembler notation.
|
||||
// String returns the instruction in assembler notation.
|
||||
func (a NegateA) String() string {
|
||||
return fmt.Sprintf("neg")
|
||||
}
|
||||
|
@ -514,7 +514,7 @@ func (a Jump) Assemble() (RawInstruction, error) {
|
|||
}, nil
|
||||
}
|
||||
|
||||
// String returns the the instruction in assembler notation.
|
||||
// String returns the instruction in assembler notation.
|
||||
func (a Jump) String() string {
|
||||
return fmt.Sprintf("ja %d", a.Skip)
|
||||
}
|
||||
|
@ -566,7 +566,7 @@ func (a JumpIf) Assemble() (RawInstruction, error) {
|
|||
}, nil
|
||||
}
|
||||
|
||||
// String returns the the instruction in assembler notation.
|
||||
// String returns the instruction in assembler notation.
|
||||
func (a JumpIf) String() string {
|
||||
switch a.Cond {
|
||||
// K == A
|
||||
|
@ -621,7 +621,7 @@ func (a RetA) Assemble() (RawInstruction, error) {
|
|||
}, nil
|
||||
}
|
||||
|
||||
// String returns the the instruction in assembler notation.
|
||||
// String returns the instruction in assembler notation.
|
||||
func (a RetA) String() string {
|
||||
return fmt.Sprintf("ret a")
|
||||
}
|
||||
|
@ -639,7 +639,7 @@ func (a RetConstant) Assemble() (RawInstruction, error) {
|
|||
}, nil
|
||||
}
|
||||
|
||||
// String returns the the instruction in assembler notation.
|
||||
// String returns the instruction in assembler notation.
|
||||
func (a RetConstant) String() string {
|
||||
return fmt.Sprintf("ret #%d", a.Val)
|
||||
}
|
||||
|
@ -654,7 +654,7 @@ func (a TXA) Assemble() (RawInstruction, error) {
|
|||
}, nil
|
||||
}
|
||||
|
||||
// String returns the the instruction in assembler notation.
|
||||
// String returns the instruction in assembler notation.
|
||||
func (a TXA) String() string {
|
||||
return fmt.Sprintf("txa")
|
||||
}
|
||||
|
@ -669,7 +669,7 @@ func (a TAX) Assemble() (RawInstruction, error) {
|
|||
}, nil
|
||||
}
|
||||
|
||||
// String returns the the instruction in assembler notation.
|
||||
// String returns the instruction in assembler notation.
|
||||
func (a TAX) String() string {
|
||||
return fmt.Sprintf("tax")
|
||||
}
|
||||
|
|
|
@ -1,44 +1,40 @@
|
|||
// go generate gen.go
|
||||
// GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
|
||||
// Code generated by the command above; DO NOT EDIT.
|
||||
|
||||
// Package iana provides protocol number resources managed by the Internet Assigned Numbers Authority (IANA).
|
||||
package iana // import "golang.org/x/net/internal/iana"
|
||||
|
||||
// Differentiated Services Field Codepoints (DSCP), Updated: 2017-05-12
|
||||
// Differentiated Services Field Codepoints (DSCP), Updated: 2018-05-04
|
||||
const (
|
||||
DiffServCS0 = 0x0 // CS0
|
||||
DiffServCS1 = 0x20 // CS1
|
||||
DiffServCS2 = 0x40 // CS2
|
||||
DiffServCS3 = 0x60 // CS3
|
||||
DiffServCS4 = 0x80 // CS4
|
||||
DiffServCS5 = 0xa0 // CS5
|
||||
DiffServCS6 = 0xc0 // CS6
|
||||
DiffServCS7 = 0xe0 // CS7
|
||||
DiffServAF11 = 0x28 // AF11
|
||||
DiffServAF12 = 0x30 // AF12
|
||||
DiffServAF13 = 0x38 // AF13
|
||||
DiffServAF21 = 0x48 // AF21
|
||||
DiffServAF22 = 0x50 // AF22
|
||||
DiffServAF23 = 0x58 // AF23
|
||||
DiffServAF31 = 0x68 // AF31
|
||||
DiffServAF32 = 0x70 // AF32
|
||||
DiffServAF33 = 0x78 // AF33
|
||||
DiffServAF41 = 0x88 // AF41
|
||||
DiffServAF42 = 0x90 // AF42
|
||||
DiffServAF43 = 0x98 // AF43
|
||||
DiffServEF = 0xb8 // EF
|
||||
DiffServVOICEADMIT = 0xb0 // VOICE-ADMIT
|
||||
DiffServCS0 = 0x00 // CS0
|
||||
DiffServCS1 = 0x20 // CS1
|
||||
DiffServCS2 = 0x40 // CS2
|
||||
DiffServCS3 = 0x60 // CS3
|
||||
DiffServCS4 = 0x80 // CS4
|
||||
DiffServCS5 = 0xa0 // CS5
|
||||
DiffServCS6 = 0xc0 // CS6
|
||||
DiffServCS7 = 0xe0 // CS7
|
||||
DiffServAF11 = 0x28 // AF11
|
||||
DiffServAF12 = 0x30 // AF12
|
||||
DiffServAF13 = 0x38 // AF13
|
||||
DiffServAF21 = 0x48 // AF21
|
||||
DiffServAF22 = 0x50 // AF22
|
||||
DiffServAF23 = 0x58 // AF23
|
||||
DiffServAF31 = 0x68 // AF31
|
||||
DiffServAF32 = 0x70 // AF32
|
||||
DiffServAF33 = 0x78 // AF33
|
||||
DiffServAF41 = 0x88 // AF41
|
||||
DiffServAF42 = 0x90 // AF42
|
||||
DiffServAF43 = 0x98 // AF43
|
||||
DiffServEF = 0xb8 // EF
|
||||
DiffServVOICEADMIT = 0xb0 // VOICE-ADMIT
|
||||
NotECNTransport = 0x00 // Not-ECT (Not ECN-Capable Transport)
|
||||
ECNTransport1 = 0x01 // ECT(1) (ECN-Capable Transport(1))
|
||||
ECNTransport0 = 0x02 // ECT(0) (ECN-Capable Transport(0))
|
||||
CongestionExperienced = 0x03 // CE (Congestion Experienced)
|
||||
)
|
||||
|
||||
// IPv4 TOS Byte and IPv6 Traffic Class Octet, Updated: 2001-09-06
|
||||
const (
|
||||
NotECNTransport = 0x0 // Not-ECT (Not ECN-Capable Transport)
|
||||
ECNTransport1 = 0x1 // ECT(1) (ECN-Capable Transport(1))
|
||||
ECNTransport0 = 0x2 // ECT(0) (ECN-Capable Transport(0))
|
||||
CongestionExperienced = 0x3 // CE (Congestion Experienced)
|
||||
)
|
||||
|
||||
// Protocol Numbers, Updated: 2016-06-22
|
||||
// Protocol Numbers, Updated: 2017-10-13
|
||||
const (
|
||||
ProtocolIP = 0 // IPv4 encapsulation, pseudo protocol number
|
||||
ProtocolHOPOPT = 0 // IPv6 Hop-by-Hop Option
|
||||
|
@ -178,3 +174,50 @@ const (
|
|||
ProtocolROHC = 142 // Robust Header Compression
|
||||
ProtocolReserved = 255 // Reserved
|
||||
)
|
||||
|
||||
// Address Family Numbers, Updated: 2018-04-02
|
||||
const (
|
||||
AddrFamilyIPv4 = 1 // IP (IP version 4)
|
||||
AddrFamilyIPv6 = 2 // IP6 (IP version 6)
|
||||
AddrFamilyNSAP = 3 // NSAP
|
||||
AddrFamilyHDLC = 4 // HDLC (8-bit multidrop)
|
||||
AddrFamilyBBN1822 = 5 // BBN 1822
|
||||
AddrFamily802 = 6 // 802 (includes all 802 media plus Ethernet "canonical format")
|
||||
AddrFamilyE163 = 7 // E.163
|
||||
AddrFamilyE164 = 8 // E.164 (SMDS, Frame Relay, ATM)
|
||||
AddrFamilyF69 = 9 // F.69 (Telex)
|
||||
AddrFamilyX121 = 10 // X.121 (X.25, Frame Relay)
|
||||
AddrFamilyIPX = 11 // IPX
|
||||
AddrFamilyAppletalk = 12 // Appletalk
|
||||
AddrFamilyDecnetIV = 13 // Decnet IV
|
||||
AddrFamilyBanyanVines = 14 // Banyan Vines
|
||||
AddrFamilyE164withSubaddress = 15 // E.164 with NSAP format subaddress
|
||||
AddrFamilyDNS = 16 // DNS (Domain Name System)
|
||||
AddrFamilyDistinguishedName = 17 // Distinguished Name
|
||||
AddrFamilyASNumber = 18 // AS Number
|
||||
AddrFamilyXTPoverIPv4 = 19 // XTP over IP version 4
|
||||
AddrFamilyXTPoverIPv6 = 20 // XTP over IP version 6
|
||||
AddrFamilyXTPnativemodeXTP = 21 // XTP native mode XTP
|
||||
AddrFamilyFibreChannelWorldWidePortName = 22 // Fibre Channel World-Wide Port Name
|
||||
AddrFamilyFibreChannelWorldWideNodeName = 23 // Fibre Channel World-Wide Node Name
|
||||
AddrFamilyGWID = 24 // GWID
|
||||
AddrFamilyL2VPN = 25 // AFI for L2VPN information
|
||||
AddrFamilyMPLSTPSectionEndpointID = 26 // MPLS-TP Section Endpoint Identifier
|
||||
AddrFamilyMPLSTPLSPEndpointID = 27 // MPLS-TP LSP Endpoint Identifier
|
||||
AddrFamilyMPLSTPPseudowireEndpointID = 28 // MPLS-TP Pseudowire Endpoint Identifier
|
||||
AddrFamilyMTIPv4 = 29 // MT IP: Multi-Topology IP version 4
|
||||
AddrFamilyMTIPv6 = 30 // MT IPv6: Multi-Topology IP version 6
|
||||
AddrFamilyEIGRPCommonServiceFamily = 16384 // EIGRP Common Service Family
|
||||
AddrFamilyEIGRPIPv4ServiceFamily = 16385 // EIGRP IPv4 Service Family
|
||||
AddrFamilyEIGRPIPv6ServiceFamily = 16386 // EIGRP IPv6 Service Family
|
||||
AddrFamilyLISPCanonicalAddressFormat = 16387 // LISP Canonical Address Format (LCAF)
|
||||
AddrFamilyBGPLS = 16388 // BGP-LS
|
||||
AddrFamily48bitMAC = 16389 // 48-bit MAC
|
||||
AddrFamily64bitMAC = 16390 // 64-bit MAC
|
||||
AddrFamilyOUI = 16391 // OUI
|
||||
AddrFamilyMACFinal24bits = 16392 // MAC/24
|
||||
AddrFamilyMACFinal40bits = 16393 // MAC/40
|
||||
AddrFamilyIPv6Initial64bits = 16394 // IPv6/64
|
||||
AddrFamilyRBridgePortID = 16395 // RBridge Port ID
|
||||
AddrFamilyTRILLNickname = 16396 // TRILL Nickname
|
||||
)
|
||||
|
|
|
@ -26,6 +26,11 @@ type msghdr struct {
|
|||
Flags int32
|
||||
}
|
||||
|
||||
type mmsghdr struct {
|
||||
Hdr msghdr
|
||||
Len uint32
|
||||
}
|
||||
|
||||
type cmsghdr struct {
|
||||
Len uint32
|
||||
Level int32
|
||||
|
@ -52,6 +57,7 @@ type sockaddrInet6 struct {
|
|||
const (
|
||||
sizeofIovec = 0x8
|
||||
sizeofMsghdr = 0x1c
|
||||
sizeofMmsghdr = 0x20
|
||||
sizeofCmsghdr = 0xc
|
||||
|
||||
sizeofSockaddrInet = 0x10
|
||||
|
|
|
@ -9,7 +9,6 @@ package ipv4
|
|||
import (
|
||||
"net"
|
||||
"runtime"
|
||||
"syscall"
|
||||
|
||||
"golang.org/x/net/internal/socket"
|
||||
)
|
||||
|
@ -76,7 +75,7 @@ type Message = socket.Message
|
|||
// headers.
|
||||
func (c *payloadHandler) ReadBatch(ms []Message, flags int) (int, error) {
|
||||
if !c.ok() {
|
||||
return 0, syscall.EINVAL
|
||||
return 0, errInvalidConn
|
||||
}
|
||||
switch runtime.GOOS {
|
||||
case "linux":
|
||||
|
@ -107,7 +106,7 @@ func (c *payloadHandler) ReadBatch(ms []Message, flags int) (int, error) {
|
|||
// On other platforms, this method will write only a single message.
|
||||
func (c *payloadHandler) WriteBatch(ms []Message, flags int) (int, error) {
|
||||
if !c.ok() {
|
||||
return 0, syscall.EINVAL
|
||||
return 0, errInvalidConn
|
||||
}
|
||||
switch runtime.GOOS {
|
||||
case "linux":
|
||||
|
@ -139,7 +138,7 @@ func (c *payloadHandler) WriteBatch(ms []Message, flags int) (int, error) {
|
|||
// On other platforms, this method will read only a single message.
|
||||
func (c *packetHandler) ReadBatch(ms []Message, flags int) (int, error) {
|
||||
if !c.ok() {
|
||||
return 0, syscall.EINVAL
|
||||
return 0, errInvalidConn
|
||||
}
|
||||
switch runtime.GOOS {
|
||||
case "linux":
|
||||
|
@ -170,7 +169,7 @@ func (c *packetHandler) ReadBatch(ms []Message, flags int) (int, error) {
|
|||
// On other platforms, this method will write only a single message.
|
||||
func (c *packetHandler) WriteBatch(ms []Message, flags int) (int, error) {
|
||||
if !c.ok() {
|
||||
return 0, syscall.EINVAL
|
||||
return 0, errInvalidConn
|
||||
}
|
||||
switch runtime.GOOS {
|
||||
case "linux":
|
||||
|
|
|
@ -6,7 +6,6 @@ package ipv4
|
|||
|
||||
import (
|
||||
"net"
|
||||
"syscall"
|
||||
|
||||
"golang.org/x/net/bpf"
|
||||
)
|
||||
|
@ -15,7 +14,7 @@ import (
|
|||
// multicast packets.
|
||||
func (c *dgramOpt) MulticastTTL() (int, error) {
|
||||
if !c.ok() {
|
||||
return 0, syscall.EINVAL
|
||||
return 0, errInvalidConn
|
||||
}
|
||||
so, ok := sockOpts[ssoMulticastTTL]
|
||||
if !ok {
|
||||
|
@ -28,7 +27,7 @@ func (c *dgramOpt) MulticastTTL() (int, error) {
|
|||
// outgoing multicast packets.
|
||||
func (c *dgramOpt) SetMulticastTTL(ttl int) error {
|
||||
if !c.ok() {
|
||||
return syscall.EINVAL
|
||||
return errInvalidConn
|
||||
}
|
||||
so, ok := sockOpts[ssoMulticastTTL]
|
||||
if !ok {
|
||||
|
@ -41,7 +40,7 @@ func (c *dgramOpt) SetMulticastTTL(ttl int) error {
|
|||
// packet transmissions.
|
||||
func (c *dgramOpt) MulticastInterface() (*net.Interface, error) {
|
||||
if !c.ok() {
|
||||
return nil, syscall.EINVAL
|
||||
return nil, errInvalidConn
|
||||
}
|
||||
so, ok := sockOpts[ssoMulticastInterface]
|
||||
if !ok {
|
||||
|
@ -54,7 +53,7 @@ func (c *dgramOpt) MulticastInterface() (*net.Interface, error) {
|
|||
// multicast packet transmissions.
|
||||
func (c *dgramOpt) SetMulticastInterface(ifi *net.Interface) error {
|
||||
if !c.ok() {
|
||||
return syscall.EINVAL
|
||||
return errInvalidConn
|
||||
}
|
||||
so, ok := sockOpts[ssoMulticastInterface]
|
||||
if !ok {
|
||||
|
@ -67,7 +66,7 @@ func (c *dgramOpt) SetMulticastInterface(ifi *net.Interface) error {
|
|||
// should be copied and send back to the originator.
|
||||
func (c *dgramOpt) MulticastLoopback() (bool, error) {
|
||||
if !c.ok() {
|
||||
return false, syscall.EINVAL
|
||||
return false, errInvalidConn
|
||||
}
|
||||
so, ok := sockOpts[ssoMulticastLoopback]
|
||||
if !ok {
|
||||
|
@ -84,7 +83,7 @@ func (c *dgramOpt) MulticastLoopback() (bool, error) {
|
|||
// should be copied and send back to the originator.
|
||||
func (c *dgramOpt) SetMulticastLoopback(on bool) error {
|
||||
if !c.ok() {
|
||||
return syscall.EINVAL
|
||||
return errInvalidConn
|
||||
}
|
||||
so, ok := sockOpts[ssoMulticastLoopback]
|
||||
if !ok {
|
||||
|
@ -104,7 +103,7 @@ func (c *dgramOpt) SetMulticastLoopback(on bool) error {
|
|||
// configuration.
|
||||
func (c *dgramOpt) JoinGroup(ifi *net.Interface, group net.Addr) error {
|
||||
if !c.ok() {
|
||||
return syscall.EINVAL
|
||||
return errInvalidConn
|
||||
}
|
||||
so, ok := sockOpts[ssoJoinGroup]
|
||||
if !ok {
|
||||
|
@ -122,7 +121,7 @@ func (c *dgramOpt) JoinGroup(ifi *net.Interface, group net.Addr) error {
|
|||
// source-specific group.
|
||||
func (c *dgramOpt) LeaveGroup(ifi *net.Interface, group net.Addr) error {
|
||||
if !c.ok() {
|
||||
return syscall.EINVAL
|
||||
return errInvalidConn
|
||||
}
|
||||
so, ok := sockOpts[ssoLeaveGroup]
|
||||
if !ok {
|
||||
|
@ -143,7 +142,7 @@ func (c *dgramOpt) LeaveGroup(ifi *net.Interface, group net.Addr) error {
|
|||
// routing configuration.
|
||||
func (c *dgramOpt) JoinSourceSpecificGroup(ifi *net.Interface, group, source net.Addr) error {
|
||||
if !c.ok() {
|
||||
return syscall.EINVAL
|
||||
return errInvalidConn
|
||||
}
|
||||
so, ok := sockOpts[ssoJoinSourceGroup]
|
||||
if !ok {
|
||||
|
@ -164,7 +163,7 @@ func (c *dgramOpt) JoinSourceSpecificGroup(ifi *net.Interface, group, source net
|
|||
// interface ifi.
|
||||
func (c *dgramOpt) LeaveSourceSpecificGroup(ifi *net.Interface, group, source net.Addr) error {
|
||||
if !c.ok() {
|
||||
return syscall.EINVAL
|
||||
return errInvalidConn
|
||||
}
|
||||
so, ok := sockOpts[ssoLeaveSourceGroup]
|
||||
if !ok {
|
||||
|
@ -186,7 +185,7 @@ func (c *dgramOpt) LeaveSourceSpecificGroup(ifi *net.Interface, group, source ne
|
|||
// ifi.
|
||||
func (c *dgramOpt) ExcludeSourceSpecificGroup(ifi *net.Interface, group, source net.Addr) error {
|
||||
if !c.ok() {
|
||||
return syscall.EINVAL
|
||||
return errInvalidConn
|
||||
}
|
||||
so, ok := sockOpts[ssoBlockSourceGroup]
|
||||
if !ok {
|
||||
|
@ -207,7 +206,7 @@ func (c *dgramOpt) ExcludeSourceSpecificGroup(ifi *net.Interface, group, source
|
|||
// group by ExcludeSourceSpecificGroup again on the interface ifi.
|
||||
func (c *dgramOpt) IncludeSourceSpecificGroup(ifi *net.Interface, group, source net.Addr) error {
|
||||
if !c.ok() {
|
||||
return syscall.EINVAL
|
||||
return errInvalidConn
|
||||
}
|
||||
so, ok := sockOpts[ssoUnblockSourceGroup]
|
||||
if !ok {
|
||||
|
@ -228,7 +227,7 @@ func (c *dgramOpt) IncludeSourceSpecificGroup(ifi *net.Interface, group, source
|
|||
// Currently only Linux supports this.
|
||||
func (c *dgramOpt) ICMPFilter() (*ICMPFilter, error) {
|
||||
if !c.ok() {
|
||||
return nil, syscall.EINVAL
|
||||
return nil, errInvalidConn
|
||||
}
|
||||
so, ok := sockOpts[ssoICMPFilter]
|
||||
if !ok {
|
||||
|
@ -241,7 +240,7 @@ func (c *dgramOpt) ICMPFilter() (*ICMPFilter, error) {
|
|||
// Currently only Linux supports this.
|
||||
func (c *dgramOpt) SetICMPFilter(f *ICMPFilter) error {
|
||||
if !c.ok() {
|
||||
return syscall.EINVAL
|
||||
return errInvalidConn
|
||||
}
|
||||
so, ok := sockOpts[ssoICMPFilter]
|
||||
if !ok {
|
||||
|
@ -255,7 +254,7 @@ func (c *dgramOpt) SetICMPFilter(f *ICMPFilter) error {
|
|||
// Only supported on Linux.
|
||||
func (c *dgramOpt) SetBPF(filter []bpf.RawInstruction) error {
|
||||
if !c.ok() {
|
||||
return syscall.EINVAL
|
||||
return errInvalidConn
|
||||
}
|
||||
so, ok := sockOpts[ssoAttachFilter]
|
||||
if !ok {
|
||||
|
|
|
@ -55,7 +55,7 @@
|
|||
// Multicasting
|
||||
//
|
||||
// The options for multicasting are available for net.UDPConn and
|
||||
// net.IPconn which are created as network connections that use the
|
||||
// net.IPConn which are created as network connections that use the
|
||||
// IPv4 transport. A few network facilities must be prepared before
|
||||
// you begin multicasting, at a minimum joining network interfaces and
|
||||
// multicast groups.
|
||||
|
@ -241,4 +241,4 @@
|
|||
// IncludeSourceSpecificGroup may return an error.
|
||||
package ipv4 // import "golang.org/x/net/ipv4"
|
||||
|
||||
// BUG(mikio): This package is not implemented on NaCl and Plan 9.
|
||||
// BUG(mikio): This package is not implemented on JS, NaCl and Plan 9.
|
||||
|
|
|
@ -6,7 +6,6 @@ package ipv4
|
|||
|
||||
import (
|
||||
"net"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/internal/socket"
|
||||
|
@ -58,7 +57,7 @@ func (c *dgramOpt) ok() bool { return c != nil && c.Conn != nil }
|
|||
// SetControlMessage sets the per packet IP-level socket options.
|
||||
func (c *PacketConn) SetControlMessage(cf ControlFlags, on bool) error {
|
||||
if !c.payloadHandler.ok() {
|
||||
return syscall.EINVAL
|
||||
return errInvalidConn
|
||||
}
|
||||
return setControlMessage(c.dgramOpt.Conn, &c.payloadHandler.rawOpt, cf, on)
|
||||
}
|
||||
|
@ -67,7 +66,7 @@ func (c *PacketConn) SetControlMessage(cf ControlFlags, on bool) error {
|
|||
// endpoint.
|
||||
func (c *PacketConn) SetDeadline(t time.Time) error {
|
||||
if !c.payloadHandler.ok() {
|
||||
return syscall.EINVAL
|
||||
return errInvalidConn
|
||||
}
|
||||
return c.payloadHandler.PacketConn.SetDeadline(t)
|
||||
}
|
||||
|
@ -76,7 +75,7 @@ func (c *PacketConn) SetDeadline(t time.Time) error {
|
|||
// endpoint.
|
||||
func (c *PacketConn) SetReadDeadline(t time.Time) error {
|
||||
if !c.payloadHandler.ok() {
|
||||
return syscall.EINVAL
|
||||
return errInvalidConn
|
||||
}
|
||||
return c.payloadHandler.PacketConn.SetReadDeadline(t)
|
||||
}
|
||||
|
@ -85,7 +84,7 @@ func (c *PacketConn) SetReadDeadline(t time.Time) error {
|
|||
// endpoint.
|
||||
func (c *PacketConn) SetWriteDeadline(t time.Time) error {
|
||||
if !c.payloadHandler.ok() {
|
||||
return syscall.EINVAL
|
||||
return errInvalidConn
|
||||
}
|
||||
return c.payloadHandler.PacketConn.SetWriteDeadline(t)
|
||||
}
|
||||
|
@ -93,7 +92,7 @@ func (c *PacketConn) SetWriteDeadline(t time.Time) error {
|
|||
// Close closes the endpoint.
|
||||
func (c *PacketConn) Close() error {
|
||||
if !c.payloadHandler.ok() {
|
||||
return syscall.EINVAL
|
||||
return errInvalidConn
|
||||
}
|
||||
return c.payloadHandler.PacketConn.Close()
|
||||
}
|
||||
|
@ -124,7 +123,7 @@ type RawConn struct {
|
|||
// SetControlMessage sets the per packet IP-level socket options.
|
||||
func (c *RawConn) SetControlMessage(cf ControlFlags, on bool) error {
|
||||
if !c.packetHandler.ok() {
|
||||
return syscall.EINVAL
|
||||
return errInvalidConn
|
||||
}
|
||||
return setControlMessage(c.dgramOpt.Conn, &c.packetHandler.rawOpt, cf, on)
|
||||
}
|
||||
|
@ -133,7 +132,7 @@ func (c *RawConn) SetControlMessage(cf ControlFlags, on bool) error {
|
|||
// endpoint.
|
||||
func (c *RawConn) SetDeadline(t time.Time) error {
|
||||
if !c.packetHandler.ok() {
|
||||
return syscall.EINVAL
|
||||
return errInvalidConn
|
||||
}
|
||||
return c.packetHandler.IPConn.SetDeadline(t)
|
||||
}
|
||||
|
@ -142,7 +141,7 @@ func (c *RawConn) SetDeadline(t time.Time) error {
|
|||
// endpoint.
|
||||
func (c *RawConn) SetReadDeadline(t time.Time) error {
|
||||
if !c.packetHandler.ok() {
|
||||
return syscall.EINVAL
|
||||
return errInvalidConn
|
||||
}
|
||||
return c.packetHandler.IPConn.SetReadDeadline(t)
|
||||
}
|
||||
|
@ -151,7 +150,7 @@ func (c *RawConn) SetReadDeadline(t time.Time) error {
|
|||
// endpoint.
|
||||
func (c *RawConn) SetWriteDeadline(t time.Time) error {
|
||||
if !c.packetHandler.ok() {
|
||||
return syscall.EINVAL
|
||||
return errInvalidConn
|
||||
}
|
||||
return c.packetHandler.IPConn.SetWriteDeadline(t)
|
||||
}
|
||||
|
@ -159,7 +158,7 @@ func (c *RawConn) SetWriteDeadline(t time.Time) error {
|
|||
// Close closes the endpoint.
|
||||
func (c *RawConn) Close() error {
|
||||
if !c.packetHandler.ok() {
|
||||
return syscall.EINVAL
|
||||
return errInvalidConn
|
||||
}
|
||||
return c.packetHandler.IPConn.Close()
|
||||
}
|
||||
|
|
|
@ -4,12 +4,10 @@
|
|||
|
||||
package ipv4
|
||||
|
||||
import "syscall"
|
||||
|
||||
// TOS returns the type-of-service field value for outgoing packets.
|
||||
func (c *genericOpt) TOS() (int, error) {
|
||||
if !c.ok() {
|
||||
return 0, syscall.EINVAL
|
||||
return 0, errInvalidConn
|
||||
}
|
||||
so, ok := sockOpts[ssoTOS]
|
||||
if !ok {
|
||||
|
@ -22,7 +20,7 @@ func (c *genericOpt) TOS() (int, error) {
|
|||
// packets.
|
||||
func (c *genericOpt) SetTOS(tos int) error {
|
||||
if !c.ok() {
|
||||
return syscall.EINVAL
|
||||
return errInvalidConn
|
||||
}
|
||||
so, ok := sockOpts[ssoTOS]
|
||||
if !ok {
|
||||
|
@ -34,7 +32,7 @@ func (c *genericOpt) SetTOS(tos int) error {
|
|||
// TTL returns the time-to-live field value for outgoing packets.
|
||||
func (c *genericOpt) TTL() (int, error) {
|
||||
if !c.ok() {
|
||||
return 0, syscall.EINVAL
|
||||
return 0, errInvalidConn
|
||||
}
|
||||
so, ok := sockOpts[ssoTTL]
|
||||
if !ok {
|
||||
|
@ -47,7 +45,7 @@ func (c *genericOpt) TTL() (int, error) {
|
|||
// packets.
|
||||
func (c *genericOpt) SetTTL(ttl int) error {
|
||||
if !c.ok() {
|
||||
return syscall.EINVAL
|
||||
return errInvalidConn
|
||||
}
|
||||
so, ok := sockOpts[ssoTTL]
|
||||
if !ok {
|
||||
|
|
|
@ -9,7 +9,6 @@ import (
|
|||
"fmt"
|
||||
"net"
|
||||
"runtime"
|
||||
"syscall"
|
||||
|
||||
"golang.org/x/net/internal/socket"
|
||||
)
|
||||
|
@ -52,9 +51,13 @@ func (h *Header) String() string {
|
|||
}
|
||||
|
||||
// Marshal returns the binary encoding of h.
|
||||
//
|
||||
// The returned slice is in the format used by a raw IP socket on the
|
||||
// local system.
|
||||
// This may differ from the wire format, depending on the system.
|
||||
func (h *Header) Marshal() ([]byte, error) {
|
||||
if h == nil {
|
||||
return nil, syscall.EINVAL
|
||||
return nil, errInvalidConn
|
||||
}
|
||||
if h.Len < HeaderLen {
|
||||
return nil, errHeaderTooShort
|
||||
|
@ -98,7 +101,11 @@ func (h *Header) Marshal() ([]byte, error) {
|
|||
return b, nil
|
||||
}
|
||||
|
||||
// Parse parses b as an IPv4 header and sotres the result in h.
|
||||
// Parse parses b as an IPv4 header and stores the result in h.
|
||||
//
|
||||
// The provided b must be in the format used by a raw IP socket on the
|
||||
// local system.
|
||||
// This may differ from the wire format, depending on the system.
|
||||
func (h *Header) Parse(b []byte) error {
|
||||
if h == nil || len(b) < HeaderLen {
|
||||
return errHeaderTooShort
|
||||
|
@ -150,6 +157,10 @@ func (h *Header) Parse(b []byte) error {
|
|||
}
|
||||
|
||||
// ParseHeader parses b as an IPv4 header.
|
||||
//
|
||||
// The provided b must be in the format used by a raw IP socket on the
|
||||
// local system.
|
||||
// This may differ from the wire format, depending on the system.
|
||||
func ParseHeader(b []byte) (*Header, error) {
|
||||
h := new(Header)
|
||||
if err := h.Parse(b); err != nil {
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
)
|
||||
|
||||
var (
|
||||
errInvalidConn = errors.New("invalid connection")
|
||||
errMissingAddress = errors.New("missing address")
|
||||
errMissingHeader = errors.New("missing header")
|
||||
errHeaderTooShort = errors.New("header too short")
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
// go generate gen.go
|
||||
// GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
|
||||
// Code generated by the command above; DO NOT EDIT.
|
||||
|
||||
package ipv4
|
||||
|
||||
// Internet Control Message Protocol (ICMP) Parameters, Updated: 2013-04-19
|
||||
// Internet Control Message Protocol (ICMP) Parameters, Updated: 2018-02-26
|
||||
const (
|
||||
ICMPTypeEchoReply ICMPType = 0 // Echo Reply
|
||||
ICMPTypeDestinationUnreachable ICMPType = 3 // Destination Unreachable
|
||||
|
@ -16,9 +16,11 @@ const (
|
|||
ICMPTypeTimestamp ICMPType = 13 // Timestamp
|
||||
ICMPTypeTimestampReply ICMPType = 14 // Timestamp Reply
|
||||
ICMPTypePhoturis ICMPType = 40 // Photuris
|
||||
ICMPTypeExtendedEchoRequest ICMPType = 42 // Extended Echo Request
|
||||
ICMPTypeExtendedEchoReply ICMPType = 43 // Extended Echo Reply
|
||||
)
|
||||
|
||||
// Internet Control Message Protocol (ICMP) Parameters, Updated: 2013-04-19
|
||||
// Internet Control Message Protocol (ICMP) Parameters, Updated: 2018-02-26
|
||||
var icmpTypes = map[ICMPType]string{
|
||||
0: "echo reply",
|
||||
3: "destination unreachable",
|
||||
|
@ -31,4 +33,6 @@ var icmpTypes = map[ICMPType]string{
|
|||
13: "timestamp",
|
||||
14: "timestamp reply",
|
||||
40: "photuris",
|
||||
42: "extended echo request",
|
||||
43: "extended echo reply",
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@ package ipv4
|
|||
|
||||
import (
|
||||
"net"
|
||||
"syscall"
|
||||
|
||||
"golang.org/x/net/internal/socket"
|
||||
)
|
||||
|
@ -28,7 +27,7 @@ func (c *packetHandler) ok() bool { return c != nil && c.IPConn != nil && c.Conn
|
|||
// header h, the payload p and the control message cm.
|
||||
func (c *packetHandler) ReadFrom(b []byte) (h *Header, p []byte, cm *ControlMessage, err error) {
|
||||
if !c.ok() {
|
||||
return nil, nil, nil, syscall.EINVAL
|
||||
return nil, nil, nil, errInvalidConn
|
||||
}
|
||||
return c.readFrom(b)
|
||||
}
|
||||
|
@ -63,7 +62,7 @@ func slicePacket(b []byte) (h, p []byte, err error) {
|
|||
// Options = optional
|
||||
func (c *packetHandler) WriteTo(h *Header, p []byte, cm *ControlMessage) error {
|
||||
if !c.ok() {
|
||||
return syscall.EINVAL
|
||||
return errInvalidConn
|
||||
}
|
||||
return c.writeTo(h, p, cm)
|
||||
}
|
||||
|
|
|
@ -2,14 +2,11 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build !nacl,!plan9,!windows
|
||||
// +build !js,!nacl,!plan9,!windows
|
||||
|
||||
package ipv4
|
||||
|
||||
import (
|
||||
"net"
|
||||
"syscall"
|
||||
)
|
||||
import "net"
|
||||
|
||||
// ReadFrom reads a payload of the received IPv4 datagram, from the
|
||||
// endpoint c, copying the payload into b. It returns the number of
|
||||
|
@ -17,7 +14,7 @@ import (
|
|||
// src of the received datagram.
|
||||
func (c *payloadHandler) ReadFrom(b []byte) (n int, cm *ControlMessage, src net.Addr, err error) {
|
||||
if !c.ok() {
|
||||
return 0, nil, nil, syscall.EINVAL
|
||||
return 0, nil, nil, errInvalidConn
|
||||
}
|
||||
return c.readFrom(b)
|
||||
}
|
||||
|
@ -30,7 +27,7 @@ func (c *payloadHandler) ReadFrom(b []byte) (n int, cm *ControlMessage, src net.
|
|||
// control of the outgoing datagram is not required.
|
||||
func (c *payloadHandler) WriteTo(b []byte, cm *ControlMessage, dst net.Addr) (n int, err error) {
|
||||
if !c.ok() {
|
||||
return 0, syscall.EINVAL
|
||||
return 0, errInvalidConn
|
||||
}
|
||||
return c.writeTo(b, cm, dst)
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build !go1.9
|
||||
// +build !nacl,!plan9,!windows
|
||||
// +build !js,!nacl,!plan9,!windows
|
||||
|
||||
package ipv4
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build go1.9
|
||||
// +build !nacl,!plan9,!windows
|
||||
// +build !js,!nacl,!plan9,!windows
|
||||
|
||||
package ipv4
|
||||
|
||||
|
|
|
@ -2,14 +2,11 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build nacl plan9 windows
|
||||
// +build js nacl plan9 windows
|
||||
|
||||
package ipv4
|
||||
|
||||
import (
|
||||
"net"
|
||||
"syscall"
|
||||
)
|
||||
import "net"
|
||||
|
||||
// ReadFrom reads a payload of the received IPv4 datagram, from the
|
||||
// endpoint c, copying the payload into b. It returns the number of
|
||||
|
@ -17,7 +14,7 @@ import (
|
|||
// src of the received datagram.
|
||||
func (c *payloadHandler) ReadFrom(b []byte) (n int, cm *ControlMessage, src net.Addr, err error) {
|
||||
if !c.ok() {
|
||||
return 0, nil, nil, syscall.EINVAL
|
||||
return 0, nil, nil, errInvalidConn
|
||||
}
|
||||
if n, src, err = c.PacketConn.ReadFrom(b); err != nil {
|
||||
return 0, nil, nil, err
|
||||
|
@ -33,7 +30,7 @@ func (c *payloadHandler) ReadFrom(b []byte) (n int, cm *ControlMessage, src net.
|
|||
// control of the outgoing datagram is not required.
|
||||
func (c *payloadHandler) WriteTo(b []byte, cm *ControlMessage, dst net.Addr) (n int, err error) {
|
||||
if !c.ok() {
|
||||
return 0, syscall.EINVAL
|
||||
return 0, errInvalidConn
|
||||
}
|
||||
if dst == nil {
|
||||
return 0, errMissingAddress
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
|
||||
// +build go1.9
|
||||
|
||||
package unix
|
||||
|
||||
import "syscall"
|
||||
|
||||
type Signal = syscall.Signal
|
||||
type Errno = syscall.Errno
|
||||
type SysProcAttr = syscall.SysProcAttr
|
|
@ -13,17 +13,17 @@
|
|||
// Just jump to package syscall's implementation for all these functions.
|
||||
// The runtime may know about them.
|
||||
|
||||
TEXT ·Syscall(SB),NOSPLIT,$0-64
|
||||
TEXT ·Syscall(SB),NOSPLIT,$0-56
|
||||
JMP syscall·Syscall(SB)
|
||||
|
||||
TEXT ·Syscall6(SB),NOSPLIT,$0-88
|
||||
TEXT ·Syscall6(SB),NOSPLIT,$0-80
|
||||
JMP syscall·Syscall6(SB)
|
||||
|
||||
TEXT ·Syscall9(SB),NOSPLIT,$0-112
|
||||
TEXT ·Syscall9(SB),NOSPLIT,$0-104
|
||||
JMP syscall·Syscall9(SB)
|
||||
|
||||
TEXT ·RawSyscall(SB),NOSPLIT,$0-64
|
||||
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
|
||||
JMP syscall·RawSyscall(SB)
|
||||
|
||||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-88
|
||||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
|
||||
JMP syscall·RawSyscall6(SB)
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
package unix
|
||||
|
||||
import (
|
||||
errorspkg "errors"
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
|
@ -60,26 +60,26 @@ func CapRightsSet(rights *CapRights, setrights []uint64) error {
|
|||
|
||||
n := caparsize(rights)
|
||||
if n < capArSizeMin || n > capArSizeMax {
|
||||
return errorspkg.New("bad rights size")
|
||||
return errors.New("bad rights size")
|
||||
}
|
||||
|
||||
for _, right := range setrights {
|
||||
if caprver(right) != CAP_RIGHTS_VERSION_00 {
|
||||
return errorspkg.New("bad right version")
|
||||
return errors.New("bad right version")
|
||||
}
|
||||
i, err := rightToIndex(right)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if i >= n {
|
||||
return errorspkg.New("index overflow")
|
||||
return errors.New("index overflow")
|
||||
}
|
||||
if capidxbit(rights.Rights[i]) != capidxbit(right) {
|
||||
return errorspkg.New("index mismatch")
|
||||
return errors.New("index mismatch")
|
||||
}
|
||||
rights.Rights[i] |= right
|
||||
if capidxbit(rights.Rights[i]) != capidxbit(right) {
|
||||
return errorspkg.New("index mismatch (after assign)")
|
||||
return errors.New("index mismatch (after assign)")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -95,26 +95,26 @@ func CapRightsClear(rights *CapRights, clearrights []uint64) error {
|
|||
|
||||
n := caparsize(rights)
|
||||
if n < capArSizeMin || n > capArSizeMax {
|
||||
return errorspkg.New("bad rights size")
|
||||
return errors.New("bad rights size")
|
||||
}
|
||||
|
||||
for _, right := range clearrights {
|
||||
if caprver(right) != CAP_RIGHTS_VERSION_00 {
|
||||
return errorspkg.New("bad right version")
|
||||
return errors.New("bad right version")
|
||||
}
|
||||
i, err := rightToIndex(right)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if i >= n {
|
||||
return errorspkg.New("index overflow")
|
||||
return errors.New("index overflow")
|
||||
}
|
||||
if capidxbit(rights.Rights[i]) != capidxbit(right) {
|
||||
return errorspkg.New("index mismatch")
|
||||
return errors.New("index mismatch")
|
||||
}
|
||||
rights.Rights[i] &= ^(right & 0x01FFFFFFFFFFFFFF)
|
||||
if capidxbit(rights.Rights[i]) != capidxbit(right) {
|
||||
return errorspkg.New("index mismatch (after assign)")
|
||||
return errors.New("index mismatch (after assign)")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -130,22 +130,22 @@ func CapRightsIsSet(rights *CapRights, setrights []uint64) (bool, error) {
|
|||
|
||||
n := caparsize(rights)
|
||||
if n < capArSizeMin || n > capArSizeMax {
|
||||
return false, errorspkg.New("bad rights size")
|
||||
return false, errors.New("bad rights size")
|
||||
}
|
||||
|
||||
for _, right := range setrights {
|
||||
if caprver(right) != CAP_RIGHTS_VERSION_00 {
|
||||
return false, errorspkg.New("bad right version")
|
||||
return false, errors.New("bad right version")
|
||||
}
|
||||
i, err := rightToIndex(right)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if i >= n {
|
||||
return false, errorspkg.New("index overflow")
|
||||
return false, errors.New("index overflow")
|
||||
}
|
||||
if capidxbit(rights.Rights[i]) != capidxbit(right) {
|
||||
return false, errorspkg.New("index mismatch")
|
||||
return false, errors.New("index mismatch")
|
||||
}
|
||||
if (rights.Rights[i] & right) != right {
|
||||
return false, nil
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue