vendor: Add dependencies for strelaypoolsrv

This commit is contained in:
Jakob Borg
2016-07-04 11:12:59 +02:00
parent 7d434aa9c4
commit 59370588dd
261 changed files with 118913 additions and 0 deletions

13
vendor/github.com/oschwald/maxminddb-golang/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,13 @@
Copyright (c) 2015, Gregory J. Oschwald <oschwald@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.

559
vendor/github.com/oschwald/maxminddb-golang/decoder.go generated vendored Normal file
View File

@@ -0,0 +1,559 @@
package maxminddb
import (
"encoding/binary"
"math"
"math/big"
"reflect"
"sync"
)
type decoder struct {
buffer []byte
}
type dataType int
const (
_Extended dataType = iota
_Pointer
_String
_Float64
_Bytes
_Uint16
_Uint32
_Map
_Int32
_Uint64
_Uint128
_Slice
_Container
_Marker
_Bool
_Float32
)
func (d *decoder) decode(offset uint, result reflect.Value) (uint, error) {
typeNum, size, newOffset := d.decodeCtrlData(offset)
if typeNum != _Pointer && result.Kind() == reflect.Uintptr {
result.Set(reflect.ValueOf(uintptr(offset)))
return d.nextValueOffset(offset, 1), nil
}
return d.decodeFromType(typeNum, size, newOffset, result)
}
func (d *decoder) decodeCtrlData(offset uint) (dataType, uint, uint) {
newOffset := offset + 1
ctrlByte := d.buffer[offset]
typeNum := dataType(ctrlByte >> 5)
if typeNum == _Extended {
typeNum = dataType(d.buffer[newOffset] + 7)
newOffset++
}
var size uint
size, newOffset = d.sizeFromCtrlByte(ctrlByte, newOffset, typeNum)
return typeNum, size, newOffset
}
func (d *decoder) sizeFromCtrlByte(ctrlByte byte, offset uint, typeNum dataType) (uint, uint) {
size := uint(ctrlByte & 0x1f)
if typeNum == _Extended {
return size, offset
}
var bytesToRead uint
if size > 28 {
bytesToRead = size - 28
}
newOffset := offset + bytesToRead
sizeBytes := d.buffer[offset:newOffset]
switch {
case size == 29:
size = 29 + uint(sizeBytes[0])
case size == 30:
size = 285 + uint(uintFromBytes(0, sizeBytes))
case size > 30:
size = uint(uintFromBytes(0, sizeBytes)) + 65821
}
return size, newOffset
}
func (d *decoder) decodeFromType(dtype dataType, size uint, offset uint, result reflect.Value) (uint, error) {
for result.Kind() == reflect.Ptr {
if result.IsNil() {
result.Set(reflect.New(result.Type().Elem()))
}
result = result.Elem()
}
switch dtype {
case _Bool:
return d.unmarshalBool(size, offset, result)
case _Bytes:
return d.unmarshalBytes(size, offset, result)
case _Float32:
return d.unmarshalFloat32(size, offset, result)
case _Float64:
return d.unmarshalFloat64(size, offset, result)
case _Int32:
return d.unmarshalInt32(size, offset, result)
case _Map:
return d.unmarshalMap(size, offset, result)
case _Pointer:
return d.unmarshalPointer(size, offset, result)
case _Slice:
return d.unmarshalSlice(size, offset, result)
case _String:
return d.unmarshalString(size, offset, result)
case _Uint16:
return d.unmarshalUint(size, offset, result, 16)
case _Uint32:
return d.unmarshalUint(size, offset, result, 32)
case _Uint64:
return d.unmarshalUint(size, offset, result, 64)
case _Uint128:
return d.unmarshalUint128(size, offset, result)
default:
return 0, newInvalidDatabaseError("unknown type: %d", dtype)
}
}
func (d *decoder) unmarshalBool(size uint, offset uint, result reflect.Value) (uint, error) {
if size > 1 {
return 0, newInvalidDatabaseError("the MaxMind DB file's data section contains bad data (bool size of %v)", size)
}
value, newOffset, err := d.decodeBool(size, offset)
if err != nil {
return 0, err
}
switch result.Kind() {
default:
return newOffset, newUnmarshalTypeError(value, result.Type())
case reflect.Bool:
result.SetBool(value)
return newOffset, nil
case reflect.Interface:
result.Set(reflect.ValueOf(value))
return newOffset, nil
}
}
func (d *decoder) unmarshalBytes(size uint, offset uint, result reflect.Value) (uint, error) {
value, newOffset, err := d.decodeBytes(size, offset)
if err != nil {
return 0, err
}
switch result.Kind() {
default:
return newOffset, newUnmarshalTypeError(value, result.Type())
case reflect.Slice:
result.SetBytes(value)
return newOffset, nil
case reflect.Interface:
result.Set(reflect.ValueOf(value))
return newOffset, nil
}
}
func (d *decoder) unmarshalFloat32(size uint, offset uint, result reflect.Value) (uint, error) {
if size != 4 {
return 0, newInvalidDatabaseError("the MaxMind DB file's data section contains bad data (float32 size of %v)", size)
}
value, newOffset, err := d.decodeFloat32(size, offset)
if err != nil {
return 0, err
}
switch result.Kind() {
default:
return newOffset, newUnmarshalTypeError(value, result.Type())
case reflect.Float32, reflect.Float64:
result.SetFloat(float64(value))
return newOffset, nil
case reflect.Interface:
result.Set(reflect.ValueOf(value))
return newOffset, nil
}
}
func (d *decoder) unmarshalFloat64(size uint, offset uint, result reflect.Value) (uint, error) {
if size != 8 {
return 0, newInvalidDatabaseError("the MaxMind DB file's data section contains bad data (float 64 size of %v)", size)
}
value, newOffset, err := d.decodeFloat64(size, offset)
if err != nil {
return 0, err
}
switch result.Kind() {
default:
return newOffset, newUnmarshalTypeError(value, result.Type())
case reflect.Float32, reflect.Float64:
if result.OverflowFloat(value) {
return 0, newUnmarshalTypeError(value, result.Type())
}
result.SetFloat(value)
return newOffset, nil
case reflect.Interface:
result.Set(reflect.ValueOf(value))
return newOffset, nil
}
}
func (d *decoder) unmarshalInt32(size uint, offset uint, result reflect.Value) (uint, error) {
if size > 4 {
return 0, newInvalidDatabaseError("the MaxMind DB file's data section contains bad data (int32 size of %v)", size)
}
value, newOffset, err := d.decodeInt(size, offset)
if err != nil {
return 0, err
}
switch result.Kind() {
default:
return newOffset, newUnmarshalTypeError(value, result.Type())
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
n := int64(value)
if result.OverflowInt(n) {
return 0, newUnmarshalTypeError(value, result.Type())
}
result.SetInt(n)
return newOffset, nil
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
n := uint64(value)
if result.OverflowUint(n) {
return 0, newUnmarshalTypeError(value, result.Type())
}
result.SetUint(n)
return newOffset, nil
case reflect.Interface:
result.Set(reflect.ValueOf(value))
return newOffset, nil
}
}
func (d *decoder) unmarshalMap(size uint, offset uint, result reflect.Value) (uint, error) {
switch result.Kind() {
default:
return 0, newUnmarshalTypeError("map", result.Type())
case reflect.Struct:
return d.decodeStruct(size, offset, result)
case reflect.Map:
return d.decodeMap(size, offset, result)
case reflect.Interface:
rv := reflect.ValueOf(make(map[string]interface{}, size))
newOffset, err := d.decodeMap(size, offset, rv)
result.Set(rv)
return newOffset, err
}
}
func (d *decoder) unmarshalPointer(size uint, offset uint, result reflect.Value) (uint, error) {
pointer, newOffset := d.decodePointer(size, offset)
_, err := d.decode(pointer, result)
return newOffset, err
}
func (d *decoder) unmarshalSlice(size uint, offset uint, result reflect.Value) (uint, error) {
switch result.Kind() {
default:
return 0, newUnmarshalTypeError("array", result.Type())
case reflect.Slice:
return d.decodeSlice(size, offset, result)
case reflect.Interface:
a := []interface{}{}
rv := reflect.ValueOf(&a).Elem()
newOffset, err := d.decodeSlice(size, offset, rv)
result.Set(rv)
return newOffset, err
}
}
func (d *decoder) unmarshalString(size uint, offset uint, result reflect.Value) (uint, error) {
value, newOffset, err := d.decodeString(size, offset)
if err != nil {
return 0, err
}
switch result.Kind() {
default:
return newOffset, newUnmarshalTypeError(value, result.Type())
case reflect.String:
result.SetString(value)
return newOffset, nil
case reflect.Interface:
result.Set(reflect.ValueOf(value))
return newOffset, nil
}
}
func (d *decoder) unmarshalUint(size uint, offset uint, result reflect.Value, uintType uint) (uint, error) {
if size > uintType/8 {
return 0, newInvalidDatabaseError("the MaxMind DB file's data section contains bad data (uint%v size of %v)", uintType, size)
}
value, newOffset, err := d.decodeUint(size, offset)
if err != nil {
return 0, err
}
switch result.Kind() {
default:
return newOffset, newUnmarshalTypeError(value, result.Type())
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
n := int64(value)
if result.OverflowInt(n) {
return 0, newUnmarshalTypeError(value, result.Type())
}
result.SetInt(n)
return newOffset, nil
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
if result.OverflowUint(value) {
return 0, newUnmarshalTypeError(value, result.Type())
}
result.SetUint(value)
return newOffset, nil
case reflect.Interface:
result.Set(reflect.ValueOf(value))
return newOffset, nil
}
}
func (d *decoder) unmarshalUint128(size uint, offset uint, result reflect.Value) (uint, error) {
if size > 16 {
return 0, newInvalidDatabaseError("the MaxMind DB file's data section contains bad data (uint128 size of %v)", size)
}
value, newOffset, err := d.decodeUint128(size, offset)
if err != nil {
return 0, err
}
// XXX - this should allow *big.Int rather than just bigInt
// Currently this is reported as invalid
switch result.Kind() {
default:
return newOffset, newUnmarshalTypeError(value, result.Type())
case reflect.Struct:
result.Set(reflect.ValueOf(*value))
return newOffset, nil
case reflect.Interface, reflect.Ptr:
result.Set(reflect.ValueOf(value))
return newOffset, nil
}
}
func (d *decoder) decodeBool(size uint, offset uint) (bool, uint, error) {
return size != 0, offset, nil
}
func (d *decoder) decodeBytes(size uint, offset uint) ([]byte, uint, error) {
newOffset := offset + size
bytes := make([]byte, size)
copy(bytes, d.buffer[offset:newOffset])
return bytes, newOffset, nil
}
func (d *decoder) decodeFloat64(size uint, offset uint) (float64, uint, error) {
newOffset := offset + size
bits := binary.BigEndian.Uint64(d.buffer[offset:newOffset])
return math.Float64frombits(bits), newOffset, nil
}
func (d *decoder) decodeFloat32(size uint, offset uint) (float32, uint, error) {
newOffset := offset + size
bits := binary.BigEndian.Uint32(d.buffer[offset:newOffset])
return math.Float32frombits(bits), newOffset, nil
}
func (d *decoder) decodeInt(size uint, offset uint) (int, uint, error) {
newOffset := offset + size
var val int32
for _, b := range d.buffer[offset:newOffset] {
val = (val << 8) | int32(b)
}
return int(val), newOffset, nil
}
func (d *decoder) decodeMap(size uint, offset uint, result reflect.Value) (uint, error) {
if result.IsNil() {
result.Set(reflect.MakeMap(result.Type()))
}
for i := uint(0); i < size; i++ {
var key string
var err error
key, offset, err = d.decodeKeyString(offset)
if err != nil {
return 0, err
}
value := reflect.New(result.Type().Elem())
offset, err = d.decode(offset, value)
if err != nil {
return 0, err
}
result.SetMapIndex(reflect.ValueOf(key), value.Elem())
}
return offset, nil
}
func (d *decoder) decodePointer(size uint, offset uint) (uint, uint) {
pointerSize := ((size >> 3) & 0x3) + 1
newOffset := offset + pointerSize
pointerBytes := d.buffer[offset:newOffset]
var prefix uint64
if pointerSize == 4 {
prefix = 0
} else {
prefix = uint64(size & 0x7)
}
unpacked := uint(uintFromBytes(prefix, pointerBytes))
var pointerValueOffset uint
switch pointerSize {
case 1:
pointerValueOffset = 0
case 2:
pointerValueOffset = 2048
case 3:
pointerValueOffset = 526336
case 4:
pointerValueOffset = 0
}
pointer := unpacked + pointerValueOffset
return pointer, newOffset
}
func (d *decoder) decodeSlice(size uint, offset uint, result reflect.Value) (uint, error) {
result.Set(reflect.MakeSlice(result.Type(), int(size), int(size)))
for i := 0; i < int(size); i++ {
var err error
offset, err = d.decode(offset, result.Index(i))
if err != nil {
return 0, err
}
}
return offset, nil
}
func (d *decoder) decodeString(size uint, offset uint) (string, uint, error) {
newOffset := offset + size
return string(d.buffer[offset:newOffset]), newOffset, nil
}
var (
fieldMap = map[reflect.Type]map[string]int{}
fieldMapMu sync.RWMutex
)
func (d *decoder) decodeStruct(size uint, offset uint, result reflect.Value) (uint, error) {
resultType := result.Type()
fieldMapMu.RLock()
fields, ok := fieldMap[resultType]
fieldMapMu.RUnlock()
if !ok {
numFields := resultType.NumField()
fields = make(map[string]int, numFields)
for i := 0; i < numFields; i++ {
fieldType := resultType.Field(i)
fieldName := fieldType.Name
if tag := fieldType.Tag.Get("maxminddb"); tag != "" {
fieldName = tag
}
fields[fieldName] = i
}
fieldMapMu.Lock()
fieldMap[resultType] = fields
fieldMapMu.Unlock()
}
for i := uint(0); i < size; i++ {
var (
err error
key string
)
key, offset, err = d.decodeStructKey(offset)
if err != nil {
return 0, err
}
i, ok := fields[key]
if !ok {
offset = d.nextValueOffset(offset, 1)
continue
}
offset, err = d.decode(offset, result.Field(i))
if err != nil {
return 0, err
}
}
return offset, nil
}
func (d *decoder) decodeUint(size uint, offset uint) (uint64, uint, error) {
newOffset := offset + size
val := uintFromBytes(0, d.buffer[offset:newOffset])
return val, newOffset, nil
}
func (d *decoder) decodeUint128(size uint, offset uint) (*big.Int, uint, error) {
newOffset := offset + size
val := new(big.Int)
val.SetBytes(d.buffer[offset:newOffset])
return val, newOffset, nil
}
func uintFromBytes(prefix uint64, uintBytes []byte) uint64 {
val := prefix
for _, b := range uintBytes {
val = (val << 8) | uint64(b)
}
return val
}
func (d *decoder) decodeKeyString(offset uint) (string, uint, error) {
typeNum, size, newOffset := d.decodeCtrlData(offset)
if typeNum == _Pointer {
pointer, ptrOffset := d.decodePointer(size, newOffset)
key, _, err := d.decodeKeyString(pointer)
return key, ptrOffset, err
}
if typeNum != _String {
return "", 0, newInvalidDatabaseError("unexpected type when decoding string: %v", typeNum)
}
return d.decodeString(size, newOffset)
}
// This function is used to skip ahead to the next value without decoding
// the one at the offset passed in. The size bits have different meanings for
// different data types
func (d *decoder) nextValueOffset(offset uint, numberToSkip uint) uint {
if numberToSkip == 0 {
return offset
}
typeNum, size, offset := d.decodeCtrlData(offset)
switch typeNum {
case _Pointer:
_, offset = d.decodePointer(size, offset)
case _Map:
numberToSkip += 2 * size
case _Slice:
numberToSkip += size
case _Bool:
default:
offset += size
}
return d.nextValueOffset(offset, numberToSkip-1)
}

38
vendor/github.com/oschwald/maxminddb-golang/errors.go generated vendored Normal file
View File

@@ -0,0 +1,38 @@
package maxminddb
import (
"fmt"
"reflect"
)
// InvalidDatabaseError is returned when the database contains invalid data
// and cannot be parsed.
type InvalidDatabaseError struct {
message string
}
func newInvalidDatabaseError(format string, args ...interface{}) InvalidDatabaseError {
return InvalidDatabaseError{fmt.Sprintf(format, args...)}
}
func (e InvalidDatabaseError) Error() string {
return e.message
}
// UnmarshalTypeError is returned when the value in the database cannot be
// assigned to the specified data type.
type UnmarshalTypeError struct {
Value string // stringified copy of the database value that caused the error
Type reflect.Type // type of the value that could not be assign to
}
func newUnmarshalTypeError(value interface{}, rType reflect.Type) UnmarshalTypeError {
return UnmarshalTypeError{
Value: fmt.Sprintf("%v", value),
Type: rType,
}
}
func (e UnmarshalTypeError) Error() string {
return fmt.Sprintf("maxminddb: cannot unmarshal %s into type %s", e.Value, e.Type.String())
}

View File

@@ -0,0 +1,7 @@
// +build appengine
package maxminddb
func (d *decoder) decodeStructKey(offset uint) (string, uint, error) {
return d.decodeKeyString(offset)
}

View File

@@ -0,0 +1,28 @@
// +build !appengine
package maxminddb
import (
"reflect"
"unsafe"
)
// decodeStructKey returns a string which points into the database. Don't keep
// it around.
func (d *decoder) decodeStructKey(offset uint) (string, uint, error) {
typeNum, size, newOffset := d.decodeCtrlData(offset)
switch typeNum {
case _Pointer:
pointer, ptrOffset := d.decodePointer(size, newOffset)
s, _, err := d.decodeStructKey(pointer)
return s, ptrOffset, err
case _String:
var s string
val := (*reflect.StringHeader)(unsafe.Pointer(&s))
val.Data = uintptr(unsafe.Pointer(&d.buffer[newOffset]))
val.Len = int(size)
return s, newOffset + size, nil
default:
return "", 0, newInvalidDatabaseError("unexpected type when decoding struct key: %v", typeNum)
}
}

View File

@@ -0,0 +1,17 @@
// +build !windows,!appengine
package maxminddb
import (
"syscall"
"golang.org/x/sys/unix"
)
func mmap(fd int, length int) (data []byte, err error) {
return unix.Mmap(fd, 0, length, syscall.PROT_READ, syscall.MAP_SHARED)
}
func munmap(b []byte) (err error) {
return unix.Munmap(b)
}

View File

@@ -0,0 +1,83 @@
package maxminddb
// Windows support largely borrowed from mmap-go.
//
// Copyright 2011 Evan Shaw. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
import (
"errors"
"os"
"reflect"
"sync"
"unsafe"
"golang.org/x/sys/windows"
)
type memoryMap []byte
// Windows
var handleLock sync.Mutex
var handleMap = map[uintptr]windows.Handle{}
func mmap(fd int, length int) (data []byte, err error) {
h, errno := windows.CreateFileMapping(windows.Handle(fd), nil,
uint32(windows.PAGE_READONLY), 0, uint32(length), nil)
if h == 0 {
return nil, os.NewSyscallError("CreateFileMapping", errno)
}
addr, errno := windows.MapViewOfFile(h, uint32(windows.FILE_MAP_READ), 0,
0, uintptr(length))
if addr == 0 {
return nil, os.NewSyscallError("MapViewOfFile", errno)
}
handleLock.Lock()
handleMap[addr] = h
handleLock.Unlock()
m := memoryMap{}
dh := m.header()
dh.Data = addr
dh.Len = length
dh.Cap = dh.Len
return m, nil
}
func (m *memoryMap) header() *reflect.SliceHeader {
return (*reflect.SliceHeader)(unsafe.Pointer(m))
}
func flush(addr, len uintptr) error {
errno := windows.FlushViewOfFile(addr, len)
return os.NewSyscallError("FlushViewOfFile", errno)
}
func munmap(b []byte) (err error) {
m := memoryMap(b)
dh := m.header()
addr := dh.Data
length := uintptr(dh.Len)
flush(addr, length)
err = windows.UnmapViewOfFile(addr)
if err != nil {
return err
}
handleLock.Lock()
defer handleLock.Unlock()
handle, ok := handleMap[addr]
if !ok {
// should be impossible; we would've errored above
return errors.New("unknown base address")
}
delete(handleMap, addr)
e := windows.CloseHandle(windows.Handle(handle))
return os.NewSyscallError("CloseHandle", e)
}

246
vendor/github.com/oschwald/maxminddb-golang/reader.go generated vendored Normal file
View File

@@ -0,0 +1,246 @@
package maxminddb
import (
"bytes"
"errors"
"fmt"
"net"
"reflect"
)
const (
// NotFound is returned by LookupOffset when a matched root record offset
// cannot be found.
NotFound = ^uintptr(0)
dataSectionSeparatorSize = 16
)
var metadataStartMarker = []byte("\xAB\xCD\xEFMaxMind.com")
// Reader holds the data corresponding to the MaxMind DB file. Its only public
// field is Metadata, which contains the metadata from the MaxMind DB file.
type Reader struct {
hasMappedFile bool
buffer []byte
decoder decoder
Metadata Metadata
ipv4Start uint
}
// Metadata holds the metadata decoded from the MaxMind DB file. In particular
// in has the format version, the build time as Unix epoch time, the database
// type and description, the IP version supported, and a slice of the natural
// languages included.
type Metadata struct {
BinaryFormatMajorVersion uint `maxminddb:"binary_format_major_version"`
BinaryFormatMinorVersion uint `maxminddb:"binary_format_minor_version"`
BuildEpoch uint `maxminddb:"build_epoch"`
DatabaseType string `maxminddb:"database_type"`
Description map[string]string `maxminddb:"description"`
IPVersion uint `maxminddb:"ip_version"`
Languages []string `maxminddb:"languages"`
NodeCount uint `maxminddb:"node_count"`
RecordSize uint `maxminddb:"record_size"`
}
// FromBytes takes a byte slice corresponding to a MaxMind DB file and returns
// a Reader structure or an error.
func FromBytes(buffer []byte) (*Reader, error) {
metadataStart := bytes.LastIndex(buffer, metadataStartMarker)
if metadataStart == -1 {
return nil, newInvalidDatabaseError("error opening database: invalid MaxMind DB file")
}
metadataStart += len(metadataStartMarker)
metadataDecoder := decoder{buffer[metadataStart:]}
var metadata Metadata
rvMetdata := reflect.ValueOf(&metadata)
_, err := metadataDecoder.decode(0, rvMetdata)
if err != nil {
return nil, err
}
searchTreeSize := metadata.NodeCount * metadata.RecordSize / 4
dataSectionStart := searchTreeSize + dataSectionSeparatorSize
dataSectionEnd := uint(metadataStart - len(metadataStartMarker))
if dataSectionStart > dataSectionEnd {
return nil, newInvalidDatabaseError("the MaxMind DB contains invalid metadata")
}
d := decoder{
buffer[searchTreeSize+dataSectionSeparatorSize : metadataStart-len(metadataStartMarker)],
}
reader := &Reader{
buffer: buffer,
decoder: d,
Metadata: metadata,
ipv4Start: 0,
}
reader.ipv4Start, err = reader.startNode()
return reader, err
}
func (r *Reader) startNode() (uint, error) {
if r.Metadata.IPVersion != 6 {
return 0, nil
}
nodeCount := r.Metadata.NodeCount
node := uint(0)
var err error
for i := 0; i < 96 && node < nodeCount; i++ {
node, err = r.readNode(node, 0)
if err != nil {
return 0, err
}
}
return node, err
}
// Lookup takes an IP address as a net.IP structure and a pointer to the
// result value to Decode into.
func (r *Reader) Lookup(ipAddress net.IP, result interface{}) error {
pointer, err := r.lookupPointer(ipAddress)
if pointer == 0 || err != nil {
return err
}
return r.retrieveData(pointer, result)
}
// LookupOffset maps an argument net.IP to a corresponding record offset in the
// database. NotFound is returned if no such record is found, and a record may
// otherwise be extracted by passing the returned offset to Decode. LookupOffset
// is an advanced API, which exists to provide clients with a means to cache
// previously-decoded records.
func (r *Reader) LookupOffset(ipAddress net.IP) (uintptr, error) {
pointer, err := r.lookupPointer(ipAddress)
if pointer == 0 || err != nil {
return NotFound, err
}
return r.resolveDataPointer(pointer)
}
// Decode the record at |offset| into |result|. The result value pointed to
// must be a data value that corresponds to a record in the database. This may
// include a struct representation of the data, a map capable of holding the
// data or an empty interface{} value.
//
// If result is a pointer to a struct, the struct need not include a field
// for every value that may be in the database. If a field is not present in
// the structure, the decoder will not decode that field, reducing the time
// required to decode the record.
//
// As a special case, a struct field of type uintptr will be used to capture
// the offset of the value. Decode may later be used to extract the stored
// value from the offset. MaxMind DBs are highly normalized: for example in
// the City database, all records of the same country will reference a
// single representative record for that country. This uintptr behavior allows
// clients to leverage this normalization in their own sub-record caching.
func (r *Reader) Decode(offset uintptr, result interface{}) error {
rv := reflect.ValueOf(result)
if rv.Kind() != reflect.Ptr || rv.IsNil() {
return errors.New("result param must be a pointer")
}
_, err := r.decoder.decode(uint(offset), reflect.ValueOf(result))
return err
}
func (r *Reader) lookupPointer(ipAddress net.IP) (uint, error) {
if ipAddress == nil {
return 0, errors.New("ipAddress passed to Lookup cannot be nil")
}
ipV4Address := ipAddress.To4()
if ipV4Address != nil {
ipAddress = ipV4Address
}
if len(ipAddress) == 16 && r.Metadata.IPVersion == 4 {
return 0, fmt.Errorf("error looking up '%s': you attempted to look up an IPv6 address in an IPv4-only database", ipAddress.String())
}
return r.findAddressInTree(ipAddress)
}
func (r *Reader) findAddressInTree(ipAddress net.IP) (uint, error) {
bitCount := uint(len(ipAddress) * 8)
var node uint
if bitCount == 32 {
node = r.ipv4Start
}
nodeCount := r.Metadata.NodeCount
for i := uint(0); i < bitCount && node < nodeCount; i++ {
bit := uint(1) & (uint(ipAddress[i>>3]) >> (7 - (i % 8)))
var err error
node, err = r.readNode(node, bit)
if err != nil {
return 0, err
}
}
if node == nodeCount {
// Record is empty
return 0, nil
} else if node > nodeCount {
return node, nil
}
return 0, newInvalidDatabaseError("invalid node in search tree")
}
func (r *Reader) readNode(nodeNumber uint, index uint) (uint, error) {
RecordSize := r.Metadata.RecordSize
baseOffset := nodeNumber * RecordSize / 4
var nodeBytes []byte
var prefix uint64
switch RecordSize {
case 24:
offset := baseOffset + index*3
nodeBytes = r.buffer[offset : offset+3]
case 28:
prefix = uint64(r.buffer[baseOffset+3])
if index != 0 {
prefix &= 0x0F
} else {
prefix = (0xF0 & prefix) >> 4
}
offset := baseOffset + index*4
nodeBytes = r.buffer[offset : offset+3]
case 32:
offset := baseOffset + index*4
nodeBytes = r.buffer[offset : offset+4]
default:
return 0, newInvalidDatabaseError("unknown record size: %d", RecordSize)
}
return uint(uintFromBytes(prefix, nodeBytes)), nil
}
func (r *Reader) retrieveData(pointer uint, result interface{}) error {
if offset, err := r.resolveDataPointer(pointer); err != nil {
return err
} else {
return r.Decode(offset, result)
}
}
func (r *Reader) resolveDataPointer(pointer uint) (uintptr, error) {
var resolved = uintptr(pointer - r.Metadata.NodeCount - dataSectionSeparatorSize)
if resolved > uintptr(len(r.buffer)) {
return 0, newInvalidDatabaseError("the MaxMind DB file's search tree is corrupt")
}
return resolved, nil
}

View File

@@ -0,0 +1,26 @@
// +build appengine
package maxminddb
import "io/ioutil"
// Open takes a string path to a MaxMind DB file and returns a Reader
// structure or an error. The database file is opened using a memory map,
// except on Google App Engine where mmap is not supported; there the database
// is loaded into memory. Use the Close method on the Reader object to return
// the resources to the system.
func Open(file string) (*Reader, error) {
bytes, err := ioutil.ReadFile(file)
if err != nil {
return nil, err
}
return FromBytes(bytes)
}
// Close unmaps the database file from virtual memory and returns the
// resources to the system. If called on a Reader opened using FromBytes
// or Open on Google App Engine, this method does nothing.
func (r *Reader) Close() error {
return nil
}

View File

@@ -0,0 +1,56 @@
// +build !appengine
package maxminddb
import "os"
// Open takes a string path to a MaxMind DB file and returns a Reader
// structure or an error. The database file is opened using a memory map,
// except on Google App Engine where mmap is not supported; there the database
// is loaded into memory. Use the Close method on the Reader object to return
// the resources to the system.
func Open(file string) (*Reader, error) {
mapFile, err := os.Open(file)
if err != nil {
return nil, err
}
defer func() {
if rerr := mapFile.Close(); rerr != nil {
err = rerr
}
}()
stats, err := mapFile.Stat()
if err != nil {
return nil, err
}
fileSize := int(stats.Size())
mmap, err := mmap(int(mapFile.Fd()), fileSize)
if err != nil {
return nil, err
}
reader, err := FromBytes(mmap)
if err != nil {
if err2 := munmap(mmap); err2 != nil {
// failing to unmap the file is probably the more severe error
return nil, err2
}
return nil, err
}
reader.hasMappedFile = true
return reader, err
}
// Close unmaps the database file from virtual memory and returns the
// resources to the system. If called on a Reader opened using FromBytes
// or Open on Google App Engine, this method does nothing.
func (r *Reader) Close() (err error) {
if r.hasMappedFile {
err = munmap(r.buffer)
r.hasMappedFile = false
}
return err
}

108
vendor/github.com/oschwald/maxminddb-golang/traverse.go generated vendored Normal file
View File

@@ -0,0 +1,108 @@
package maxminddb
import "net"
// Internal structure used to keep track of nodes we still need to visit.
type netNode struct {
ip net.IP
bit uint
pointer uint
}
// Networks represents a set of subnets that we are iterating over.
type Networks struct {
reader *Reader
nodes []netNode // Nodes we still have to visit.
lastNode netNode
err error
}
// Networks returns an iterator that can be used to traverse all networks in
// the database.
//
// Please note that a MaxMind DB may map IPv4 networks into several locations
// in in an IPv6 database. This iterator will iterate over all of these
// locations separately.
func (r *Reader) Networks() *Networks {
s := 4
if r.Metadata.IPVersion == 6 {
s = 16
}
return &Networks{
reader: r,
nodes: []netNode{
netNode{
ip: make(net.IP, s),
},
},
}
}
// Next prepares the next network for reading with the Network method. It
// returns true if there is another network to be processed and false if there
// are no more networks or if there is an error.
func (n *Networks) Next() bool {
for len(n.nodes) > 0 {
node := n.nodes[len(n.nodes)-1]
n.nodes = n.nodes[:len(n.nodes)-1]
for {
if node.pointer < n.reader.Metadata.NodeCount {
ipRight := make(net.IP, len(node.ip))
copy(ipRight, node.ip)
if len(ipRight) <= int(node.bit>>3) {
n.err = newInvalidDatabaseError(
"invalid search tree at %v/%v", ipRight, node.bit)
return false
}
ipRight[node.bit>>3] |= 1 << uint(7-(node.bit%8))
rightPointer, err := n.reader.readNode(node.pointer, 1)
if err != nil {
n.err = err
return false
}
node.bit++
n.nodes = append(n.nodes, netNode{
pointer: rightPointer,
ip: ipRight,
bit: node.bit,
})
node.pointer, err = n.reader.readNode(node.pointer, 0)
if err != nil {
n.err = err
return false
}
} else if node.pointer > n.reader.Metadata.NodeCount {
n.lastNode = node
return true
} else {
break
}
}
}
return false
}
// Network returns the current network or an error if there is a problem
// decoding the data for the network. It takes a pointer to a result value to
// decode the network's data into.
func (n *Networks) Network(result interface{}) (*net.IPNet, error) {
if err := n.reader.retrieveData(n.lastNode.pointer, result); err != nil {
return nil, err
}
return &net.IPNet{
IP: n.lastNode.ip,
Mask: net.CIDRMask(int(n.lastNode.bit), len(n.lastNode.ip)*8),
}, nil
}
// Err returns an error, if any, that was encountered during iteration.
func (n *Networks) Err() error {
return n.err
}

185
vendor/github.com/oschwald/maxminddb-golang/verifier.go generated vendored Normal file
View File

@@ -0,0 +1,185 @@
package maxminddb
import "reflect"
type verifier struct {
reader *Reader
}
// Verify checks that the database is valid. It validates the search tree,
// the data section, and the metadata section. This verifier is stricter than
// the specification and may return errors on databases that are readable.
func (r *Reader) Verify() error {
v := verifier{r}
if err := v.verifyMetadata(); err != nil {
return err
}
return v.verifyDatabase()
}
func (v *verifier) verifyMetadata() error {
metadata := v.reader.Metadata
if metadata.BinaryFormatMajorVersion != 2 {
return testError(
"binary_format_major_version",
2,
metadata.BinaryFormatMajorVersion,
)
}
if metadata.BinaryFormatMinorVersion != 0 {
return testError(
"binary_format_minor_version",
0,
metadata.BinaryFormatMinorVersion,
)
}
if metadata.DatabaseType == "" {
return testError(
"database_type",
"non-empty string",
metadata.DatabaseType,
)
}
if len(metadata.Description) == 0 {
return testError(
"description",
"non-empty slice",
metadata.Description,
)
}
if metadata.IPVersion != 4 && metadata.IPVersion != 6 {
return testError(
"ip_version",
"4 or 6",
metadata.IPVersion,
)
}
if metadata.RecordSize != 24 &&
metadata.RecordSize != 28 &&
metadata.RecordSize != 32 {
return testError(
"record_size",
"24, 28, or 32",
metadata.RecordSize,
)
}
if metadata.NodeCount == 0 {
return testError(
"node_count",
"positive integer",
metadata.NodeCount,
)
}
return nil
}
func (v *verifier) verifyDatabase() error {
offsets, err := v.verifySearchTree()
if err != nil {
return err
}
if err := v.verifyDataSectionSeparator(); err != nil {
return err
}
return v.verifyDataSection(offsets)
}
func (v *verifier) verifySearchTree() (map[uint]bool, error) {
offsets := make(map[uint]bool)
it := v.reader.Networks()
for it.Next() {
offset, err := v.reader.resolveDataPointer(it.lastNode.pointer)
if err != nil {
return nil, err
}
offsets[uint(offset)] = true
}
if err := it.Err(); err != nil {
return nil, err
}
return offsets, nil
}
func (v *verifier) verifyDataSectionSeparator() error {
separatorStart := v.reader.Metadata.NodeCount * v.reader.Metadata.RecordSize / 4
separator := v.reader.buffer[separatorStart : separatorStart+dataSectionSeparatorSize]
for _, b := range separator {
if b != 0 {
return newInvalidDatabaseError("unexpected byte in data separator: %v", separator)
}
}
return nil
}
func (v *verifier) verifyDataSection(offsets map[uint]bool) error {
pointerCount := len(offsets)
decoder := v.reader.decoder
var offset uint
bufferLen := uint(len(decoder.buffer))
for offset < bufferLen {
var data interface{}
rv := reflect.ValueOf(&data)
newOffset, err := decoder.decode(offset, rv)
if err != nil {
return newInvalidDatabaseError("received decoding error (%v) at offset of %v", err, offset)
}
if newOffset <= offset {
return newInvalidDatabaseError("data section offset unexpectedly went from %v to %v", offset, newOffset)
}
pointer := offset
if _, ok := offsets[pointer]; ok {
delete(offsets, pointer)
} else {
return newInvalidDatabaseError("found data (%v) at %v that the search tree does not point to", data, pointer)
}
offset = newOffset
}
if offset != bufferLen {
return newInvalidDatabaseError(
"unexpected data at the end of the data section (last offset: %v, end: %v)",
offset,
bufferLen,
)
}
if len(offsets) != 0 {
return newInvalidDatabaseError(
"found %v pointers (of %v) in the search tree that we did not see in the data section",
len(offsets),
pointerCount,
)
}
return nil
}
func testError(
field string,
expected interface{},
actual interface{},
) error {
return newInvalidDatabaseError(
"%v - Expected: %v Actual: %v",
field,
expected,
actual,
)
}