mirror of
https://github.com/octoleo/syncthing.git
synced 2024-11-09 14:50:56 +00:00
Update dependencies
This commit is contained in:
parent
145c8e4063
commit
75cfa4c33e
11
Godeps/Godeps.json
generated
11
Godeps/Godeps.json
generated
@ -7,8 +7,8 @@
|
|||||||
"Deps": [
|
"Deps": [
|
||||||
{
|
{
|
||||||
"ImportPath": "code.google.com/p/go.net/ipv6",
|
"ImportPath": "code.google.com/p/go.net/ipv6",
|
||||||
"Comment": "null-88",
|
"Comment": "null-117",
|
||||||
"Rev": "55437409069bb181ad562b1ad1e5f361c44aff17"
|
"Rev": "c17ad62118ea511e1051721b429779fa40bddc74"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "code.google.com/p/go.text/transform",
|
"ImportPath": "code.google.com/p/go.text/transform",
|
||||||
@ -22,15 +22,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/calmh/ini",
|
"ImportPath": "github.com/calmh/ini",
|
||||||
"Rev": "1020b6d8618a7dc6031cda4a7782324eac346875"
|
"Rev": "386c4240a9684d91d9ec4d93651909b49c7269e1"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/codegangsta/inject",
|
"ImportPath": "github.com/codegangsta/inject",
|
||||||
"Rev": "37512bbe41b4cc579cdd706742efc7bf34f94b06"
|
"Rev": "9aea7a2fa5b79ef7fc00f63a575e72df33b4e886"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/codegangsta/martini",
|
"ImportPath": "github.com/codegangsta/martini",
|
||||||
"Rev": "f86ef0561cc5aa2801d41a7277fd480272ad1556"
|
"Comment": "v0.1-142-g8659df7",
|
||||||
|
"Rev": "8659df7a51aebe6c6120268cd5a8b4c34fa8441a"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
1
Godeps/_workspace/src/code.google.com/p/go.net/ipv6/control.go
generated
vendored
1
Godeps/_workspace/src/code.google.com/p/go.net/ipv6/control.go
generated
vendored
@ -12,7 +12,6 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
errNotSupported = errors.New("not supported")
|
|
||||||
errMissingAddress = errors.New("missing address")
|
errMissingAddress = errors.New("missing address")
|
||||||
errInvalidConnType = errors.New("invalid conn type")
|
errInvalidConnType = errors.New("invalid conn type")
|
||||||
errNoSuchInterface = errors.New("no such interface")
|
errNoSuchInterface = errors.New("no such interface")
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build darwin
|
||||||
|
|
||||||
package ipv6
|
package ipv6
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -47,23 +49,23 @@ func newControlMessage(opt *rawOpt) (oob []byte) {
|
|||||||
l += syscall.CmsgSpace(4)
|
l += syscall.CmsgSpace(4)
|
||||||
}
|
}
|
||||||
if opt.isset(pktinfo) {
|
if opt.isset(pktinfo) {
|
||||||
l += syscall.CmsgSpace(syscall.SizeofInet6Pktinfo)
|
l += syscall.CmsgSpace(sysSizeofPacketInfo)
|
||||||
}
|
}
|
||||||
if l > 0 {
|
if l > 0 {
|
||||||
oob = make([]byte, l)
|
oob = make([]byte, l)
|
||||||
if opt.isset(FlagHopLimit) {
|
if opt.isset(FlagHopLimit) {
|
||||||
m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
|
m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
|
||||||
m.Level = ianaProtocolIPv6
|
m.Level = ianaProtocolIPv6
|
||||||
m.Type = syscall.IPV6_2292HOPLIMIT
|
m.Type = sysSockopt2292HopLimit
|
||||||
m.SetLen(syscall.CmsgLen(4))
|
m.SetLen(syscall.CmsgLen(4))
|
||||||
off += syscall.CmsgSpace(4)
|
off += syscall.CmsgSpace(4)
|
||||||
}
|
}
|
||||||
if opt.isset(pktinfo) {
|
if opt.isset(pktinfo) {
|
||||||
m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
|
m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
|
||||||
m.Level = ianaProtocolIPv6
|
m.Level = ianaProtocolIPv6
|
||||||
m.Type = syscall.IPV6_2292PKTINFO
|
m.Type = sysSockopt2292PacketInfo
|
||||||
m.SetLen(syscall.CmsgLen(syscall.SizeofInet6Pktinfo))
|
m.SetLen(syscall.CmsgLen(sysSizeofPacketInfo))
|
||||||
off += syscall.CmsgSpace(syscall.SizeofInet6Pktinfo)
|
off += syscall.CmsgSpace(sysSizeofPacketInfo)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
@ -83,12 +85,12 @@ func parseControlMessage(b []byte) (*ControlMessage, error) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
switch m.Header.Type {
|
switch m.Header.Type {
|
||||||
case syscall.IPV6_2292HOPLIMIT:
|
case sysSockopt2292HopLimit:
|
||||||
cm.HopLimit = int(*(*byte)(unsafe.Pointer(&m.Data[:1][0])))
|
cm.HopLimit = int(*(*byte)(unsafe.Pointer(&m.Data[:1][0])))
|
||||||
case syscall.IPV6_2292PKTINFO:
|
case sysSockopt2292PacketInfo:
|
||||||
pi := (*syscall.Inet6Pktinfo)(unsafe.Pointer(&m.Data[0]))
|
pi := (*sysPacketInfo)(unsafe.Pointer(&m.Data[0]))
|
||||||
cm.IfIndex = int(pi.Ifindex)
|
cm.IfIndex = int(pi.IfIndex)
|
||||||
cm.Dst = pi.Addr[:]
|
cm.Dst = pi.IP[:]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return cm, nil
|
return cm, nil
|
||||||
@ -105,7 +107,7 @@ func marshalControlMessage(cm *ControlMessage) (oob []byte) {
|
|||||||
pion := false
|
pion := false
|
||||||
if cm.Src.To4() == nil && cm.Src.To16() != nil || cm.IfIndex != 0 {
|
if cm.Src.To4() == nil && cm.Src.To16() != nil || cm.IfIndex != 0 {
|
||||||
pion = true
|
pion = true
|
||||||
l += syscall.CmsgSpace(syscall.SizeofInet6Pktinfo)
|
l += syscall.CmsgSpace(sysSizeofPacketInfo)
|
||||||
}
|
}
|
||||||
if len(cm.NextHop) == net.IPv6len {
|
if len(cm.NextHop) == net.IPv6len {
|
||||||
l += syscall.CmsgSpace(syscall.SizeofSockaddrInet6)
|
l += syscall.CmsgSpace(syscall.SizeofSockaddrInet6)
|
||||||
@ -115,7 +117,7 @@ func marshalControlMessage(cm *ControlMessage) (oob []byte) {
|
|||||||
if cm.HopLimit > 0 {
|
if cm.HopLimit > 0 {
|
||||||
m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
|
m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
|
||||||
m.Level = ianaProtocolIPv6
|
m.Level = ianaProtocolIPv6
|
||||||
m.Type = syscall.IPV6_2292HOPLIMIT
|
m.Type = sysSockopt2292HopLimit
|
||||||
m.SetLen(syscall.CmsgLen(4))
|
m.SetLen(syscall.CmsgLen(4))
|
||||||
data := oob[off+syscall.CmsgLen(0):]
|
data := oob[off+syscall.CmsgLen(0):]
|
||||||
*(*byte)(unsafe.Pointer(&data[:1][0])) = byte(cm.HopLimit)
|
*(*byte)(unsafe.Pointer(&data[:1][0])) = byte(cm.HopLimit)
|
||||||
@ -124,26 +126,24 @@ func marshalControlMessage(cm *ControlMessage) (oob []byte) {
|
|||||||
if pion {
|
if pion {
|
||||||
m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
|
m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
|
||||||
m.Level = ianaProtocolIPv6
|
m.Level = ianaProtocolIPv6
|
||||||
m.Type = syscall.IPV6_2292PKTINFO
|
m.Type = sysSockopt2292PacketInfo
|
||||||
m.SetLen(syscall.CmsgLen(syscall.SizeofInet6Pktinfo))
|
m.SetLen(syscall.CmsgLen(sysSizeofPacketInfo))
|
||||||
pi := (*syscall.Inet6Pktinfo)(unsafe.Pointer(&oob[off+syscall.CmsgLen(0)]))
|
pi := (*sysPacketInfo)(unsafe.Pointer(&oob[off+syscall.CmsgLen(0)]))
|
||||||
if ip := cm.Src.To16(); ip != nil && ip.To4() == nil {
|
if ip := cm.Src.To16(); ip != nil && ip.To4() == nil {
|
||||||
copy(pi.Addr[:], ip)
|
copy(pi.IP[:], ip)
|
||||||
}
|
}
|
||||||
if cm.IfIndex != 0 {
|
if cm.IfIndex != 0 {
|
||||||
pi.Ifindex = uint32(cm.IfIndex)
|
pi.IfIndex = uint32(cm.IfIndex)
|
||||||
}
|
}
|
||||||
off += syscall.CmsgSpace(syscall.SizeofInet6Pktinfo)
|
off += syscall.CmsgSpace(sysSizeofPacketInfo)
|
||||||
}
|
}
|
||||||
if len(cm.NextHop) == net.IPv6len {
|
if len(cm.NextHop) == net.IPv6len {
|
||||||
m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
|
m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
|
||||||
m.Level = ianaProtocolIPv6
|
m.Level = ianaProtocolIPv6
|
||||||
m.Type = syscall.IPV6_2292NEXTHOP
|
m.Type = sysSockopt2292NextHop
|
||||||
m.SetLen(syscall.CmsgLen(syscall.SizeofSockaddrInet6))
|
m.SetLen(syscall.CmsgLen(syscall.SizeofSockaddrInet6))
|
||||||
sa := (*syscall.RawSockaddrInet6)(unsafe.Pointer(&oob[off+syscall.CmsgLen(0)]))
|
sa := (*syscall.RawSockaddrInet6)(unsafe.Pointer(&oob[off+syscall.CmsgLen(0)]))
|
||||||
sa.Len = syscall.SizeofSockaddrInet6
|
setSockaddr(sa, cm.NextHop, cm.IfIndex)
|
||||||
sa.Family = syscall.AF_INET6
|
|
||||||
copy(sa.Addr[:], cm.NextHop)
|
|
||||||
off += syscall.CmsgSpace(syscall.SizeofSockaddrInet6)
|
off += syscall.CmsgSpace(syscall.SizeofSockaddrInet6)
|
||||||
}
|
}
|
||||||
}
|
}
|
217
Godeps/_workspace/src/code.google.com/p/go.net/ipv6/control_rfc3542_linux.go
generated
vendored
217
Godeps/_workspace/src/code.google.com/p/go.net/ipv6/control_rfc3542_linux.go
generated
vendored
@ -1,217 +0,0 @@
|
|||||||
// 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.
|
|
||||||
|
|
||||||
package ipv6
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net"
|
|
||||||
"os"
|
|
||||||
"syscall"
|
|
||||||
"unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// See /usr/include/linux/in6.h.
|
|
||||||
syscall_IPV6_RECVPATHMTU = syscall.IPV6_DSTOPTS + 1 + iota
|
|
||||||
syscall_IPV6_PATHMTU
|
|
||||||
syscall_IPV6_DONTFRAG
|
|
||||||
)
|
|
||||||
|
|
||||||
const pktinfo = FlagDst | FlagInterface
|
|
||||||
|
|
||||||
func setControlMessage(fd int, opt *rawOpt, cf ControlFlags, on bool) error {
|
|
||||||
opt.Lock()
|
|
||||||
defer opt.Unlock()
|
|
||||||
if cf&FlagTrafficClass != 0 {
|
|
||||||
if err := setIPv6ReceiveTrafficClass(fd, on); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if on {
|
|
||||||
opt.set(FlagTrafficClass)
|
|
||||||
} else {
|
|
||||||
opt.clear(FlagTrafficClass)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if cf&FlagHopLimit != 0 {
|
|
||||||
if err := setIPv6ReceiveHopLimit(fd, on); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if on {
|
|
||||||
opt.set(FlagHopLimit)
|
|
||||||
} else {
|
|
||||||
opt.clear(FlagHopLimit)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if cf&pktinfo != 0 {
|
|
||||||
if err := setIPv6ReceivePacketInfo(fd, on); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if on {
|
|
||||||
opt.set(cf & pktinfo)
|
|
||||||
} else {
|
|
||||||
opt.clear(cf & pktinfo)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if cf&FlagPathMTU != 0 {
|
|
||||||
if err := setIPv6ReceivePathMTU(fd, on); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if on {
|
|
||||||
opt.set(FlagPathMTU)
|
|
||||||
} else {
|
|
||||||
opt.clear(FlagPathMTU)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func newControlMessage(opt *rawOpt) (oob []byte) {
|
|
||||||
opt.Lock()
|
|
||||||
defer opt.Unlock()
|
|
||||||
l, off := 0, 0
|
|
||||||
if opt.isset(FlagTrafficClass) {
|
|
||||||
l += syscall.CmsgSpace(4)
|
|
||||||
}
|
|
||||||
if opt.isset(FlagHopLimit) {
|
|
||||||
l += syscall.CmsgSpace(4)
|
|
||||||
}
|
|
||||||
if opt.isset(pktinfo) {
|
|
||||||
l += syscall.CmsgSpace(syscall.SizeofInet6Pktinfo)
|
|
||||||
}
|
|
||||||
if opt.isset(FlagPathMTU) {
|
|
||||||
l += syscall.CmsgSpace(syscall.SizeofIPv6MTUInfo)
|
|
||||||
}
|
|
||||||
if l > 0 {
|
|
||||||
oob = make([]byte, l)
|
|
||||||
if opt.isset(FlagTrafficClass) {
|
|
||||||
m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
|
|
||||||
m.Level = ianaProtocolIPv6
|
|
||||||
m.Type = syscall.IPV6_RECVTCLASS
|
|
||||||
m.SetLen(syscall.CmsgLen(4))
|
|
||||||
off += syscall.CmsgSpace(4)
|
|
||||||
}
|
|
||||||
if opt.isset(FlagHopLimit) {
|
|
||||||
m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
|
|
||||||
m.Level = ianaProtocolIPv6
|
|
||||||
m.Type = syscall.IPV6_RECVHOPLIMIT
|
|
||||||
m.SetLen(syscall.CmsgLen(4))
|
|
||||||
off += syscall.CmsgSpace(4)
|
|
||||||
}
|
|
||||||
if opt.isset(pktinfo) {
|
|
||||||
m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
|
|
||||||
m.Level = ianaProtocolIPv6
|
|
||||||
m.Type = syscall.IPV6_RECVPKTINFO
|
|
||||||
m.SetLen(syscall.CmsgLen(syscall.SizeofInet6Pktinfo))
|
|
||||||
off += syscall.CmsgSpace(syscall.SizeofInet6Pktinfo)
|
|
||||||
}
|
|
||||||
if opt.isset(FlagPathMTU) {
|
|
||||||
m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
|
|
||||||
m.Level = ianaProtocolIPv6
|
|
||||||
m.Type = syscall_IPV6_RECVPATHMTU
|
|
||||||
m.SetLen(syscall.CmsgLen(syscall.SizeofIPv6MTUInfo))
|
|
||||||
off += syscall.CmsgSpace(syscall.SizeofIPv6MTUInfo)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseControlMessage(b []byte) (*ControlMessage, error) {
|
|
||||||
if len(b) == 0 {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
cmsgs, err := syscall.ParseSocketControlMessage(b)
|
|
||||||
if err != nil {
|
|
||||||
return nil, os.NewSyscallError("parse socket control message", err)
|
|
||||||
}
|
|
||||||
cm := &ControlMessage{}
|
|
||||||
for _, m := range cmsgs {
|
|
||||||
if m.Header.Level != ianaProtocolIPv6 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
switch m.Header.Type {
|
|
||||||
case syscall.IPV6_TCLASS:
|
|
||||||
cm.TrafficClass = int(*(*byte)(unsafe.Pointer(&m.Data[:1][0])))
|
|
||||||
case syscall.IPV6_HOPLIMIT:
|
|
||||||
cm.HopLimit = int(*(*byte)(unsafe.Pointer(&m.Data[:1][0])))
|
|
||||||
case syscall.IPV6_PKTINFO:
|
|
||||||
pi := (*syscall.Inet6Pktinfo)(unsafe.Pointer(&m.Data[0]))
|
|
||||||
cm.Dst = pi.Addr[:]
|
|
||||||
cm.IfIndex = int(pi.Ifindex)
|
|
||||||
case syscall_IPV6_PATHMTU:
|
|
||||||
mi := (*syscall.IPv6MTUInfo)(unsafe.Pointer(&m.Data[0]))
|
|
||||||
cm.Dst = mi.Addr.Addr[:]
|
|
||||||
cm.IfIndex = int(mi.Addr.Scope_id)
|
|
||||||
cm.MTU = int(mi.Mtu)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return cm, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func marshalControlMessage(cm *ControlMessage) (oob []byte) {
|
|
||||||
if cm == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
l, off := 0, 0
|
|
||||||
if cm.TrafficClass > 0 {
|
|
||||||
l += syscall.CmsgSpace(4)
|
|
||||||
}
|
|
||||||
if cm.HopLimit > 0 {
|
|
||||||
l += syscall.CmsgSpace(4)
|
|
||||||
}
|
|
||||||
pion := false
|
|
||||||
if cm.Src.To4() == nil && cm.Src.To16() != nil || cm.IfIndex != 0 {
|
|
||||||
pion = true
|
|
||||||
l += syscall.CmsgSpace(syscall.SizeofInet6Pktinfo)
|
|
||||||
}
|
|
||||||
if len(cm.NextHop) == net.IPv6len {
|
|
||||||
l += syscall.CmsgSpace(syscall.SizeofSockaddrInet6)
|
|
||||||
}
|
|
||||||
if l > 0 {
|
|
||||||
oob = make([]byte, l)
|
|
||||||
if cm.TrafficClass > 0 {
|
|
||||||
m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
|
|
||||||
m.Level = ianaProtocolIPv6
|
|
||||||
m.Type = syscall.IPV6_TCLASS
|
|
||||||
m.SetLen(syscall.CmsgLen(4))
|
|
||||||
data := oob[off+syscall.CmsgLen(0):]
|
|
||||||
*(*byte)(unsafe.Pointer(&data[:1][0])) = byte(cm.TrafficClass)
|
|
||||||
off += syscall.CmsgSpace(4)
|
|
||||||
}
|
|
||||||
if cm.HopLimit > 0 {
|
|
||||||
m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
|
|
||||||
m.Level = ianaProtocolIPv6
|
|
||||||
m.Type = syscall.IPV6_HOPLIMIT
|
|
||||||
m.SetLen(syscall.CmsgLen(4))
|
|
||||||
data := oob[off+syscall.CmsgLen(0):]
|
|
||||||
*(*byte)(unsafe.Pointer(&data[:1][0])) = byte(cm.HopLimit)
|
|
||||||
off += syscall.CmsgSpace(4)
|
|
||||||
}
|
|
||||||
if pion {
|
|
||||||
m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
|
|
||||||
m.Level = ianaProtocolIPv6
|
|
||||||
m.Type = syscall.IPV6_PKTINFO
|
|
||||||
m.SetLen(syscall.CmsgLen(syscall.SizeofInet6Pktinfo))
|
|
||||||
pi := (*syscall.Inet6Pktinfo)(unsafe.Pointer(&oob[off+syscall.CmsgLen(0)]))
|
|
||||||
if ip := cm.Src.To16(); ip != nil && ip.To4() == nil {
|
|
||||||
copy(pi.Addr[:], ip)
|
|
||||||
}
|
|
||||||
if cm.IfIndex != 0 {
|
|
||||||
pi.Ifindex = uint32(cm.IfIndex)
|
|
||||||
}
|
|
||||||
off += syscall.CmsgSpace(syscall.SizeofInet6Pktinfo)
|
|
||||||
}
|
|
||||||
if len(cm.NextHop) == net.IPv6len {
|
|
||||||
m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
|
|
||||||
m.Level = ianaProtocolIPv6
|
|
||||||
m.Type = syscall.IPV6_NEXTHOP
|
|
||||||
m.SetLen(syscall.CmsgLen(syscall.SizeofSockaddrInet6))
|
|
||||||
sa := (*syscall.RawSockaddrInet6)(unsafe.Pointer(&oob[off+syscall.CmsgLen(0)]))
|
|
||||||
sa.Family = syscall.AF_INET6
|
|
||||||
copy(sa.Addr[:], cm.NextHop)
|
|
||||||
sa.Scope_id = uint32(cm.IfIndex)
|
|
||||||
off += syscall.CmsgSpace(syscall.SizeofSockaddrInet6)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
@ -2,13 +2,13 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package ipv6
|
// +build dragonfly plan9 solaris
|
||||||
|
|
||||||
import "syscall"
|
package ipv6
|
||||||
|
|
||||||
func setControlMessage(fd int, opt *rawOpt, cf ControlFlags, on bool) error {
|
func setControlMessage(fd int, opt *rawOpt, cf ControlFlags, on bool) error {
|
||||||
// TODO(mikio): Implement this
|
// TODO(mikio): Implement this
|
||||||
return syscall.EPLAN9
|
return errOpNoSupport
|
||||||
}
|
}
|
||||||
|
|
||||||
func newControlMessage(opt *rawOpt) (oob []byte) {
|
func newControlMessage(opt *rawOpt) (oob []byte) {
|
||||||
@ -18,7 +18,7 @@ func newControlMessage(opt *rawOpt) (oob []byte) {
|
|||||||
|
|
||||||
func parseControlMessage(b []byte) (*ControlMessage, error) {
|
func parseControlMessage(b []byte) (*ControlMessage, error) {
|
||||||
// TODO(mikio): Implement this
|
// TODO(mikio): Implement this
|
||||||
return nil, syscall.EPLAN9
|
return nil, errOpNoSupport
|
||||||
}
|
}
|
||||||
|
|
||||||
func marshalControlMessage(cm *ControlMessage) (oob []byte) {
|
func marshalControlMessage(cm *ControlMessage) (oob []byte) {
|
@ -2,7 +2,7 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
// +build freebsd netbsd openbsd
|
// +build freebsd linux netbsd openbsd
|
||||||
|
|
||||||
package ipv6
|
package ipv6
|
||||||
|
|
||||||
@ -72,40 +72,40 @@ func newControlMessage(opt *rawOpt) (oob []byte) {
|
|||||||
l += syscall.CmsgSpace(4)
|
l += syscall.CmsgSpace(4)
|
||||||
}
|
}
|
||||||
if opt.isset(pktinfo) {
|
if opt.isset(pktinfo) {
|
||||||
l += syscall.CmsgSpace(syscall.SizeofInet6Pktinfo)
|
l += syscall.CmsgSpace(sysSizeofPacketInfo)
|
||||||
}
|
}
|
||||||
if opt.isset(FlagPathMTU) {
|
if opt.isset(FlagPathMTU) {
|
||||||
l += syscall.CmsgSpace(syscall.SizeofIPv6MTUInfo)
|
l += syscall.CmsgSpace(sysSizeofMTUInfo)
|
||||||
}
|
}
|
||||||
if l > 0 {
|
if l > 0 {
|
||||||
oob = make([]byte, l)
|
oob = make([]byte, l)
|
||||||
if opt.isset(FlagTrafficClass) {
|
if opt.isset(FlagTrafficClass) {
|
||||||
m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
|
m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
|
||||||
m.Level = ianaProtocolIPv6
|
m.Level = ianaProtocolIPv6
|
||||||
m.Type = syscall.IPV6_RECVTCLASS
|
m.Type = sysSockoptReceiveTrafficClass
|
||||||
m.SetLen(syscall.CmsgLen(4))
|
m.SetLen(syscall.CmsgLen(4))
|
||||||
off += syscall.CmsgSpace(4)
|
off += syscall.CmsgSpace(4)
|
||||||
}
|
}
|
||||||
if opt.isset(FlagHopLimit) {
|
if opt.isset(FlagHopLimit) {
|
||||||
m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
|
m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
|
||||||
m.Level = ianaProtocolIPv6
|
m.Level = ianaProtocolIPv6
|
||||||
m.Type = syscall.IPV6_RECVHOPLIMIT
|
m.Type = sysSockoptReceiveHopLimit
|
||||||
m.SetLen(syscall.CmsgLen(4))
|
m.SetLen(syscall.CmsgLen(4))
|
||||||
off += syscall.CmsgSpace(4)
|
off += syscall.CmsgSpace(4)
|
||||||
}
|
}
|
||||||
if opt.isset(pktinfo) {
|
if opt.isset(pktinfo) {
|
||||||
m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
|
m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
|
||||||
m.Level = ianaProtocolIPv6
|
m.Level = ianaProtocolIPv6
|
||||||
m.Type = syscall.IPV6_RECVPKTINFO
|
m.Type = sysSockoptReceivePacketInfo
|
||||||
m.SetLen(syscall.CmsgLen(syscall.SizeofInet6Pktinfo))
|
m.SetLen(syscall.CmsgLen(sysSizeofPacketInfo))
|
||||||
off += syscall.CmsgSpace(syscall.SizeofInet6Pktinfo)
|
off += syscall.CmsgSpace(sysSizeofPacketInfo)
|
||||||
}
|
}
|
||||||
if opt.isset(FlagPathMTU) {
|
if opt.isset(FlagPathMTU) {
|
||||||
m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
|
m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
|
||||||
m.Level = ianaProtocolIPv6
|
m.Level = ianaProtocolIPv6
|
||||||
m.Type = syscall.IPV6_RECVPATHMTU
|
m.Type = sysSockoptReceivePathMTU
|
||||||
m.SetLen(syscall.CmsgLen(syscall.SizeofIPv6MTUInfo))
|
m.SetLen(syscall.CmsgLen(sysSizeofMTUInfo))
|
||||||
off += syscall.CmsgSpace(syscall.SizeofIPv6MTUInfo)
|
off += syscall.CmsgSpace(sysSizeofMTUInfo)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
@ -125,19 +125,19 @@ func parseControlMessage(b []byte) (*ControlMessage, error) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
switch m.Header.Type {
|
switch m.Header.Type {
|
||||||
case syscall.IPV6_TCLASS:
|
case sysSockoptTrafficClass:
|
||||||
cm.TrafficClass = int(*(*byte)(unsafe.Pointer(&m.Data[:1][0])))
|
cm.TrafficClass = int(*(*byte)(unsafe.Pointer(&m.Data[:1][0])))
|
||||||
case syscall.IPV6_HOPLIMIT:
|
case sysSockoptHopLimit:
|
||||||
cm.HopLimit = int(*(*byte)(unsafe.Pointer(&m.Data[:1][0])))
|
cm.HopLimit = int(*(*byte)(unsafe.Pointer(&m.Data[:1][0])))
|
||||||
case syscall.IPV6_PKTINFO:
|
case sysSockoptPacketInfo:
|
||||||
pi := (*syscall.Inet6Pktinfo)(unsafe.Pointer(&m.Data[0]))
|
pi := (*sysPacketInfo)(unsafe.Pointer(&m.Data[0]))
|
||||||
cm.Dst = pi.Addr[:]
|
cm.Dst = pi.IP[:]
|
||||||
cm.IfIndex = int(pi.Ifindex)
|
cm.IfIndex = int(pi.IfIndex)
|
||||||
case syscall.IPV6_PATHMTU:
|
case sysSockoptPathMTU:
|
||||||
mi := (*syscall.IPv6MTUInfo)(unsafe.Pointer(&m.Data[0]))
|
mi := (*sysMTUInfo)(unsafe.Pointer(&m.Data[0]))
|
||||||
cm.Dst = mi.Addr.Addr[:]
|
cm.Dst = mi.Addr.Addr[:]
|
||||||
cm.IfIndex = int(mi.Addr.Scope_id)
|
cm.IfIndex = int(mi.Addr.Scope_id)
|
||||||
cm.MTU = int(mi.Mtu)
|
cm.MTU = int(mi.MTU)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return cm, nil
|
return cm, nil
|
||||||
@ -157,7 +157,7 @@ func marshalControlMessage(cm *ControlMessage) (oob []byte) {
|
|||||||
pion := false
|
pion := false
|
||||||
if cm.Src.To4() == nil && cm.Src.To16() != nil || cm.IfIndex != 0 {
|
if cm.Src.To4() == nil && cm.Src.To16() != nil || cm.IfIndex != 0 {
|
||||||
pion = true
|
pion = true
|
||||||
l += syscall.CmsgSpace(syscall.SizeofInet6Pktinfo)
|
l += syscall.CmsgSpace(sysSizeofPacketInfo)
|
||||||
}
|
}
|
||||||
if len(cm.NextHop) == net.IPv6len {
|
if len(cm.NextHop) == net.IPv6len {
|
||||||
l += syscall.CmsgSpace(syscall.SizeofSockaddrInet6)
|
l += syscall.CmsgSpace(syscall.SizeofSockaddrInet6)
|
||||||
@ -167,7 +167,7 @@ func marshalControlMessage(cm *ControlMessage) (oob []byte) {
|
|||||||
if cm.TrafficClass > 0 {
|
if cm.TrafficClass > 0 {
|
||||||
m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
|
m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
|
||||||
m.Level = ianaProtocolIPv6
|
m.Level = ianaProtocolIPv6
|
||||||
m.Type = syscall.IPV6_TCLASS
|
m.Type = sysSockoptTrafficClass
|
||||||
m.SetLen(syscall.CmsgLen(4))
|
m.SetLen(syscall.CmsgLen(4))
|
||||||
data := oob[off+syscall.CmsgLen(0):]
|
data := oob[off+syscall.CmsgLen(0):]
|
||||||
*(*byte)(unsafe.Pointer(&data[:1][0])) = byte(cm.TrafficClass)
|
*(*byte)(unsafe.Pointer(&data[:1][0])) = byte(cm.TrafficClass)
|
||||||
@ -176,7 +176,7 @@ func marshalControlMessage(cm *ControlMessage) (oob []byte) {
|
|||||||
if cm.HopLimit > 0 {
|
if cm.HopLimit > 0 {
|
||||||
m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
|
m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
|
||||||
m.Level = ianaProtocolIPv6
|
m.Level = ianaProtocolIPv6
|
||||||
m.Type = syscall.IPV6_HOPLIMIT
|
m.Type = sysSockoptHopLimit
|
||||||
m.SetLen(syscall.CmsgLen(4))
|
m.SetLen(syscall.CmsgLen(4))
|
||||||
data := oob[off+syscall.CmsgLen(0):]
|
data := oob[off+syscall.CmsgLen(0):]
|
||||||
*(*byte)(unsafe.Pointer(&data[:1][0])) = byte(cm.HopLimit)
|
*(*byte)(unsafe.Pointer(&data[:1][0])) = byte(cm.HopLimit)
|
||||||
@ -185,27 +185,24 @@ func marshalControlMessage(cm *ControlMessage) (oob []byte) {
|
|||||||
if pion {
|
if pion {
|
||||||
m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
|
m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
|
||||||
m.Level = ianaProtocolIPv6
|
m.Level = ianaProtocolIPv6
|
||||||
m.Type = syscall.IPV6_PKTINFO
|
m.Type = sysSockoptPacketInfo
|
||||||
m.SetLen(syscall.CmsgLen(syscall.SizeofInet6Pktinfo))
|
m.SetLen(syscall.CmsgLen(sysSizeofPacketInfo))
|
||||||
pi := (*syscall.Inet6Pktinfo)(unsafe.Pointer(&oob[off+syscall.CmsgLen(0)]))
|
pi := (*sysPacketInfo)(unsafe.Pointer(&oob[off+syscall.CmsgLen(0)]))
|
||||||
if ip := cm.Src.To16(); ip != nil && ip.To4() == nil {
|
if ip := cm.Src.To16(); ip != nil && ip.To4() == nil {
|
||||||
copy(pi.Addr[:], ip)
|
copy(pi.IP[:], ip)
|
||||||
}
|
}
|
||||||
if cm.IfIndex != 0 {
|
if cm.IfIndex != 0 {
|
||||||
pi.Ifindex = uint32(cm.IfIndex)
|
pi.IfIndex = uint32(cm.IfIndex)
|
||||||
}
|
}
|
||||||
off += syscall.CmsgSpace(syscall.SizeofInet6Pktinfo)
|
off += syscall.CmsgSpace(sysSizeofPacketInfo)
|
||||||
}
|
}
|
||||||
if len(cm.NextHop) == net.IPv6len {
|
if len(cm.NextHop) == net.IPv6len {
|
||||||
m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
|
m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
|
||||||
m.Level = ianaProtocolIPv6
|
m.Level = ianaProtocolIPv6
|
||||||
m.Type = syscall.IPV6_NEXTHOP
|
m.Type = sysSockoptNextHop
|
||||||
m.SetLen(syscall.CmsgLen(syscall.SizeofSockaddrInet6))
|
m.SetLen(syscall.CmsgLen(syscall.SizeofSockaddrInet6))
|
||||||
sa := (*syscall.RawSockaddrInet6)(unsafe.Pointer(&oob[off+syscall.CmsgLen(0)]))
|
sa := (*syscall.RawSockaddrInet6)(unsafe.Pointer(&oob[off+syscall.CmsgLen(0)]))
|
||||||
sa.Len = syscall.SizeofSockaddrInet6
|
setSockaddr(sa, cm.NextHop, cm.IfIndex)
|
||||||
sa.Family = syscall.AF_INET6
|
|
||||||
copy(sa.Addr[:], cm.NextHop)
|
|
||||||
sa.Scope_id = uint32(cm.IfIndex)
|
|
||||||
off += syscall.CmsgSpace(syscall.SizeofSockaddrInet6)
|
off += syscall.CmsgSpace(syscall.SizeofSockaddrInet6)
|
||||||
}
|
}
|
||||||
}
|
}
|
42
Godeps/_workspace/src/code.google.com/p/go.net/ipv6/control_test.go
generated
vendored
42
Godeps/_workspace/src/code.google.com/p/go.net/ipv6/control_test.go
generated
vendored
@ -1,42 +0,0 @@
|
|||||||
// 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.
|
|
||||||
|
|
||||||
package ipv6
|
|
||||||
|
|
||||||
import (
|
|
||||||
"sync"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestControlFlags(t *testing.T) {
|
|
||||||
tf := FlagInterface | FlagPathMTU
|
|
||||||
opt := rawOpt{cflags: tf | FlagHopLimit}
|
|
||||||
|
|
||||||
// This loop runs methods of raw.Opt concurrently for testing
|
|
||||||
// concurrent access to the rawOpt. The first entry shold be
|
|
||||||
// opt.set and the last entry should be opt.clear.
|
|
||||||
tfns := []func(ControlFlags){opt.set, opt.clear, opt.clear}
|
|
||||||
ch := make(chan bool)
|
|
||||||
var wg sync.WaitGroup
|
|
||||||
for i, fn := range tfns {
|
|
||||||
wg.Add(1)
|
|
||||||
go func(i int, fn func(ControlFlags)) {
|
|
||||||
defer wg.Done()
|
|
||||||
switch i {
|
|
||||||
case 0:
|
|
||||||
close(ch)
|
|
||||||
case len(tfns) - 1:
|
|
||||||
<-ch
|
|
||||||
}
|
|
||||||
opt.Lock()
|
|
||||||
defer opt.Unlock()
|
|
||||||
fn(tf)
|
|
||||||
}(i, fn)
|
|
||||||
}
|
|
||||||
wg.Wait()
|
|
||||||
|
|
||||||
if opt.isset(tf) {
|
|
||||||
t.Fatalf("got %#x; expected %#x", opt.cflags, FlagHopLimit)
|
|
||||||
}
|
|
||||||
}
|
|
@ -2,53 +2,52 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build dragonfly plan9 solaris
|
||||||
|
|
||||||
package ipv6
|
package ipv6
|
||||||
|
|
||||||
import (
|
import "net"
|
||||||
"net"
|
|
||||||
"syscall"
|
|
||||||
)
|
|
||||||
|
|
||||||
// MulticastHopLimit returns the hop limit field value for outgoing
|
// MulticastHopLimit returns the hop limit field value for outgoing
|
||||||
// multicast packets.
|
// multicast packets.
|
||||||
func (c *dgramOpt) MulticastHopLimit() (int, error) {
|
func (c *dgramOpt) MulticastHopLimit() (int, error) {
|
||||||
// TODO(mikio): Implement this
|
// TODO(mikio): Implement this
|
||||||
return 0, syscall.EPLAN9
|
return 0, errOpNoSupport
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetMulticastHopLimit sets the hop limit field value for future
|
// SetMulticastHopLimit sets the hop limit field value for future
|
||||||
// outgoing multicast packets.
|
// outgoing multicast packets.
|
||||||
func (c *dgramOpt) SetMulticastHopLimit(hoplim int) error {
|
func (c *dgramOpt) SetMulticastHopLimit(hoplim int) error {
|
||||||
// TODO(mikio): Implement this
|
// TODO(mikio): Implement this
|
||||||
return syscall.EPLAN9
|
return errOpNoSupport
|
||||||
}
|
}
|
||||||
|
|
||||||
// MulticastInterface returns the default interface for multicast
|
// MulticastInterface returns the default interface for multicast
|
||||||
// packet transmissions.
|
// packet transmissions.
|
||||||
func (c *dgramOpt) MulticastInterface() (*net.Interface, error) {
|
func (c *dgramOpt) MulticastInterface() (*net.Interface, error) {
|
||||||
// TODO(mikio): Implement this
|
// TODO(mikio): Implement this
|
||||||
return nil, syscall.EPLAN9
|
return nil, errOpNoSupport
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetMulticastInterface sets the default interface for future
|
// SetMulticastInterface sets the default interface for future
|
||||||
// multicast packet transmissions.
|
// multicast packet transmissions.
|
||||||
func (c *dgramOpt) SetMulticastInterface(ifi *net.Interface) error {
|
func (c *dgramOpt) SetMulticastInterface(ifi *net.Interface) error {
|
||||||
// TODO(mikio): Implement this
|
// TODO(mikio): Implement this
|
||||||
return syscall.EPLAN9
|
return errOpNoSupport
|
||||||
}
|
}
|
||||||
|
|
||||||
// MulticastLoopback reports whether transmitted multicast packets
|
// MulticastLoopback reports whether transmitted multicast packets
|
||||||
// should be copied and send back to the originator.
|
// should be copied and send back to the originator.
|
||||||
func (c *dgramOpt) MulticastLoopback() (bool, error) {
|
func (c *dgramOpt) MulticastLoopback() (bool, error) {
|
||||||
// TODO(mikio): Implement this
|
// TODO(mikio): Implement this
|
||||||
return false, syscall.EPLAN9
|
return false, errOpNoSupport
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetMulticastLoopback sets whether transmitted multicast packets
|
// SetMulticastLoopback sets whether transmitted multicast packets
|
||||||
// should be copied and send back to the originator.
|
// should be copied and send back to the originator.
|
||||||
func (c *dgramOpt) SetMulticastLoopback(on bool) error {
|
func (c *dgramOpt) SetMulticastLoopback(on bool) error {
|
||||||
// TODO(mikio): Implement this
|
// TODO(mikio): Implement this
|
||||||
return syscall.EPLAN9
|
return errOpNoSupport
|
||||||
}
|
}
|
||||||
|
|
||||||
// JoinGroup joins the group address group on the interface ifi.
|
// JoinGroup joins the group address group on the interface ifi.
|
||||||
@ -57,13 +56,13 @@ func (c *dgramOpt) SetMulticastLoopback(on bool) error {
|
|||||||
// platforms and sometimes it might require routing configuration.
|
// platforms and sometimes it might require routing configuration.
|
||||||
func (c *dgramOpt) JoinGroup(ifi *net.Interface, group net.Addr) error {
|
func (c *dgramOpt) JoinGroup(ifi *net.Interface, group net.Addr) error {
|
||||||
// TODO(mikio): Implement this
|
// TODO(mikio): Implement this
|
||||||
return syscall.EPLAN9
|
return errOpNoSupport
|
||||||
}
|
}
|
||||||
|
|
||||||
// LeaveGroup leaves the group address group on the interface ifi.
|
// LeaveGroup leaves the group address group on the interface ifi.
|
||||||
func (c *dgramOpt) LeaveGroup(ifi *net.Interface, group net.Addr) error {
|
func (c *dgramOpt) LeaveGroup(ifi *net.Interface, group net.Addr) error {
|
||||||
// TODO(mikio): Implement this
|
// TODO(mikio): Implement this
|
||||||
return syscall.EPLAN9
|
return errOpNoSupport
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checksum reports whether the kernel will compute, store or verify a
|
// Checksum reports whether the kernel will compute, store or verify a
|
||||||
@ -72,7 +71,7 @@ func (c *dgramOpt) LeaveGroup(ifi *net.Interface, group net.Addr) error {
|
|||||||
// field is located.
|
// field is located.
|
||||||
func (c *dgramOpt) Checksum() (on bool, offset int, err error) {
|
func (c *dgramOpt) Checksum() (on bool, offset int, err error) {
|
||||||
// TODO(mikio): Implement this
|
// TODO(mikio): Implement this
|
||||||
return false, 0, syscall.EPLAN9
|
return false, 0, errOpNoSupport
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetChecksum enables the kernel checksum processing. If on is ture,
|
// SetChecksum enables the kernel checksum processing. If on is ture,
|
||||||
@ -80,17 +79,17 @@ func (c *dgramOpt) Checksum() (on bool, offset int, err error) {
|
|||||||
// checksum field is located.
|
// checksum field is located.
|
||||||
func (c *dgramOpt) SetChecksum(on bool, offset int) error {
|
func (c *dgramOpt) SetChecksum(on bool, offset int) error {
|
||||||
// TODO(mikio): Implement this
|
// TODO(mikio): Implement this
|
||||||
return syscall.EPLAN9
|
return errOpNoSupport
|
||||||
}
|
}
|
||||||
|
|
||||||
// ICMPFilter returns an ICMP filter.
|
// ICMPFilter returns an ICMP filter.
|
||||||
func (c *dgramOpt) ICMPFilter() (*ICMPFilter, error) {
|
func (c *dgramOpt) ICMPFilter() (*ICMPFilter, error) {
|
||||||
// TODO(mikio): Implement this
|
// TODO(mikio): Implement this
|
||||||
return nil, syscall.EPLAN9
|
return nil, errOpNoSupport
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetICMPFilter deploys the ICMP filter.
|
// SetICMPFilter deploys the ICMP filter.
|
||||||
func (c *dgramOpt) SetICMPFilter(f *ICMPFilter) error {
|
func (c *dgramOpt) SetICMPFilter(f *ICMPFilter) error {
|
||||||
// TODO(mikio): Implement this
|
// TODO(mikio): Implement this
|
||||||
return syscall.EPLAN9
|
return errOpNoSupport
|
||||||
}
|
}
|
@ -2,33 +2,33 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package ipv6
|
// +build dragonfly plan9 solaris
|
||||||
|
|
||||||
import "syscall"
|
package ipv6
|
||||||
|
|
||||||
// TrafficClass returns the traffic class field value for outgoing
|
// TrafficClass returns the traffic class field value for outgoing
|
||||||
// packets.
|
// packets.
|
||||||
func (c *genericOpt) TrafficClass() (int, error) {
|
func (c *genericOpt) TrafficClass() (int, error) {
|
||||||
// TODO(mikio): Implement this
|
// TODO(mikio): Implement this
|
||||||
return 0, syscall.EPLAN9
|
return 0, errOpNoSupport
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetTrafficClass sets the traffic class field value for future
|
// SetTrafficClass sets the traffic class field value for future
|
||||||
// outgoing packets.
|
// outgoing packets.
|
||||||
func (c *genericOpt) SetTrafficClass(tclass int) error {
|
func (c *genericOpt) SetTrafficClass(tclass int) error {
|
||||||
// TODO(mikio): Implement this
|
// TODO(mikio): Implement this
|
||||||
return syscall.EPLAN9
|
return errOpNoSupport
|
||||||
}
|
}
|
||||||
|
|
||||||
// HopLimit returns the hop limit field value for outgoing packets.
|
// HopLimit returns the hop limit field value for outgoing packets.
|
||||||
func (c *genericOpt) HopLimit() (int, error) {
|
func (c *genericOpt) HopLimit() (int, error) {
|
||||||
// TODO(mikio): Implement this
|
// TODO(mikio): Implement this
|
||||||
return 0, syscall.EPLAN9
|
return 0, errOpNoSupport
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetHopLimit sets the hop limit field value for future outgoing
|
// SetHopLimit sets the hop limit field value for future outgoing
|
||||||
// packets.
|
// packets.
|
||||||
func (c *genericOpt) SetHopLimit(hoplim int) error {
|
func (c *genericOpt) SetHopLimit(hoplim int) error {
|
||||||
// TODO(mikio): Implement this
|
// TODO(mikio): Implement this
|
||||||
return syscall.EPLAN9
|
return errOpNoSupport
|
||||||
}
|
}
|
7
Godeps/_workspace/src/code.google.com/p/go.net/ipv6/helper.go
generated
vendored
7
Godeps/_workspace/src/code.google.com/p/go.net/ipv6/helper.go
generated
vendored
@ -4,7 +4,12 @@
|
|||||||
|
|
||||||
package ipv6
|
package ipv6
|
||||||
|
|
||||||
import "net"
|
import (
|
||||||
|
"errors"
|
||||||
|
"net"
|
||||||
|
)
|
||||||
|
|
||||||
|
var errOpNoSupport = errors.New("operation not supported")
|
||||||
|
|
||||||
func boolint(b bool) int {
|
func boolint(b bool) int {
|
||||||
if b {
|
if b {
|
||||||
|
@ -2,21 +2,21 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package ipv6
|
// +build dragonfly plan9 solaris
|
||||||
|
|
||||||
import "syscall"
|
package ipv6
|
||||||
|
|
||||||
func (c *genericOpt) sysfd() (int, error) {
|
func (c *genericOpt) sysfd() (int, error) {
|
||||||
// TODO(mikio): Implement this
|
// TODO(mikio): Implement this
|
||||||
return 0, syscall.EPLAN9
|
return 0, errOpNoSupport
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *dgramOpt) sysfd() (int, error) {
|
func (c *dgramOpt) sysfd() (int, error) {
|
||||||
// TODO(mikio): Implement this
|
// TODO(mikio): Implement this
|
||||||
return 0, syscall.EPLAN9
|
return 0, errOpNoSupport
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *payloadHandler) sysfd() (int, error) {
|
func (c *payloadHandler) sysfd() (int, error) {
|
||||||
// TODO(mikio): Implement this
|
// TODO(mikio): Implement this
|
||||||
return 0, syscall.EPLAN9
|
return 0, errOpNoSupport
|
||||||
}
|
}
|
11
Godeps/_workspace/src/code.google.com/p/go.net/ipv6/icmp.go
generated
vendored
11
Godeps/_workspace/src/code.google.com/p/go.net/ipv6/icmp.go
generated
vendored
@ -21,26 +21,27 @@ func (typ ICMPType) String() string {
|
|||||||
// packets.
|
// packets.
|
||||||
type ICMPFilter struct {
|
type ICMPFilter struct {
|
||||||
mu sync.RWMutex
|
mu sync.RWMutex
|
||||||
rawICMPFilter
|
sysICMPFilter
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set sets the ICMP type and filter action to the filter.
|
// Set sets the ICMP type and filter action to the filter.
|
||||||
func (f *ICMPFilter) Set(typ ICMPType, block bool) {
|
func (f *ICMPFilter) Set(typ ICMPType, block bool) {
|
||||||
f.mu.Lock()
|
f.mu.Lock()
|
||||||
defer f.mu.Unlock()
|
|
||||||
f.set(typ, block)
|
f.set(typ, block)
|
||||||
|
f.mu.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetAll sets the filter action to the filter.
|
// SetAll sets the filter action to the filter.
|
||||||
func (f *ICMPFilter) SetAll(block bool) {
|
func (f *ICMPFilter) SetAll(block bool) {
|
||||||
f.mu.Lock()
|
f.mu.Lock()
|
||||||
defer f.mu.Unlock()
|
|
||||||
f.setAll(block)
|
f.setAll(block)
|
||||||
|
f.mu.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
// WillBlock reports whether the ICMP type will be blocked.
|
// WillBlock reports whether the ICMP type will be blocked.
|
||||||
func (f *ICMPFilter) WillBlock(typ ICMPType) bool {
|
func (f *ICMPFilter) WillBlock(typ ICMPType) bool {
|
||||||
f.mu.RLock()
|
f.mu.RLock()
|
||||||
defer f.mu.RUnlock()
|
ok := f.willBlock(typ)
|
||||||
return f.willBlock(typ)
|
f.mu.RUnlock()
|
||||||
|
return ok
|
||||||
}
|
}
|
||||||
|
12
Godeps/_workspace/src/code.google.com/p/go.net/ipv6/icmp_bsd.go
generated
vendored
12
Godeps/_workspace/src/code.google.com/p/go.net/ipv6/icmp_bsd.go
generated
vendored
@ -6,13 +6,11 @@
|
|||||||
|
|
||||||
package ipv6
|
package ipv6
|
||||||
|
|
||||||
import "syscall"
|
type sysICMPFilter struct {
|
||||||
|
Filt [8]uint32
|
||||||
type rawICMPFilter struct {
|
|
||||||
syscall.ICMPv6Filter
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *rawICMPFilter) set(typ ICMPType, block bool) {
|
func (f *sysICMPFilter) set(typ ICMPType, block bool) {
|
||||||
if block {
|
if block {
|
||||||
f.Filt[typ>>5] &^= 1 << (uint32(typ) & 31)
|
f.Filt[typ>>5] &^= 1 << (uint32(typ) & 31)
|
||||||
} else {
|
} else {
|
||||||
@ -20,7 +18,7 @@ func (f *rawICMPFilter) set(typ ICMPType, block bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *rawICMPFilter) setAll(block bool) {
|
func (f *sysICMPFilter) setAll(block bool) {
|
||||||
for i := range f.Filt {
|
for i := range f.Filt {
|
||||||
if block {
|
if block {
|
||||||
f.Filt[i] = 0
|
f.Filt[i] = 0
|
||||||
@ -30,6 +28,6 @@ func (f *rawICMPFilter) setAll(block bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *rawICMPFilter) willBlock(typ ICMPType) bool {
|
func (f *sysICMPFilter) willBlock(typ ICMPType) bool {
|
||||||
return f.Filt[typ>>5]&(1<<(uint32(typ)&31)) == 0
|
return f.Filt[typ>>5]&(1<<(uint32(typ)&31)) == 0
|
||||||
}
|
}
|
||||||
|
12
Godeps/_workspace/src/code.google.com/p/go.net/ipv6/icmp_linux.go
generated
vendored
12
Godeps/_workspace/src/code.google.com/p/go.net/ipv6/icmp_linux.go
generated
vendored
@ -4,13 +4,11 @@
|
|||||||
|
|
||||||
package ipv6
|
package ipv6
|
||||||
|
|
||||||
import "syscall"
|
type sysICMPFilter struct {
|
||||||
|
Data [8]uint32
|
||||||
type rawICMPFilter struct {
|
|
||||||
syscall.ICMPv6Filter
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *rawICMPFilter) set(typ ICMPType, block bool) {
|
func (f *sysICMPFilter) set(typ ICMPType, block bool) {
|
||||||
if block {
|
if block {
|
||||||
f.Data[typ>>5] |= 1 << (uint32(typ) & 31)
|
f.Data[typ>>5] |= 1 << (uint32(typ) & 31)
|
||||||
} else {
|
} else {
|
||||||
@ -18,7 +16,7 @@ func (f *rawICMPFilter) set(typ ICMPType, block bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *rawICMPFilter) setAll(block bool) {
|
func (f *sysICMPFilter) setAll(block bool) {
|
||||||
for i := range f.Data {
|
for i := range f.Data {
|
||||||
if block {
|
if block {
|
||||||
f.Data[i] = 1<<32 - 1
|
f.Data[i] = 1<<32 - 1
|
||||||
@ -28,6 +26,6 @@ func (f *rawICMPFilter) setAll(block bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *rawICMPFilter) willBlock(typ ICMPType) bool {
|
func (f *sysICMPFilter) willBlock(typ ICMPType) bool {
|
||||||
return f.Data[typ>>5]&(1<<(uint32(typ)&31)) != 0
|
return f.Data[typ>>5]&(1<<(uint32(typ)&31)) != 0
|
||||||
}
|
}
|
||||||
|
@ -2,21 +2,23 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build dragonfly plan9 solaris
|
||||||
|
|
||||||
package ipv6
|
package ipv6
|
||||||
|
|
||||||
type rawICMPFilter struct {
|
type sysICMPFilter struct {
|
||||||
// TODO(mikio): Implement this
|
// TODO(mikio): Implement this
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *rawICMPFilter) set(typ ICMPType, block bool) {
|
func (f *sysICMPFilter) set(typ ICMPType, block bool) {
|
||||||
// TODO(mikio): Implement this
|
// TODO(mikio): Implement this
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *rawICMPFilter) setAll(block bool) {
|
func (f *sysICMPFilter) setAll(block bool) {
|
||||||
// TODO(mikio): Implement this
|
// TODO(mikio): Implement this
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *rawICMPFilter) willBlock(typ ICMPType) bool {
|
func (f *sysICMPFilter) willBlock(typ ICMPType) bool {
|
||||||
// TODO(mikio): Implement this
|
// TODO(mikio): Implement this
|
||||||
return false
|
return false
|
||||||
}
|
}
|
22
Godeps/_workspace/src/code.google.com/p/go.net/ipv6/icmp_test.go
generated
vendored
22
Godeps/_workspace/src/code.google.com/p/go.net/ipv6/icmp_test.go
generated
vendored
@ -14,9 +14,27 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var icmpStringTests = []struct {
|
||||||
|
in ipv6.ICMPType
|
||||||
|
out string
|
||||||
|
}{
|
||||||
|
{ipv6.ICMPTypeDestinationUnreachable, "destination unreachable"},
|
||||||
|
|
||||||
|
{256, "<nil>"},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestICMPString(t *testing.T) {
|
||||||
|
for _, tt := range icmpStringTests {
|
||||||
|
s := tt.in.String()
|
||||||
|
if s != tt.out {
|
||||||
|
t.Errorf("got %s; expected %s", s, tt.out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestICMPFilter(t *testing.T) {
|
func TestICMPFilter(t *testing.T) {
|
||||||
switch runtime.GOOS {
|
switch runtime.GOOS {
|
||||||
case "plan9", "windows":
|
case "dragonfly", "plan9", "solaris", "windows":
|
||||||
t.Skipf("not supported on %q", runtime.GOOS)
|
t.Skipf("not supported on %q", runtime.GOOS)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,7 +67,7 @@ func TestICMPFilter(t *testing.T) {
|
|||||||
|
|
||||||
func TestSetICMPFilter(t *testing.T) {
|
func TestSetICMPFilter(t *testing.T) {
|
||||||
switch runtime.GOOS {
|
switch runtime.GOOS {
|
||||||
case "plan9", "windows":
|
case "dragonfly", "plan9", "solaris", "windows":
|
||||||
t.Skipf("not supported on %q", runtime.GOOS)
|
t.Skipf("not supported on %q", runtime.GOOS)
|
||||||
}
|
}
|
||||||
if !supportsIPv6 {
|
if !supportsIPv6 {
|
||||||
|
8
Godeps/_workspace/src/code.google.com/p/go.net/ipv6/icmp_windows.go
generated
vendored
8
Godeps/_workspace/src/code.google.com/p/go.net/ipv6/icmp_windows.go
generated
vendored
@ -4,19 +4,19 @@
|
|||||||
|
|
||||||
package ipv6
|
package ipv6
|
||||||
|
|
||||||
type rawICMPFilter struct {
|
type sysICMPFilter struct {
|
||||||
// TODO(mikio): Implement this
|
// TODO(mikio): Implement this
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *rawICMPFilter) set(typ ICMPType, block bool) {
|
func (f *sysICMPFilter) set(typ ICMPType, block bool) {
|
||||||
// TODO(mikio): Implement this
|
// TODO(mikio): Implement this
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *rawICMPFilter) setAll(block bool) {
|
func (f *sysICMPFilter) setAll(block bool) {
|
||||||
// TODO(mikio): Implement this
|
// TODO(mikio): Implement this
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *rawICMPFilter) willBlock(typ ICMPType) bool {
|
func (f *sysICMPFilter) willBlock(typ ICMPType) bool {
|
||||||
// TODO(mikio): Implement this
|
// TODO(mikio): Implement this
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
30
Godeps/_workspace/src/code.google.com/p/go.net/ipv6/mockicmp_test.go
generated
vendored
30
Godeps/_workspace/src/code.google.com/p/go.net/ipv6/mockicmp_test.go
generated
vendored
@ -7,8 +7,22 @@ package ipv6_test
|
|||||||
import (
|
import (
|
||||||
"code.google.com/p/go.net/ipv6"
|
"code.google.com/p/go.net/ipv6"
|
||||||
"errors"
|
"errors"
|
||||||
|
"net"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
ipv6PseudoHeaderLen = 2*net.IPv6len + 8
|
||||||
|
ianaProtocolIPv6ICMP = 58
|
||||||
|
)
|
||||||
|
|
||||||
|
func ipv6PseudoHeader(src, dst net.IP, nextHeader int) []byte {
|
||||||
|
b := make([]byte, ipv6PseudoHeaderLen)
|
||||||
|
copy(b[:net.IPv6len], src)
|
||||||
|
copy(b[net.IPv6len:], dst)
|
||||||
|
b[len(b)-1] = byte(nextHeader)
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
// icmpMessage represents an ICMP message.
|
// icmpMessage represents an ICMP message.
|
||||||
type icmpMessage struct {
|
type icmpMessage struct {
|
||||||
Type ipv6.ICMPType // type
|
Type ipv6.ICMPType // type
|
||||||
@ -25,8 +39,11 @@ type icmpMessageBody interface {
|
|||||||
|
|
||||||
// Marshal returns the binary enconding of the ICMP echo request or
|
// Marshal returns the binary enconding of the ICMP echo request or
|
||||||
// reply message m.
|
// reply message m.
|
||||||
func (m *icmpMessage) Marshal() ([]byte, error) {
|
func (m *icmpMessage) Marshal(psh []byte) ([]byte, error) {
|
||||||
b := []byte{byte(m.Type), byte(m.Code), 0, 0}
|
b := []byte{byte(m.Type), byte(m.Code), 0, 0}
|
||||||
|
if psh != nil {
|
||||||
|
b = append(psh, b...)
|
||||||
|
}
|
||||||
if m.Body != nil && m.Body.Len() != 0 {
|
if m.Body != nil && m.Body.Len() != 0 {
|
||||||
mb, err := m.Body.Marshal()
|
mb, err := m.Body.Marshal()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -34,10 +51,11 @@ func (m *icmpMessage) Marshal() ([]byte, error) {
|
|||||||
}
|
}
|
||||||
b = append(b, mb...)
|
b = append(b, mb...)
|
||||||
}
|
}
|
||||||
switch m.Type {
|
if psh == nil {
|
||||||
case ipv6.ICMPTypeEchoRequest, ipv6.ICMPTypeEchoReply:
|
|
||||||
return b, nil
|
return b, nil
|
||||||
}
|
}
|
||||||
|
off, l := 2*net.IPv6len, len(b)-len(psh)
|
||||||
|
b[off], b[off+1], b[off+2], b[off+3] = byte(l>>24), byte(l>>16), byte(l>>8), byte(l)
|
||||||
csumcv := len(b) - 1 // checksum coverage
|
csumcv := len(b) - 1 // checksum coverage
|
||||||
s := uint32(0)
|
s := uint32(0)
|
||||||
for i := 0; i < csumcv; i += 2 {
|
for i := 0; i < csumcv; i += 2 {
|
||||||
@ -50,9 +68,9 @@ func (m *icmpMessage) Marshal() ([]byte, error) {
|
|||||||
s = s + s>>16
|
s = s + s>>16
|
||||||
// Place checksum back in header; using ^= avoids the
|
// Place checksum back in header; using ^= avoids the
|
||||||
// assumption the checksum bytes are zero.
|
// assumption the checksum bytes are zero.
|
||||||
b[2] ^= byte(^s)
|
b[len(psh)+2] ^= byte(^s)
|
||||||
b[3] ^= byte(^s >> 8)
|
b[len(psh)+3] ^= byte(^s >> 8)
|
||||||
return b, nil
|
return b[len(psh):], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// parseICMPMessage parses b as an ICMP message.
|
// parseICMPMessage parses b as an ICMP message.
|
||||||
|
22
Godeps/_workspace/src/code.google.com/p/go.net/ipv6/mocktransponder_test.go
generated
vendored
22
Godeps/_workspace/src/code.google.com/p/go.net/ipv6/mocktransponder_test.go
generated
vendored
@ -86,25 +86,3 @@ func acceptor(t *testing.T, ln net.Listener, done chan<- bool) {
|
|||||||
}
|
}
|
||||||
c.Close()
|
c.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
func transponder(t *testing.T, ln net.Listener, done chan<- bool) {
|
|
||||||
defer func() { done <- true }()
|
|
||||||
|
|
||||||
c, err := ln.Accept()
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("net.Listener.Accept failed: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer c.Close()
|
|
||||||
|
|
||||||
b := make([]byte, 128)
|
|
||||||
n, err := c.Read(b)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("net.Conn.Read failed: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if _, err := c.Write(b[:n]); err != nil {
|
|
||||||
t.Errorf("net.Conn.Write failed: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
76
Godeps/_workspace/src/code.google.com/p/go.net/ipv6/multicast_test.go
generated
vendored
76
Godeps/_workspace/src/code.google.com/p/go.net/ipv6/multicast_test.go
generated
vendored
@ -5,11 +5,13 @@
|
|||||||
package ipv6_test
|
package ipv6_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"code.google.com/p/go.net/ipv6"
|
"code.google.com/p/go.net/ipv6"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestPacketConnReadWriteMulticastUDP(t *testing.T) {
|
func TestPacketConnReadWriteMulticastUDP(t *testing.T) {
|
||||||
@ -17,7 +19,7 @@ func TestPacketConnReadWriteMulticastUDP(t *testing.T) {
|
|||||||
case "freebsd": // due to a bug on loopback marking
|
case "freebsd": // due to a bug on loopback marking
|
||||||
// See http://www.freebsd.org/cgi/query-pr.cgi?pr=180065.
|
// See http://www.freebsd.org/cgi/query-pr.cgi?pr=180065.
|
||||||
t.Skipf("not supported on %q", runtime.GOOS)
|
t.Skipf("not supported on %q", runtime.GOOS)
|
||||||
case "plan9", "windows":
|
case "dragonfly", "plan9", "solaris", "windows":
|
||||||
t.Skipf("not supported on %q", runtime.GOOS)
|
t.Skipf("not supported on %q", runtime.GOOS)
|
||||||
}
|
}
|
||||||
if !supportsIPv6 {
|
if !supportsIPv6 {
|
||||||
@ -44,33 +46,49 @@ func TestPacketConnReadWriteMulticastUDP(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
p := ipv6.NewPacketConn(c)
|
p := ipv6.NewPacketConn(c)
|
||||||
|
defer p.Close()
|
||||||
if err := p.JoinGroup(ifi, dst); err != nil {
|
if err := p.JoinGroup(ifi, dst); err != nil {
|
||||||
t.Fatalf("ipv6.PacketConn.JoinGroup on %v failed: %v", ifi, err)
|
t.Fatalf("ipv6.PacketConn.JoinGroup on %v failed: %v", ifi, err)
|
||||||
}
|
}
|
||||||
if err := p.SetMulticastInterface(ifi); err != nil {
|
if err := p.SetMulticastInterface(ifi); err != nil {
|
||||||
t.Fatalf("ipv6.PacketConn.SetMulticastInterface failed: %v", err)
|
t.Fatalf("ipv6.PacketConn.SetMulticastInterface failed: %v", err)
|
||||||
}
|
}
|
||||||
|
if _, err := p.MulticastInterface(); err != nil {
|
||||||
|
t.Fatalf("ipv6.PacketConn.MulticastInterface failed: %v", err)
|
||||||
|
}
|
||||||
if err := p.SetMulticastLoopback(true); err != nil {
|
if err := p.SetMulticastLoopback(true); err != nil {
|
||||||
t.Fatalf("ipv6.PacketConn.SetMulticastLoopback failed: %v", err)
|
t.Fatalf("ipv6.PacketConn.SetMulticastLoopback failed: %v", err)
|
||||||
}
|
}
|
||||||
|
if _, err := p.MulticastLoopback(); err != nil {
|
||||||
|
t.Fatalf("ipv6.PacketConn.MulticastLoopback failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
cm := ipv6.ControlMessage{
|
cm := ipv6.ControlMessage{
|
||||||
TrafficClass: DiffServAF11 | CongestionExperienced,
|
TrafficClass: DiffServAF11 | CongestionExperienced,
|
||||||
|
Src: net.IPv6loopback,
|
||||||
IfIndex: ifi.Index,
|
IfIndex: ifi.Index,
|
||||||
}
|
}
|
||||||
cf := ipv6.FlagTrafficClass | ipv6.FlagHopLimit | ipv6.FlagInterface | ipv6.FlagPathMTU
|
cf := ipv6.FlagTrafficClass | ipv6.FlagHopLimit | ipv6.FlagSrc | ipv6.FlagDst | ipv6.FlagInterface | ipv6.FlagPathMTU
|
||||||
|
wb := []byte("HELLO-R-U-THERE")
|
||||||
|
|
||||||
for i, toggle := range []bool{true, false, true} {
|
for i, toggle := range []bool{true, false, true} {
|
||||||
if err := p.SetControlMessage(cf, toggle); err != nil {
|
if err := p.SetControlMessage(cf, toggle); err != nil {
|
||||||
t.Fatalf("ipv6.PacketConn.SetControlMessage failed: %v", err)
|
t.Fatalf("ipv6.PacketConn.SetControlMessage failed: %v", err)
|
||||||
}
|
}
|
||||||
cm.HopLimit = i + 1
|
if err := p.SetDeadline(time.Now().Add(200 * time.Millisecond)); err != nil {
|
||||||
if _, err := p.WriteTo([]byte("HELLO-R-U-THERE"), &cm, dst); err != nil {
|
t.Fatalf("ipv6.PacketConn.SetDeadline failed: %v", err)
|
||||||
t.Fatalf("ipv6.PacketConn.WriteTo failed: %v", err)
|
|
||||||
}
|
}
|
||||||
b := make([]byte, 128)
|
cm.HopLimit = i + 1
|
||||||
if _, cm, _, err := p.ReadFrom(b); err != nil {
|
if n, err := p.WriteTo(wb, &cm, dst); err != nil {
|
||||||
|
t.Fatalf("ipv6.PacketConn.WriteTo failed: %v", err)
|
||||||
|
} else if n != len(wb) {
|
||||||
|
t.Fatalf("ipv6.PacketConn.WriteTo failed: short write: %v", n)
|
||||||
|
}
|
||||||
|
rb := make([]byte, 128)
|
||||||
|
if n, cm, _, err := p.ReadFrom(rb); err != nil {
|
||||||
t.Fatalf("ipv6.PacketConn.ReadFrom failed: %v", err)
|
t.Fatalf("ipv6.PacketConn.ReadFrom failed: %v", err)
|
||||||
|
} else if !bytes.Equal(rb[:n], wb) {
|
||||||
|
t.Fatalf("got %v; expected %v", rb[:n], wb)
|
||||||
} else {
|
} else {
|
||||||
t.Logf("rcvd cmsg: %v", cm)
|
t.Logf("rcvd cmsg: %v", cm)
|
||||||
}
|
}
|
||||||
@ -79,7 +97,7 @@ func TestPacketConnReadWriteMulticastUDP(t *testing.T) {
|
|||||||
|
|
||||||
func TestPacketConnReadWriteMulticastICMP(t *testing.T) {
|
func TestPacketConnReadWriteMulticastICMP(t *testing.T) {
|
||||||
switch runtime.GOOS {
|
switch runtime.GOOS {
|
||||||
case "plan9", "windows":
|
case "dragonfly", "plan9", "solaris", "windows":
|
||||||
t.Skipf("not supported on %q", runtime.GOOS)
|
t.Skipf("not supported on %q", runtime.GOOS)
|
||||||
}
|
}
|
||||||
if !supportsIPv6 {
|
if !supportsIPv6 {
|
||||||
@ -104,22 +122,31 @@ func TestPacketConnReadWriteMulticastICMP(t *testing.T) {
|
|||||||
t.Fatalf("net.ResolveIPAddr failed: %v", err)
|
t.Fatalf("net.ResolveIPAddr failed: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pshicmp := ipv6PseudoHeader(c.LocalAddr().(*net.IPAddr).IP, dst.IP, ianaProtocolIPv6ICMP)
|
||||||
p := ipv6.NewPacketConn(c)
|
p := ipv6.NewPacketConn(c)
|
||||||
|
defer p.Close()
|
||||||
if err := p.JoinGroup(ifi, dst); err != nil {
|
if err := p.JoinGroup(ifi, dst); err != nil {
|
||||||
t.Fatalf("ipv6.PacketConn.JoinGroup on %v failed: %v", ifi, err)
|
t.Fatalf("ipv6.PacketConn.JoinGroup on %v failed: %v", ifi, err)
|
||||||
}
|
}
|
||||||
if err := p.SetMulticastInterface(ifi); err != nil {
|
if err := p.SetMulticastInterface(ifi); err != nil {
|
||||||
t.Fatalf("ipv6.PacketConn.SetMulticastInterface failed: %v", err)
|
t.Fatalf("ipv6.PacketConn.SetMulticastInterface failed: %v", err)
|
||||||
}
|
}
|
||||||
|
if _, err := p.MulticastInterface(); err != nil {
|
||||||
|
t.Fatalf("ipv6.PacketConn.MulticastInterface failed: %v", err)
|
||||||
|
}
|
||||||
if err := p.SetMulticastLoopback(true); err != nil {
|
if err := p.SetMulticastLoopback(true); err != nil {
|
||||||
t.Fatalf("ipv6.PacketConn.SetMulticastLoopback failed: %v", err)
|
t.Fatalf("ipv6.PacketConn.SetMulticastLoopback failed: %v", err)
|
||||||
}
|
}
|
||||||
|
if _, err := p.MulticastLoopback(); err != nil {
|
||||||
|
t.Fatalf("ipv6.PacketConn.MulticastLoopback failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
cm := ipv6.ControlMessage{
|
cm := ipv6.ControlMessage{
|
||||||
TrafficClass: DiffServAF11 | CongestionExperienced,
|
TrafficClass: DiffServAF11 | CongestionExperienced,
|
||||||
|
Src: net.IPv6loopback,
|
||||||
IfIndex: ifi.Index,
|
IfIndex: ifi.Index,
|
||||||
}
|
}
|
||||||
cf := ipv6.FlagTrafficClass | ipv6.FlagHopLimit | ipv6.FlagInterface | ipv6.FlagPathMTU
|
cf := ipv6.FlagTrafficClass | ipv6.FlagHopLimit | ipv6.FlagSrc | ipv6.FlagDst | ipv6.FlagInterface | ipv6.FlagPathMTU
|
||||||
|
|
||||||
var f ipv6.ICMPFilter
|
var f ipv6.ICMPFilter
|
||||||
f.SetAll(true)
|
f.SetAll(true)
|
||||||
@ -128,30 +155,47 @@ func TestPacketConnReadWriteMulticastICMP(t *testing.T) {
|
|||||||
t.Fatalf("ipv6.PacketConn.SetICMPFilter failed: %v", err)
|
t.Fatalf("ipv6.PacketConn.SetICMPFilter failed: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var psh []byte
|
||||||
for i, toggle := range []bool{true, false, true} {
|
for i, toggle := range []bool{true, false, true} {
|
||||||
|
if toggle {
|
||||||
|
psh = nil
|
||||||
|
if err := p.SetChecksum(true, 2); err != nil {
|
||||||
|
t.Fatalf("ipv6.PacketConn.SetChecksum failed: %v", err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
psh = pshicmp
|
||||||
|
// Some platforms never allow to disable the
|
||||||
|
// kernel checksum processing.
|
||||||
|
p.SetChecksum(false, -1)
|
||||||
|
}
|
||||||
wb, err := (&icmpMessage{
|
wb, err := (&icmpMessage{
|
||||||
Type: ipv6.ICMPTypeEchoRequest, Code: 0,
|
Type: ipv6.ICMPTypeEchoRequest, Code: 0,
|
||||||
Body: &icmpEcho{
|
Body: &icmpEcho{
|
||||||
ID: os.Getpid() & 0xffff, Seq: i + 1,
|
ID: os.Getpid() & 0xffff, Seq: i + 1,
|
||||||
Data: []byte("HELLO-R-U-THERE"),
|
Data: []byte("HELLO-R-U-THERE"),
|
||||||
},
|
},
|
||||||
}).Marshal()
|
}).Marshal(psh)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("icmpMessage.Marshal failed: %v", err)
|
t.Fatalf("icmpMessage.Marshal failed: %v", err)
|
||||||
}
|
}
|
||||||
if err := p.SetControlMessage(cf, toggle); err != nil {
|
if err := p.SetControlMessage(cf, toggle); err != nil {
|
||||||
t.Fatalf("ipv6.PacketConn.SetControlMessage failed: %v", err)
|
t.Fatalf("ipv6.PacketConn.SetControlMessage failed: %v", err)
|
||||||
}
|
}
|
||||||
cm.HopLimit = i + 1
|
if err := p.SetDeadline(time.Now().Add(200 * time.Millisecond)); err != nil {
|
||||||
if _, err := p.WriteTo(wb, &cm, dst); err != nil {
|
t.Fatalf("ipv6.PacketConn.SetDeadline failed: %v", err)
|
||||||
t.Fatalf("ipv6.PacketConn.WriteTo failed: %v", err)
|
|
||||||
}
|
}
|
||||||
b := make([]byte, 128)
|
cm.HopLimit = i + 1
|
||||||
if n, cm, _, err := p.ReadFrom(b); err != nil {
|
if n, err := p.WriteTo(wb, &cm, dst); err != nil {
|
||||||
|
t.Fatalf("ipv6.PacketConn.WriteTo failed: %v", err)
|
||||||
|
} else if n != len(wb) {
|
||||||
|
t.Fatalf("ipv6.PacketConn.WriteTo failed: short write: %v", n)
|
||||||
|
}
|
||||||
|
rb := make([]byte, 128)
|
||||||
|
if n, cm, _, err := p.ReadFrom(rb); err != nil {
|
||||||
t.Fatalf("ipv6.PacketConn.ReadFrom failed: %v", err)
|
t.Fatalf("ipv6.PacketConn.ReadFrom failed: %v", err)
|
||||||
} else {
|
} else {
|
||||||
t.Logf("rcvd cmsg: %v", cm)
|
t.Logf("rcvd cmsg: %v", cm)
|
||||||
if m, err := parseICMPMessage(b[:n]); err != nil {
|
if m, err := parseICMPMessage(rb[:n]); err != nil {
|
||||||
t.Fatalf("parseICMPMessage failed: %v", err)
|
t.Fatalf("parseICMPMessage failed: %v", err)
|
||||||
} else if m.Type != ipv6.ICMPTypeEchoReply || m.Code != 0 {
|
} else if m.Type != ipv6.ICMPTypeEchoReply || m.Code != 0 {
|
||||||
t.Fatalf("got type=%v, code=%v; expected type=%v, code=%v", m.Type, m.Code, ipv6.ICMPTypeEchoReply, 0)
|
t.Fatalf("got type=%v, code=%v; expected type=%v, code=%v", m.Type, m.Code, ipv6.ICMPTypeEchoReply, 0)
|
||||||
|
70
Godeps/_workspace/src/code.google.com/p/go.net/ipv6/multicastlistener_test.go
generated
vendored
70
Godeps/_workspace/src/code.google.com/p/go.net/ipv6/multicastlistener_test.go
generated
vendored
@ -21,7 +21,7 @@ var udpMultipleGroupListenerTests = []net.Addr{
|
|||||||
|
|
||||||
func TestUDPSinglePacketConnWithMultipleGroupListeners(t *testing.T) {
|
func TestUDPSinglePacketConnWithMultipleGroupListeners(t *testing.T) {
|
||||||
switch runtime.GOOS {
|
switch runtime.GOOS {
|
||||||
case "plan9", "windows":
|
case "dragonfly", "plan9", "solaris", "windows":
|
||||||
t.Skipf("not supported on %q", runtime.GOOS)
|
t.Skipf("not supported on %q", runtime.GOOS)
|
||||||
}
|
}
|
||||||
if !supportsIPv6 {
|
if !supportsIPv6 {
|
||||||
@ -59,9 +59,9 @@ func TestUDPSinglePacketConnWithMultipleGroupListeners(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUDPMultipleConnWithMultipleGroupListeners(t *testing.T) {
|
func TestUDPMultiplePacketConnWithMultipleGroupListeners(t *testing.T) {
|
||||||
switch runtime.GOOS {
|
switch runtime.GOOS {
|
||||||
case "plan9", "windows":
|
case "dragonfly", "plan9", "solaris", "windows":
|
||||||
t.Skipf("not supported on %q", runtime.GOOS)
|
t.Skipf("not supported on %q", runtime.GOOS)
|
||||||
}
|
}
|
||||||
if !supportsIPv6 {
|
if !supportsIPv6 {
|
||||||
@ -113,14 +113,14 @@ func TestUDPMultipleConnWithMultipleGroupListeners(t *testing.T) {
|
|||||||
|
|
||||||
func TestUDPPerInterfaceSinglePacketConnWithSingleGroupListener(t *testing.T) {
|
func TestUDPPerInterfaceSinglePacketConnWithSingleGroupListener(t *testing.T) {
|
||||||
switch runtime.GOOS {
|
switch runtime.GOOS {
|
||||||
case "plan9", "windows":
|
case "dragonfly", "plan9", "solaris", "windows":
|
||||||
t.Skipf("not supported on %q", runtime.GOOS)
|
t.Skipf("not supported on %q", runtime.GOOS)
|
||||||
}
|
}
|
||||||
if !supportsIPv6 {
|
if !supportsIPv6 {
|
||||||
t.Skip("ipv6 is not supported")
|
t.Skip("ipv6 is not supported")
|
||||||
}
|
}
|
||||||
|
|
||||||
gaddr := &net.IPAddr{IP: net.ParseIP("ff02::114")} // see RFC 4727
|
gaddr := net.IPAddr{IP: net.ParseIP("ff02::114")} // see RFC 4727
|
||||||
type ml struct {
|
type ml struct {
|
||||||
c *ipv6.PacketConn
|
c *ipv6.PacketConn
|
||||||
ifi *net.Interface
|
ifi *net.Interface
|
||||||
@ -142,13 +142,13 @@ func TestUDPPerInterfaceSinglePacketConnWithSingleGroupListener(t *testing.T) {
|
|||||||
}
|
}
|
||||||
defer c.Close()
|
defer c.Close()
|
||||||
p := ipv6.NewPacketConn(c)
|
p := ipv6.NewPacketConn(c)
|
||||||
if err := p.JoinGroup(&ifi, gaddr); err != nil {
|
if err := p.JoinGroup(&ifi, &gaddr); err != nil {
|
||||||
t.Fatalf("ipv6.PacketConn.JoinGroup on %v failed: %v", ifi, err)
|
t.Fatalf("ipv6.PacketConn.JoinGroup on %v failed: %v", ifi, err)
|
||||||
}
|
}
|
||||||
mlt = append(mlt, &ml{p, &ift[i]})
|
mlt = append(mlt, &ml{p, &ift[i]})
|
||||||
}
|
}
|
||||||
for _, m := range mlt {
|
for _, m := range mlt {
|
||||||
if err := m.c.LeaveGroup(m.ifi, gaddr); err != nil {
|
if err := m.c.LeaveGroup(m.ifi, &gaddr); err != nil {
|
||||||
t.Fatalf("ipv6.PacketConn.LeaveGroup on %v failed: %v", m.ifi, err)
|
t.Fatalf("ipv6.PacketConn.LeaveGroup on %v failed: %v", m.ifi, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -156,7 +156,7 @@ func TestUDPPerInterfaceSinglePacketConnWithSingleGroupListener(t *testing.T) {
|
|||||||
|
|
||||||
func TestIPSinglePacketConnWithSingleGroupListener(t *testing.T) {
|
func TestIPSinglePacketConnWithSingleGroupListener(t *testing.T) {
|
||||||
switch runtime.GOOS {
|
switch runtime.GOOS {
|
||||||
case "plan9", "windows":
|
case "dragonfly", "plan9", "solaris", "windows":
|
||||||
t.Skipf("not supported on %q", runtime.GOOS)
|
t.Skipf("not supported on %q", runtime.GOOS)
|
||||||
}
|
}
|
||||||
if !supportsIPv6 {
|
if !supportsIPv6 {
|
||||||
@ -166,14 +166,14 @@ func TestIPSinglePacketConnWithSingleGroupListener(t *testing.T) {
|
|||||||
t.Skip("must be root")
|
t.Skip("must be root")
|
||||||
}
|
}
|
||||||
|
|
||||||
c, err := net.ListenPacket("ip6:ipv6-icmp", "::")
|
c, err := net.ListenPacket("ip6:ipv6-icmp", "::") // wildcard address
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("net.ListenPacket failed: %v", err)
|
t.Fatalf("net.ListenPacket failed: %v", err)
|
||||||
}
|
}
|
||||||
defer c.Close()
|
defer c.Close()
|
||||||
|
|
||||||
p := ipv6.NewPacketConn(c)
|
p := ipv6.NewPacketConn(c)
|
||||||
gaddr := &net.IPAddr{IP: net.ParseIP("ff02::114")} // see RFC 4727
|
gaddr := net.IPAddr{IP: net.ParseIP("ff02::114")} // see RFC 4727
|
||||||
var mift []*net.Interface
|
var mift []*net.Interface
|
||||||
|
|
||||||
ift, err := net.Interfaces()
|
ift, err := net.Interfaces()
|
||||||
@ -184,14 +184,60 @@ func TestIPSinglePacketConnWithSingleGroupListener(t *testing.T) {
|
|||||||
if _, ok := isMulticastAvailable(&ifi); !ok {
|
if _, ok := isMulticastAvailable(&ifi); !ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if err := p.JoinGroup(&ifi, gaddr); err != nil {
|
if err := p.JoinGroup(&ifi, &gaddr); err != nil {
|
||||||
t.Fatalf("ipv6.PacketConn.JoinGroup on %v failed: %v", ifi, err)
|
t.Fatalf("ipv6.PacketConn.JoinGroup on %v failed: %v", ifi, err)
|
||||||
}
|
}
|
||||||
mift = append(mift, &ift[i])
|
mift = append(mift, &ift[i])
|
||||||
}
|
}
|
||||||
for _, ifi := range mift {
|
for _, ifi := range mift {
|
||||||
if err := p.LeaveGroup(ifi, gaddr); err != nil {
|
if err := p.LeaveGroup(ifi, &gaddr); err != nil {
|
||||||
t.Fatalf("ipv6.PacketConn.LeaveGroup on %v failed: %v", ifi, err)
|
t.Fatalf("ipv6.PacketConn.LeaveGroup on %v failed: %v", ifi, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestIPPerInterfaceSinglePacketConnWithSingleGroupListener(t *testing.T) {
|
||||||
|
switch runtime.GOOS {
|
||||||
|
case "darwin", "dragonfly", "plan9", "solaris", "windows":
|
||||||
|
t.Skipf("not supported on %q", runtime.GOOS)
|
||||||
|
}
|
||||||
|
if !supportsIPv6 {
|
||||||
|
t.Skip("ipv6 is not supported")
|
||||||
|
}
|
||||||
|
if os.Getuid() != 0 {
|
||||||
|
t.Skip("must be root")
|
||||||
|
}
|
||||||
|
|
||||||
|
gaddr := net.IPAddr{IP: net.ParseIP("ff02::114")} // see RFC 4727
|
||||||
|
type ml struct {
|
||||||
|
c *ipv6.PacketConn
|
||||||
|
ifi *net.Interface
|
||||||
|
}
|
||||||
|
var mlt []*ml
|
||||||
|
|
||||||
|
ift, err := net.Interfaces()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("net.Interfaces failed: %v", err)
|
||||||
|
}
|
||||||
|
for i, ifi := range ift {
|
||||||
|
ip, ok := isMulticastAvailable(&ifi)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
c, err := net.ListenPacket("ip6:ipv6-icmp", fmt.Sprintf("%s%%%s", ip.String(), ifi.Name)) // unicast address
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("net.ListenPacket failed: %v", err)
|
||||||
|
}
|
||||||
|
defer c.Close()
|
||||||
|
p := ipv6.NewPacketConn(c)
|
||||||
|
if err := p.JoinGroup(&ifi, &gaddr); err != nil {
|
||||||
|
t.Fatalf("ipv6.PacketConn.JoinGroup on %v failed: %v", ifi, err)
|
||||||
|
}
|
||||||
|
mlt = append(mlt, &ml{p, &ift[i]})
|
||||||
|
}
|
||||||
|
for _, m := range mlt {
|
||||||
|
if err := m.c.LeaveGroup(m.ifi, &gaddr); err != nil {
|
||||||
|
t.Fatalf("ipv6.PacketConn.LeaveGroup on %v failed: %v", m.ifi, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
2
Godeps/_workspace/src/code.google.com/p/go.net/ipv6/multicastsockopt_test.go
generated
vendored
2
Godeps/_workspace/src/code.google.com/p/go.net/ipv6/multicastsockopt_test.go
generated
vendored
@ -22,7 +22,7 @@ var packetConnMulticastSocketOptionTests = []struct {
|
|||||||
|
|
||||||
func TestPacketConnMulticastSocketOptions(t *testing.T) {
|
func TestPacketConnMulticastSocketOptions(t *testing.T) {
|
||||||
switch runtime.GOOS {
|
switch runtime.GOOS {
|
||||||
case "plan9", "windows":
|
case "dragonfly", "plan9", "solaris", "windows":
|
||||||
t.Skipf("not supported on %q", runtime.GOOS)
|
t.Skipf("not supported on %q", runtime.GOOS)
|
||||||
}
|
}
|
||||||
if !supportsIPv6 {
|
if !supportsIPv6 {
|
||||||
|
168
Godeps/_workspace/src/code.google.com/p/go.net/ipv6/readwrite_test.go
generated
vendored
Normal file
168
Godeps/_workspace/src/code.google.com/p/go.net/ipv6/readwrite_test.go
generated
vendored
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
package ipv6_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"code.google.com/p/go.net/ipv6"
|
||||||
|
"net"
|
||||||
|
"runtime"
|
||||||
|
"sync"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func benchmarkUDPListener() (net.PacketConn, net.Addr, error) {
|
||||||
|
c, err := net.ListenPacket("udp6", "[::1]:0")
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
dst, err := net.ResolveUDPAddr("udp6", c.LocalAddr().String())
|
||||||
|
if err != nil {
|
||||||
|
c.Close()
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
return c, dst, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkReadWriteNetUDP(b *testing.B) {
|
||||||
|
c, dst, err := benchmarkUDPListener()
|
||||||
|
if err != nil {
|
||||||
|
b.Fatalf("benchmarkUDPListener failed: %v", err)
|
||||||
|
}
|
||||||
|
defer c.Close()
|
||||||
|
|
||||||
|
wb, rb := []byte("HELLO-R-U-THERE"), make([]byte, 128)
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
benchmarkReadWriteNetUDP(b, c, wb, rb, dst)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func benchmarkReadWriteNetUDP(b *testing.B, c net.PacketConn, wb, rb []byte, dst net.Addr) {
|
||||||
|
if _, err := c.WriteTo(wb, dst); err != nil {
|
||||||
|
b.Fatalf("net.PacketConn.WriteTo failed: %v", err)
|
||||||
|
}
|
||||||
|
if _, _, err := c.ReadFrom(rb); err != nil {
|
||||||
|
b.Fatalf("net.PacketConn.ReadFrom failed: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkReadWriteIPv6UDP(b *testing.B) {
|
||||||
|
c, dst, err := benchmarkUDPListener()
|
||||||
|
if err != nil {
|
||||||
|
b.Fatalf("benchmarkUDPListener failed: %v", err)
|
||||||
|
}
|
||||||
|
defer c.Close()
|
||||||
|
|
||||||
|
p := ipv6.NewPacketConn(c)
|
||||||
|
cf := ipv6.FlagTrafficClass | ipv6.FlagHopLimit | ipv6.FlagInterface | ipv6.FlagPathMTU
|
||||||
|
if err := p.SetControlMessage(cf, true); err != nil {
|
||||||
|
b.Fatalf("ipv6.PacketConn.SetControlMessage failed: %v", err)
|
||||||
|
}
|
||||||
|
ifi := loopbackInterface()
|
||||||
|
|
||||||
|
wb, rb := []byte("HELLO-R-U-THERE"), make([]byte, 128)
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
benchmarkReadWriteIPv6UDP(b, p, wb, rb, dst, ifi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func benchmarkReadWriteIPv6UDP(b *testing.B, p *ipv6.PacketConn, wb, rb []byte, dst net.Addr, ifi *net.Interface) {
|
||||||
|
cm := ipv6.ControlMessage{
|
||||||
|
TrafficClass: DiffServAF11 | CongestionExperienced,
|
||||||
|
HopLimit: 1,
|
||||||
|
}
|
||||||
|
if ifi != nil {
|
||||||
|
cm.IfIndex = ifi.Index
|
||||||
|
}
|
||||||
|
if n, err := p.WriteTo(wb, &cm, dst); err != nil {
|
||||||
|
b.Fatalf("ipv6.PacketConn.WriteTo failed: %v", err)
|
||||||
|
} else if n != len(wb) {
|
||||||
|
b.Fatalf("ipv6.PacketConn.WriteTo failed: short write: %v", n)
|
||||||
|
}
|
||||||
|
if _, _, _, err := p.ReadFrom(rb); err != nil {
|
||||||
|
b.Fatalf("ipv6.PacketConn.ReadFrom failed: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPacketConnConcurrentReadWriteUnicastUDP(t *testing.T) {
|
||||||
|
switch runtime.GOOS {
|
||||||
|
case "dragonfly", "plan9", "solaris", "windows":
|
||||||
|
t.Skipf("not supported on %q", runtime.GOOS)
|
||||||
|
}
|
||||||
|
if !supportsIPv6 {
|
||||||
|
t.Skip("ipv6 is not supported")
|
||||||
|
}
|
||||||
|
|
||||||
|
c, err := net.ListenPacket("udp6", "[::1]:0")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("net.ListenPacket failed: %v", err)
|
||||||
|
}
|
||||||
|
defer c.Close()
|
||||||
|
p := ipv6.NewPacketConn(c)
|
||||||
|
defer p.Close()
|
||||||
|
|
||||||
|
dst, err := net.ResolveUDPAddr("udp6", c.LocalAddr().String())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("net.ResolveUDPAddr failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ifi := loopbackInterface()
|
||||||
|
cf := ipv6.FlagTrafficClass | ipv6.FlagHopLimit | ipv6.FlagSrc | ipv6.FlagDst | ipv6.FlagInterface | ipv6.FlagPathMTU
|
||||||
|
wb := []byte("HELLO-R-U-THERE")
|
||||||
|
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
reader := func() {
|
||||||
|
defer wg.Done()
|
||||||
|
rb := make([]byte, 128)
|
||||||
|
if n, cm, _, err := p.ReadFrom(rb); err != nil {
|
||||||
|
t.Errorf("ipv6.PacketConn.ReadFrom failed: %v", err)
|
||||||
|
return
|
||||||
|
} else if !bytes.Equal(rb[:n], wb) {
|
||||||
|
t.Errorf("got %v; expected %v", rb[:n], wb)
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
t.Logf("rcvd cmsg: %v", cm)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
writer := func(toggle bool) {
|
||||||
|
defer wg.Done()
|
||||||
|
cm := ipv6.ControlMessage{
|
||||||
|
TrafficClass: DiffServAF11 | CongestionExperienced,
|
||||||
|
Src: net.IPv6loopback,
|
||||||
|
Dst: net.IPv6loopback,
|
||||||
|
}
|
||||||
|
if ifi != nil {
|
||||||
|
cm.IfIndex = ifi.Index
|
||||||
|
}
|
||||||
|
if err := p.SetControlMessage(cf, toggle); err != nil {
|
||||||
|
t.Errorf("ipv6.PacketConn.SetControlMessage failed: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if n, err := p.WriteTo(wb, &cm, dst); err != nil {
|
||||||
|
t.Errorf("ipv6.PacketConn.WriteTo failed: %v", err)
|
||||||
|
return
|
||||||
|
} else if n != len(wb) {
|
||||||
|
t.Errorf("ipv6.PacketConn.WriteTo failed: short write: %v", n)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const N = 10
|
||||||
|
wg.Add(N)
|
||||||
|
for i := 0; i < N; i++ {
|
||||||
|
go reader()
|
||||||
|
}
|
||||||
|
wg.Add(2 * N)
|
||||||
|
for i := 0; i < 2*N; i++ {
|
||||||
|
go writer(i%2 != 0)
|
||||||
|
}
|
||||||
|
wg.Add(N)
|
||||||
|
for i := 0; i < N; i++ {
|
||||||
|
go reader()
|
||||||
|
}
|
||||||
|
wg.Wait()
|
||||||
|
}
|
66
Godeps/_workspace/src/code.google.com/p/go.net/ipv6/sockopt_rfc2292_darwin.go
generated
vendored
66
Godeps/_workspace/src/code.google.com/p/go.net/ipv6/sockopt_rfc2292_darwin.go
generated
vendored
@ -1,66 +0,0 @@
|
|||||||
// 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.
|
|
||||||
|
|
||||||
package ipv6
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"syscall"
|
|
||||||
)
|
|
||||||
|
|
||||||
func ipv6ReceiveTrafficClass(fd int) (bool, error) {
|
|
||||||
return false, errNotSupported
|
|
||||||
}
|
|
||||||
|
|
||||||
func setIPv6ReceiveTrafficClass(fd int, v bool) error {
|
|
||||||
return errNotSupported
|
|
||||||
}
|
|
||||||
|
|
||||||
func ipv6ReceiveHopLimit(fd int) (bool, error) {
|
|
||||||
v, err := syscall.GetsockoptInt(fd, ianaProtocolIPv6, syscall.IPV6_2292HOPLIMIT)
|
|
||||||
if err != nil {
|
|
||||||
return false, os.NewSyscallError("getsockopt", err)
|
|
||||||
}
|
|
||||||
return v == 1, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func setIPv6ReceiveHopLimit(fd int, v bool) error {
|
|
||||||
return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolIPv6, syscall.IPV6_2292HOPLIMIT, boolint(v)))
|
|
||||||
}
|
|
||||||
|
|
||||||
func ipv6ReceivePacketInfo(fd int) (bool, error) {
|
|
||||||
v, err := syscall.GetsockoptInt(fd, ianaProtocolIPv6, syscall.IPV6_2292PKTINFO)
|
|
||||||
if err != nil {
|
|
||||||
return false, os.NewSyscallError("getsockopt", err)
|
|
||||||
}
|
|
||||||
return v == 1, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func setIPv6ReceivePacketInfo(fd int, v bool) error {
|
|
||||||
return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolIPv6, syscall.IPV6_2292PKTINFO, boolint(v)))
|
|
||||||
}
|
|
||||||
|
|
||||||
func ipv6PathMTU(fd int) (int, error) {
|
|
||||||
return 0, errNotSupported
|
|
||||||
}
|
|
||||||
|
|
||||||
func ipv6ReceivePathMTU(fd int) (bool, error) {
|
|
||||||
return false, errNotSupported
|
|
||||||
}
|
|
||||||
|
|
||||||
func setIPv6ReceivePathMTU(fd int, v bool) error {
|
|
||||||
return errNotSupported
|
|
||||||
}
|
|
||||||
|
|
||||||
func ipv6ICMPFilter(fd int) (*ICMPFilter, error) {
|
|
||||||
v, err := syscall.GetsockoptICMPv6Filter(fd, ianaProtocolIPv6ICMP, syscall.ICMP6_FILTER)
|
|
||||||
if err != nil {
|
|
||||||
return nil, os.NewSyscallError("getsockopt", err)
|
|
||||||
}
|
|
||||||
return &ICMPFilter{rawICMPFilter: rawICMPFilter{*v}}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func setIPv6ICMPFilter(fd int, f *ICMPFilter) error {
|
|
||||||
return os.NewSyscallError("setsockopt", syscall.SetsockoptICMPv6Filter(fd, ianaProtocolIPv6ICMP, syscall.ICMP6_FILTER, &f.rawICMPFilter.ICMPv6Filter))
|
|
||||||
}
|
|
73
Godeps/_workspace/src/code.google.com/p/go.net/ipv6/sockopt_rfc2292_unix.go
generated
vendored
Normal file
73
Godeps/_workspace/src/code.google.com/p/go.net/ipv6/sockopt_rfc2292_unix.go
generated
vendored
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
// 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 darwin
|
||||||
|
|
||||||
|
package ipv6
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ipv6ReceiveTrafficClass(fd int) (bool, error) {
|
||||||
|
return false, errOpNoSupport
|
||||||
|
}
|
||||||
|
|
||||||
|
func setIPv6ReceiveTrafficClass(fd int, v bool) error {
|
||||||
|
return errOpNoSupport
|
||||||
|
}
|
||||||
|
|
||||||
|
func ipv6ReceiveHopLimit(fd int) (bool, error) {
|
||||||
|
var v int32
|
||||||
|
l := sysSockoptLen(4)
|
||||||
|
if err := getsockopt(fd, ianaProtocolIPv6, sysSockopt2292HopLimit, uintptr(unsafe.Pointer(&v)), &l); err != nil {
|
||||||
|
return false, os.NewSyscallError("getsockopt", err)
|
||||||
|
}
|
||||||
|
return v == 1, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func setIPv6ReceiveHopLimit(fd int, v bool) error {
|
||||||
|
vv := int32(boolint(v))
|
||||||
|
return os.NewSyscallError("setsockopt", setsockopt(fd, ianaProtocolIPv6, sysSockopt2292HopLimit, uintptr(unsafe.Pointer(&vv)), 4))
|
||||||
|
}
|
||||||
|
|
||||||
|
func ipv6ReceivePacketInfo(fd int) (bool, error) {
|
||||||
|
var v int32
|
||||||
|
l := sysSockoptLen(4)
|
||||||
|
if err := getsockopt(fd, ianaProtocolIPv6, sysSockopt2292PacketInfo, uintptr(unsafe.Pointer(&v)), &l); err != nil {
|
||||||
|
return false, os.NewSyscallError("getsockopt", err)
|
||||||
|
}
|
||||||
|
return v == 1, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func setIPv6ReceivePacketInfo(fd int, v bool) error {
|
||||||
|
vv := int32(boolint(v))
|
||||||
|
return os.NewSyscallError("setsockopt", setsockopt(fd, ianaProtocolIPv6, sysSockopt2292PacketInfo, uintptr(unsafe.Pointer(&vv)), 4))
|
||||||
|
}
|
||||||
|
|
||||||
|
func ipv6PathMTU(fd int) (int, error) {
|
||||||
|
return 0, errOpNoSupport
|
||||||
|
}
|
||||||
|
|
||||||
|
func ipv6ReceivePathMTU(fd int) (bool, error) {
|
||||||
|
return false, errOpNoSupport
|
||||||
|
}
|
||||||
|
|
||||||
|
func setIPv6ReceivePathMTU(fd int, v bool) error {
|
||||||
|
return errOpNoSupport
|
||||||
|
}
|
||||||
|
|
||||||
|
func ipv6ICMPFilter(fd int) (*ICMPFilter, error) {
|
||||||
|
var v ICMPFilter
|
||||||
|
l := sysSockoptLen(sysSizeofICMPFilter)
|
||||||
|
if err := getsockopt(fd, ianaProtocolIPv6ICMP, sysSockoptICMPFilter, uintptr(unsafe.Pointer(&v.sysICMPFilter)), &l); err != nil {
|
||||||
|
return nil, os.NewSyscallError("getsockopt", err)
|
||||||
|
}
|
||||||
|
return &v, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func setIPv6ICMPFilter(fd int, f *ICMPFilter) error {
|
||||||
|
return os.NewSyscallError("setsockopt", setsockopt(fd, ianaProtocolIPv6ICMP, sysSockoptICMPFilter, uintptr(unsafe.Pointer(&f.sysICMPFilter)), sysSizeofICMPFilter))
|
||||||
|
}
|
5
Godeps/_workspace/src/code.google.com/p/go.net/ipv6/sockopt_rfc3493_bsd.go
generated
vendored
5
Godeps/_workspace/src/code.google.com/p/go.net/ipv6/sockopt_rfc3493_bsd.go
generated
vendored
@ -8,12 +8,13 @@ package ipv6
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
"syscall"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
func setIPv6Checksum(fd int, on bool, offset int) error {
|
func setIPv6Checksum(fd int, on bool, offset int) error {
|
||||||
if !on {
|
if !on {
|
||||||
offset = -1
|
offset = -1
|
||||||
}
|
}
|
||||||
return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolIPv6, syscall.IPV6_CHECKSUM, offset))
|
v := int32(offset)
|
||||||
|
return os.NewSyscallError("setsockopt", setsockopt(fd, ianaProtocolIPv6, sysSockoptChecksum, uintptr(unsafe.Pointer(&v)), 4))
|
||||||
}
|
}
|
||||||
|
5
Godeps/_workspace/src/code.google.com/p/go.net/ipv6/sockopt_rfc3493_linux.go
generated
vendored
5
Godeps/_workspace/src/code.google.com/p/go.net/ipv6/sockopt_rfc3493_linux.go
generated
vendored
@ -6,12 +6,13 @@ package ipv6
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
"syscall"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
func setIPv6Checksum(fd int, on bool, offset int) error {
|
func setIPv6Checksum(fd int, on bool, offset int) error {
|
||||||
if !on {
|
if !on {
|
||||||
offset = -1
|
offset = -1
|
||||||
}
|
}
|
||||||
return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolReserved, syscall.IPV6_CHECKSUM, offset))
|
v := int32(offset)
|
||||||
|
return os.NewSyscallError("setsockopt", setsockopt(fd, ianaProtocolReserved, sysSockoptChecksum, uintptr(unsafe.Pointer(&v)), 4))
|
||||||
}
|
}
|
||||||
|
76
Godeps/_workspace/src/code.google.com/p/go.net/ipv6/sockopt_rfc3493_unix.go
generated
vendored
76
Godeps/_workspace/src/code.google.com/p/go.net/ipv6/sockopt_rfc3493_unix.go
generated
vendored
@ -9,66 +9,74 @@ package ipv6
|
|||||||
import (
|
import (
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"syscall"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ipv6TrafficClass(fd int) (int, error) {
|
func ipv6TrafficClass(fd int) (int, error) {
|
||||||
v, err := syscall.GetsockoptInt(fd, ianaProtocolIPv6, syscall.IPV6_TCLASS)
|
var v int32
|
||||||
if err != nil {
|
l := sysSockoptLen(4)
|
||||||
|
if err := getsockopt(fd, ianaProtocolIPv6, sysSockoptTrafficClass, uintptr(unsafe.Pointer(&v)), &l); err != nil {
|
||||||
return 0, os.NewSyscallError("getsockopt", err)
|
return 0, os.NewSyscallError("getsockopt", err)
|
||||||
}
|
}
|
||||||
return v, nil
|
return int(v), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func setIPv6TrafficClass(fd, v int) error {
|
func setIPv6TrafficClass(fd, v int) error {
|
||||||
return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolIPv6, syscall.IPV6_TCLASS, v))
|
vv := int32(v)
|
||||||
|
return os.NewSyscallError("setsockopt", setsockopt(fd, ianaProtocolIPv6, sysSockoptTrafficClass, uintptr(unsafe.Pointer(&vv)), 4))
|
||||||
}
|
}
|
||||||
|
|
||||||
func ipv6HopLimit(fd int) (int, error) {
|
func ipv6HopLimit(fd int) (int, error) {
|
||||||
v, err := syscall.GetsockoptInt(fd, ianaProtocolIPv6, syscall.IPV6_UNICAST_HOPS)
|
var v int32
|
||||||
if err != nil {
|
l := sysSockoptLen(4)
|
||||||
|
if err := getsockopt(fd, ianaProtocolIPv6, sysSockoptUnicastHopLimit, uintptr(unsafe.Pointer(&v)), &l); err != nil {
|
||||||
return 0, os.NewSyscallError("getsockopt", err)
|
return 0, os.NewSyscallError("getsockopt", err)
|
||||||
}
|
}
|
||||||
return v, nil
|
return int(v), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func setIPv6HopLimit(fd, v int) error {
|
func setIPv6HopLimit(fd, v int) error {
|
||||||
return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolIPv6, syscall.IPV6_UNICAST_HOPS, v))
|
vv := int32(v)
|
||||||
|
return os.NewSyscallError("setsockopt", setsockopt(fd, ianaProtocolIPv6, sysSockoptUnicastHopLimit, uintptr(unsafe.Pointer(&vv)), 4))
|
||||||
}
|
}
|
||||||
|
|
||||||
func ipv6Checksum(fd int) (bool, int, error) {
|
func ipv6Checksum(fd int) (bool, int, error) {
|
||||||
v, err := syscall.GetsockoptInt(fd, ianaProtocolIPv6, syscall.IPV6_CHECKSUM)
|
var v int32
|
||||||
if err != nil {
|
l := sysSockoptLen(4)
|
||||||
|
if err := getsockopt(fd, ianaProtocolIPv6, sysSockoptChecksum, uintptr(unsafe.Pointer(&v)), &l); err != nil {
|
||||||
return false, 0, os.NewSyscallError("getsockopt", err)
|
return false, 0, os.NewSyscallError("getsockopt", err)
|
||||||
}
|
}
|
||||||
on := true
|
on := true
|
||||||
if v == -1 {
|
if v == -1 {
|
||||||
on = false
|
on = false
|
||||||
}
|
}
|
||||||
return on, v, nil
|
return on, int(v), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func ipv6MulticastHopLimit(fd int) (int, error) {
|
func ipv6MulticastHopLimit(fd int) (int, error) {
|
||||||
v, err := syscall.GetsockoptInt(fd, ianaProtocolIPv6, syscall.IPV6_MULTICAST_HOPS)
|
var v int32
|
||||||
if err != nil {
|
l := sysSockoptLen(4)
|
||||||
|
if err := getsockopt(fd, ianaProtocolIPv6, sysSockoptMulticastHopLimit, uintptr(unsafe.Pointer(&v)), &l); err != nil {
|
||||||
return 0, os.NewSyscallError("getsockopt", err)
|
return 0, os.NewSyscallError("getsockopt", err)
|
||||||
}
|
}
|
||||||
return v, nil
|
return int(v), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func setIPv6MulticastHopLimit(fd, v int) error {
|
func setIPv6MulticastHopLimit(fd, v int) error {
|
||||||
return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolIPv6, syscall.IPV6_MULTICAST_HOPS, v))
|
vv := int32(v)
|
||||||
|
return os.NewSyscallError("setsockopt", setsockopt(fd, ianaProtocolIPv6, sysSockoptMulticastHopLimit, uintptr(unsafe.Pointer(&vv)), 4))
|
||||||
}
|
}
|
||||||
|
|
||||||
func ipv6MulticastInterface(fd int) (*net.Interface, error) {
|
func ipv6MulticastInterface(fd int) (*net.Interface, error) {
|
||||||
v, err := syscall.GetsockoptInt(fd, ianaProtocolIPv6, syscall.IPV6_MULTICAST_IF)
|
var v int32
|
||||||
if err != nil {
|
l := sysSockoptLen(4)
|
||||||
|
if err := getsockopt(fd, ianaProtocolIPv6, sysSockoptMulticastInterface, uintptr(unsafe.Pointer(&v)), &l); err != nil {
|
||||||
return nil, os.NewSyscallError("getsockopt", err)
|
return nil, os.NewSyscallError("getsockopt", err)
|
||||||
}
|
}
|
||||||
if v == 0 {
|
if v == 0 {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
ifi, err := net.InterfaceByIndex(v)
|
ifi, err := net.InterfaceByIndex(int(v))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -76,39 +84,41 @@ func ipv6MulticastInterface(fd int) (*net.Interface, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func setIPv6MulticastInterface(fd int, ifi *net.Interface) error {
|
func setIPv6MulticastInterface(fd int, ifi *net.Interface) error {
|
||||||
var v int
|
var v int32
|
||||||
if ifi != nil {
|
if ifi != nil {
|
||||||
v = ifi.Index
|
v = int32(ifi.Index)
|
||||||
}
|
}
|
||||||
return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolIPv6, syscall.IPV6_MULTICAST_IF, v))
|
return os.NewSyscallError("setsockopt", setsockopt(fd, ianaProtocolIPv6, sysSockoptMulticastInterface, uintptr(unsafe.Pointer(&v)), 4))
|
||||||
}
|
}
|
||||||
|
|
||||||
func ipv6MulticastLoopback(fd int) (bool, error) {
|
func ipv6MulticastLoopback(fd int) (bool, error) {
|
||||||
v, err := syscall.GetsockoptInt(fd, ianaProtocolIPv6, syscall.IPV6_MULTICAST_LOOP)
|
var v int32
|
||||||
if err != nil {
|
l := sysSockoptLen(4)
|
||||||
|
if err := getsockopt(fd, ianaProtocolIPv6, sysSockoptMulticastLoopback, uintptr(unsafe.Pointer(&v)), &l); err != nil {
|
||||||
return false, os.NewSyscallError("getsockopt", err)
|
return false, os.NewSyscallError("getsockopt", err)
|
||||||
}
|
}
|
||||||
return v == 1, nil
|
return v == 1, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func setIPv6MulticastLoopback(fd int, v bool) error {
|
func setIPv6MulticastLoopback(fd int, v bool) error {
|
||||||
return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolIPv6, syscall.IPV6_MULTICAST_LOOP, boolint(v)))
|
vv := int32(boolint(v))
|
||||||
|
return os.NewSyscallError("setsockopt", setsockopt(fd, ianaProtocolIPv6, sysSockoptMulticastLoopback, uintptr(unsafe.Pointer(&vv)), 4))
|
||||||
}
|
}
|
||||||
|
|
||||||
func joinIPv6Group(fd int, ifi *net.Interface, grp net.IP) error {
|
func joinIPv6Group(fd int, ifi *net.Interface, grp net.IP) error {
|
||||||
mreq := syscall.IPv6Mreq{}
|
mreq := sysMulticastReq{}
|
||||||
copy(mreq.Multiaddr[:], grp)
|
copy(mreq.IP[:], grp)
|
||||||
if ifi != nil {
|
if ifi != nil {
|
||||||
mreq.Interface = uint32(ifi.Index)
|
mreq.IfIndex = uint32(ifi.Index)
|
||||||
}
|
}
|
||||||
return os.NewSyscallError("setsockopt", syscall.SetsockoptIPv6Mreq(fd, ianaProtocolIPv6, syscall.IPV6_JOIN_GROUP, &mreq))
|
return os.NewSyscallError("setsockopt", setsockopt(fd, ianaProtocolIPv6, sysSockoptJoinGroup, uintptr(unsafe.Pointer(&mreq)), sysSizeofMulticastReq))
|
||||||
}
|
}
|
||||||
|
|
||||||
func leaveIPv6Group(fd int, ifi *net.Interface, grp net.IP) error {
|
func leaveIPv6Group(fd int, ifi *net.Interface, grp net.IP) error {
|
||||||
mreq := syscall.IPv6Mreq{}
|
mreq := sysMulticastReq{}
|
||||||
copy(mreq.Multiaddr[:], grp)
|
copy(mreq.IP[:], grp)
|
||||||
if ifi != nil {
|
if ifi != nil {
|
||||||
mreq.Interface = uint32(ifi.Index)
|
mreq.IfIndex = uint32(ifi.Index)
|
||||||
}
|
}
|
||||||
return os.NewSyscallError("setsockopt", syscall.SetsockoptIPv6Mreq(fd, ianaProtocolIPv6, syscall.IPV6_LEAVE_GROUP, &mreq))
|
return os.NewSyscallError("setsockopt", setsockopt(fd, ianaProtocolIPv6, sysSockoptLeaveGroup, uintptr(unsafe.Pointer(&mreq)), sysSizeofMulticastReq))
|
||||||
}
|
}
|
||||||
|
32
Godeps/_workspace/src/code.google.com/p/go.net/ipv6/sockopt_rfc3493_windows.go
generated
vendored
32
Godeps/_workspace/src/code.google.com/p/go.net/ipv6/sockopt_rfc3493_windows.go
generated
vendored
@ -24,7 +24,7 @@ func setIPv6TrafficClass(fd syscall.Handle, v int) error {
|
|||||||
func ipv6HopLimit(fd syscall.Handle) (int, error) {
|
func ipv6HopLimit(fd syscall.Handle) (int, error) {
|
||||||
var v int32
|
var v int32
|
||||||
l := int32(4)
|
l := int32(4)
|
||||||
if err := syscall.Getsockopt(fd, ianaProtocolIPv6, syscall.IPV6_UNICAST_HOPS, (*byte)(unsafe.Pointer(&v)), &l); err != nil {
|
if err := syscall.Getsockopt(fd, ianaProtocolIPv6, sysSockoptUnicastHopLimit, (*byte)(unsafe.Pointer(&v)), &l); err != nil {
|
||||||
return 0, os.NewSyscallError("getsockopt", err)
|
return 0, os.NewSyscallError("getsockopt", err)
|
||||||
}
|
}
|
||||||
return int(v), nil
|
return int(v), nil
|
||||||
@ -32,7 +32,7 @@ func ipv6HopLimit(fd syscall.Handle) (int, error) {
|
|||||||
|
|
||||||
func setIPv6HopLimit(fd syscall.Handle, v int) error {
|
func setIPv6HopLimit(fd syscall.Handle, v int) error {
|
||||||
vv := int32(v)
|
vv := int32(v)
|
||||||
return os.NewSyscallError("setsockopt", syscall.Setsockopt(fd, ianaProtocolIPv6, syscall.IPV6_UNICAST_HOPS, (*byte)(unsafe.Pointer(&vv)), 4))
|
return os.NewSyscallError("setsockopt", syscall.Setsockopt(fd, ianaProtocolIPv6, sysSockoptUnicastHopLimit, (*byte)(unsafe.Pointer(&vv)), 4))
|
||||||
}
|
}
|
||||||
|
|
||||||
func ipv6Checksum(fd syscall.Handle) (bool, int, error) {
|
func ipv6Checksum(fd syscall.Handle) (bool, int, error) {
|
||||||
@ -43,7 +43,7 @@ func ipv6Checksum(fd syscall.Handle) (bool, int, error) {
|
|||||||
func ipv6MulticastHopLimit(fd syscall.Handle) (int, error) {
|
func ipv6MulticastHopLimit(fd syscall.Handle) (int, error) {
|
||||||
var v int32
|
var v int32
|
||||||
l := int32(4)
|
l := int32(4)
|
||||||
if err := syscall.Getsockopt(fd, ianaProtocolIPv6, syscall.IPV6_MULTICAST_HOPS, (*byte)(unsafe.Pointer(&v)), &l); err != nil {
|
if err := syscall.Getsockopt(fd, ianaProtocolIPv6, sysSockoptMulticastHopLimit, (*byte)(unsafe.Pointer(&v)), &l); err != nil {
|
||||||
return 0, os.NewSyscallError("getsockopt", err)
|
return 0, os.NewSyscallError("getsockopt", err)
|
||||||
}
|
}
|
||||||
return int(v), nil
|
return int(v), nil
|
||||||
@ -51,13 +51,13 @@ func ipv6MulticastHopLimit(fd syscall.Handle) (int, error) {
|
|||||||
|
|
||||||
func setIPv6MulticastHopLimit(fd syscall.Handle, v int) error {
|
func setIPv6MulticastHopLimit(fd syscall.Handle, v int) error {
|
||||||
vv := int32(v)
|
vv := int32(v)
|
||||||
return os.NewSyscallError("setsockopt", syscall.Setsockopt(fd, ianaProtocolIPv6, syscall.IPV6_MULTICAST_HOPS, (*byte)(unsafe.Pointer(&vv)), 4))
|
return os.NewSyscallError("setsockopt", syscall.Setsockopt(fd, ianaProtocolIPv6, sysSockoptMulticastHopLimit, (*byte)(unsafe.Pointer(&vv)), 4))
|
||||||
}
|
}
|
||||||
|
|
||||||
func ipv6MulticastInterface(fd syscall.Handle) (*net.Interface, error) {
|
func ipv6MulticastInterface(fd syscall.Handle) (*net.Interface, error) {
|
||||||
var v int32
|
var v int32
|
||||||
l := int32(4)
|
l := int32(4)
|
||||||
if err := syscall.Getsockopt(fd, ianaProtocolIPv6, syscall.IPV6_MULTICAST_IF, (*byte)(unsafe.Pointer(&v)), &l); err != nil {
|
if err := syscall.Getsockopt(fd, ianaProtocolIPv6, sysSockoptMulticastInterface, (*byte)(unsafe.Pointer(&v)), &l); err != nil {
|
||||||
return nil, os.NewSyscallError("getsockopt", err)
|
return nil, os.NewSyscallError("getsockopt", err)
|
||||||
}
|
}
|
||||||
if v == 0 {
|
if v == 0 {
|
||||||
@ -75,13 +75,13 @@ func setIPv6MulticastInterface(fd syscall.Handle, ifi *net.Interface) error {
|
|||||||
if ifi != nil {
|
if ifi != nil {
|
||||||
v = int32(ifi.Index)
|
v = int32(ifi.Index)
|
||||||
}
|
}
|
||||||
return os.NewSyscallError("setsockopt", syscall.Setsockopt(fd, ianaProtocolIPv6, syscall.IPV6_MULTICAST_IF, (*byte)(unsafe.Pointer(&v)), 4))
|
return os.NewSyscallError("setsockopt", syscall.Setsockopt(fd, ianaProtocolIPv6, sysSockoptMulticastInterface, (*byte)(unsafe.Pointer(&v)), 4))
|
||||||
}
|
}
|
||||||
|
|
||||||
func ipv6MulticastLoopback(fd syscall.Handle) (bool, error) {
|
func ipv6MulticastLoopback(fd syscall.Handle) (bool, error) {
|
||||||
var v int32
|
var v int32
|
||||||
l := int32(4)
|
l := int32(4)
|
||||||
if err := syscall.Getsockopt(fd, ianaProtocolIPv6, syscall.IPV6_MULTICAST_LOOP, (*byte)(unsafe.Pointer(&v)), &l); err != nil {
|
if err := syscall.Getsockopt(fd, ianaProtocolIPv6, sysSockoptMulticastLoopback, (*byte)(unsafe.Pointer(&v)), &l); err != nil {
|
||||||
return false, os.NewSyscallError("getsockopt", err)
|
return false, os.NewSyscallError("getsockopt", err)
|
||||||
}
|
}
|
||||||
return v == 1, nil
|
return v == 1, nil
|
||||||
@ -89,25 +89,25 @@ func ipv6MulticastLoopback(fd syscall.Handle) (bool, error) {
|
|||||||
|
|
||||||
func setIPv6MulticastLoopback(fd syscall.Handle, v bool) error {
|
func setIPv6MulticastLoopback(fd syscall.Handle, v bool) error {
|
||||||
vv := int32(boolint(v))
|
vv := int32(boolint(v))
|
||||||
return os.NewSyscallError("setsockopt", syscall.Setsockopt(fd, ianaProtocolIPv6, syscall.IPV6_MULTICAST_LOOP, (*byte)(unsafe.Pointer(&vv)), 4))
|
return os.NewSyscallError("setsockopt", syscall.Setsockopt(fd, ianaProtocolIPv6, sysSockoptMulticastLoopback, (*byte)(unsafe.Pointer(&vv)), 4))
|
||||||
}
|
}
|
||||||
|
|
||||||
func joinIPv6Group(fd syscall.Handle, ifi *net.Interface, grp net.IP) error {
|
func joinIPv6Group(fd syscall.Handle, ifi *net.Interface, grp net.IP) error {
|
||||||
mreq := syscall.IPv6Mreq{}
|
mreq := sysMulticastReq{}
|
||||||
copy(mreq.Multiaddr[:], grp)
|
copy(mreq.IP[:], grp)
|
||||||
if ifi != nil {
|
if ifi != nil {
|
||||||
mreq.Interface = uint32(ifi.Index)
|
mreq.IfIndex = uint32(ifi.Index)
|
||||||
}
|
}
|
||||||
return os.NewSyscallError("setsockopt", syscall.Setsockopt(fd, ianaProtocolIPv6, syscall.IPV6_JOIN_GROUP, (*byte)(unsafe.Pointer(&mreq)), int32(unsafe.Sizeof(mreq))))
|
return os.NewSyscallError("setsockopt", syscall.Setsockopt(fd, ianaProtocolIPv6, sysSockoptJoinGroup, (*byte)(unsafe.Pointer(&mreq)), int32(sysSizeofMulticastReq)))
|
||||||
}
|
}
|
||||||
|
|
||||||
func leaveIPv6Group(fd syscall.Handle, ifi *net.Interface, grp net.IP) error {
|
func leaveIPv6Group(fd syscall.Handle, ifi *net.Interface, grp net.IP) error {
|
||||||
mreq := syscall.IPv6Mreq{}
|
mreq := sysMulticastReq{}
|
||||||
copy(mreq.Multiaddr[:], grp)
|
copy(mreq.IP[:], grp)
|
||||||
if ifi != nil {
|
if ifi != nil {
|
||||||
mreq.Interface = uint32(ifi.Index)
|
mreq.IfIndex = uint32(ifi.Index)
|
||||||
}
|
}
|
||||||
return os.NewSyscallError("setsockopt", syscall.Setsockopt(fd, ianaProtocolIPv6, syscall.IPV6_LEAVE_GROUP, (*byte)(unsafe.Pointer(&mreq)), int32(unsafe.Sizeof(mreq))))
|
return os.NewSyscallError("setsockopt", syscall.Setsockopt(fd, ianaProtocolIPv6, sysSockoptLeaveGroup, (*byte)(unsafe.Pointer(&mreq)), int32(sysSizeofMulticastReq)))
|
||||||
}
|
}
|
||||||
|
|
||||||
func setIPv6Checksum(fd syscall.Handle, on bool, offset int) error {
|
func setIPv6Checksum(fd syscall.Handle, on bool, offset int) error {
|
||||||
|
44
Godeps/_workspace/src/code.google.com/p/go.net/ipv6/sockopt_rfc3542_bsd.go
generated
vendored
44
Godeps/_workspace/src/code.google.com/p/go.net/ipv6/sockopt_rfc3542_bsd.go
generated
vendored
@ -1,44 +0,0 @@
|
|||||||
// 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 freebsd netbsd openbsd
|
|
||||||
|
|
||||||
package ipv6
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"syscall"
|
|
||||||
)
|
|
||||||
|
|
||||||
func ipv6PathMTU(fd int) (int, error) {
|
|
||||||
v, err := syscall.GetsockoptIPv6MTUInfo(fd, ianaProtocolIPv6, syscall.IPV6_PATHMTU)
|
|
||||||
if err != nil {
|
|
||||||
return 0, os.NewSyscallError("getsockopt", err)
|
|
||||||
}
|
|
||||||
return int(v.Mtu), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func ipv6ReceivePathMTU(fd int) (bool, error) {
|
|
||||||
v, err := syscall.GetsockoptInt(fd, ianaProtocolIPv6, syscall.IPV6_RECVPATHMTU)
|
|
||||||
if err != nil {
|
|
||||||
return false, os.NewSyscallError("getsockopt", err)
|
|
||||||
}
|
|
||||||
return v == 1, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func setIPv6ReceivePathMTU(fd int, v bool) error {
|
|
||||||
return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolIPv6, syscall.IPV6_RECVPATHMTU, boolint(v)))
|
|
||||||
}
|
|
||||||
|
|
||||||
func ipv6ICMPFilter(fd int) (*ICMPFilter, error) {
|
|
||||||
v, err := syscall.GetsockoptICMPv6Filter(fd, ianaProtocolIPv6ICMP, syscall.ICMP6_FILTER)
|
|
||||||
if err != nil {
|
|
||||||
return nil, os.NewSyscallError("getsockopt", err)
|
|
||||||
}
|
|
||||||
return &ICMPFilter{rawICMPFilter: rawICMPFilter{*v}}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func setIPv6ICMPFilter(fd int, f *ICMPFilter) error {
|
|
||||||
return os.NewSyscallError("setsockopt", syscall.SetsockoptICMPv6Filter(fd, ianaProtocolIPv6ICMP, syscall.ICMP6_FILTER, &f.rawICMPFilter.ICMPv6Filter))
|
|
||||||
}
|
|
42
Godeps/_workspace/src/code.google.com/p/go.net/ipv6/sockopt_rfc3542_linux.go
generated
vendored
42
Godeps/_workspace/src/code.google.com/p/go.net/ipv6/sockopt_rfc3542_linux.go
generated
vendored
@ -1,42 +0,0 @@
|
|||||||
// 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.
|
|
||||||
|
|
||||||
package ipv6
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"syscall"
|
|
||||||
)
|
|
||||||
|
|
||||||
func ipv6PathMTU(fd int) (int, error) {
|
|
||||||
v, err := syscall.GetsockoptIPv6MTUInfo(fd, ianaProtocolIPv6, syscall_IPV6_PATHMTU)
|
|
||||||
if err != nil {
|
|
||||||
return 0, os.NewSyscallError("getsockopt", err)
|
|
||||||
}
|
|
||||||
return int(v.Mtu), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func ipv6ReceivePathMTU(fd int) (bool, error) {
|
|
||||||
v, err := syscall.GetsockoptInt(fd, ianaProtocolIPv6, syscall_IPV6_RECVPATHMTU)
|
|
||||||
if err != nil {
|
|
||||||
return false, os.NewSyscallError("getsockopt", err)
|
|
||||||
}
|
|
||||||
return v == 1, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func setIPv6ReceivePathMTU(fd int, v bool) error {
|
|
||||||
return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolIPv6, syscall_IPV6_RECVPATHMTU, boolint(v)))
|
|
||||||
}
|
|
||||||
|
|
||||||
func ipv6ICMPFilter(fd int) (*ICMPFilter, error) {
|
|
||||||
v, err := syscall.GetsockoptICMPv6Filter(fd, ianaProtocolIPv6ICMP, syscall.ICMPV6_FILTER)
|
|
||||||
if err != nil {
|
|
||||||
return nil, os.NewSyscallError("getsockopt", err)
|
|
||||||
}
|
|
||||||
return &ICMPFilter{rawICMPFilter: rawICMPFilter{*v}}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func setIPv6ICMPFilter(fd int, f *ICMPFilter) error {
|
|
||||||
return os.NewSyscallError("setsockopt", syscall.SetsockoptICMPv6Filter(fd, ianaProtocolIPv6ICMP, syscall.ICMPV6_FILTER, &f.rawICMPFilter.ICMPv6Filter))
|
|
||||||
}
|
|
@ -2,11 +2,11 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package ipv6
|
// +build dragonfly plan9 solaris
|
||||||
|
|
||||||
import "syscall"
|
package ipv6
|
||||||
|
|
||||||
func ipv6PathMTU(fd int) (int, error) {
|
func ipv6PathMTU(fd int) (int, error) {
|
||||||
// TODO(mikio): Implement this
|
// TODO(mikio): Implement this
|
||||||
return 0, syscall.EPLAN9
|
return 0, errOpNoSupport
|
||||||
}
|
}
|
62
Godeps/_workspace/src/code.google.com/p/go.net/ipv6/sockopt_rfc3542_unix.go
generated
vendored
62
Godeps/_workspace/src/code.google.com/p/go.net/ipv6/sockopt_rfc3542_unix.go
generated
vendored
@ -8,41 +8,83 @@ package ipv6
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
"syscall"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ipv6ReceiveTrafficClass(fd int) (bool, error) {
|
func ipv6ReceiveTrafficClass(fd int) (bool, error) {
|
||||||
v, err := syscall.GetsockoptInt(fd, ianaProtocolIPv6, syscall.IPV6_RECVTCLASS)
|
var v int32
|
||||||
if err != nil {
|
l := sysSockoptLen(4)
|
||||||
|
if err := getsockopt(fd, ianaProtocolIPv6, sysSockoptReceiveTrafficClass, uintptr(unsafe.Pointer(&v)), &l); err != nil {
|
||||||
return false, os.NewSyscallError("getsockopt", err)
|
return false, os.NewSyscallError("getsockopt", err)
|
||||||
}
|
}
|
||||||
return v == 1, nil
|
return v == 1, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func setIPv6ReceiveTrafficClass(fd int, v bool) error {
|
func setIPv6ReceiveTrafficClass(fd int, v bool) error {
|
||||||
return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolIPv6, syscall.IPV6_RECVTCLASS, boolint(v)))
|
vv := int32(boolint(v))
|
||||||
|
return os.NewSyscallError("setsockopt", setsockopt(fd, ianaProtocolIPv6, sysSockoptReceiveTrafficClass, uintptr(unsafe.Pointer(&vv)), 4))
|
||||||
}
|
}
|
||||||
|
|
||||||
func ipv6ReceiveHopLimit(fd int) (bool, error) {
|
func ipv6ReceiveHopLimit(fd int) (bool, error) {
|
||||||
v, err := syscall.GetsockoptInt(fd, ianaProtocolIPv6, syscall.IPV6_RECVHOPLIMIT)
|
var v int32
|
||||||
if err != nil {
|
l := sysSockoptLen(4)
|
||||||
|
if err := getsockopt(fd, ianaProtocolIPv6, sysSockoptReceiveHopLimit, uintptr(unsafe.Pointer(&v)), &l); err != nil {
|
||||||
return false, os.NewSyscallError("getsockopt", err)
|
return false, os.NewSyscallError("getsockopt", err)
|
||||||
}
|
}
|
||||||
return v == 1, nil
|
return v == 1, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func setIPv6ReceiveHopLimit(fd int, v bool) error {
|
func setIPv6ReceiveHopLimit(fd int, v bool) error {
|
||||||
return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolIPv6, syscall.IPV6_RECVHOPLIMIT, boolint(v)))
|
vv := int32(boolint(v))
|
||||||
|
return os.NewSyscallError("setsockopt", setsockopt(fd, ianaProtocolIPv6, sysSockoptReceiveHopLimit, uintptr(unsafe.Pointer(&vv)), 4))
|
||||||
}
|
}
|
||||||
|
|
||||||
func ipv6ReceivePacketInfo(fd int) (bool, error) {
|
func ipv6ReceivePacketInfo(fd int) (bool, error) {
|
||||||
v, err := syscall.GetsockoptInt(fd, ianaProtocolIPv6, syscall.IPV6_RECVPKTINFO)
|
var v int32
|
||||||
if err != nil {
|
l := sysSockoptLen(4)
|
||||||
|
if err := getsockopt(fd, ianaProtocolIPv6, sysSockoptReceivePacketInfo, uintptr(unsafe.Pointer(&v)), &l); err != nil {
|
||||||
return false, os.NewSyscallError("getsockopt", err)
|
return false, os.NewSyscallError("getsockopt", err)
|
||||||
}
|
}
|
||||||
return v == 1, nil
|
return v == 1, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func setIPv6ReceivePacketInfo(fd int, v bool) error {
|
func setIPv6ReceivePacketInfo(fd int, v bool) error {
|
||||||
return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolIPv6, syscall.IPV6_RECVPKTINFO, boolint(v)))
|
vv := int32(boolint(v))
|
||||||
|
return os.NewSyscallError("setsockopt", setsockopt(fd, ianaProtocolIPv6, sysSockoptReceivePacketInfo, uintptr(unsafe.Pointer(&vv)), 4))
|
||||||
|
}
|
||||||
|
|
||||||
|
func ipv6PathMTU(fd int) (int, error) {
|
||||||
|
var v sysMTUInfo
|
||||||
|
l := sysSockoptLen(sysSizeofMTUInfo)
|
||||||
|
if err := getsockopt(fd, ianaProtocolIPv6, sysSockoptPathMTU, uintptr(unsafe.Pointer(&v)), &l); err != nil {
|
||||||
|
return 0, os.NewSyscallError("getsockopt", err)
|
||||||
|
}
|
||||||
|
return int(v.MTU), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ipv6ReceivePathMTU(fd int) (bool, error) {
|
||||||
|
var v int32
|
||||||
|
l := sysSockoptLen(4)
|
||||||
|
if err := getsockopt(fd, ianaProtocolIPv6, sysSockoptReceivePathMTU, uintptr(unsafe.Pointer(&v)), &l); err != nil {
|
||||||
|
return false, os.NewSyscallError("getsockopt", err)
|
||||||
|
}
|
||||||
|
return v == 1, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func setIPv6ReceivePathMTU(fd int, v bool) error {
|
||||||
|
vv := int32(boolint(v))
|
||||||
|
return os.NewSyscallError("setsockopt", setsockopt(fd, ianaProtocolIPv6, sysSockoptReceivePathMTU, uintptr(unsafe.Pointer(&vv)), 4))
|
||||||
|
}
|
||||||
|
|
||||||
|
func ipv6ICMPFilter(fd int) (*ICMPFilter, error) {
|
||||||
|
var v ICMPFilter
|
||||||
|
l := sysSockoptLen(sysSizeofICMPFilter)
|
||||||
|
if err := getsockopt(fd, ianaProtocolIPv6ICMP, sysSockoptICMPFilter, uintptr(unsafe.Pointer(&v.sysICMPFilter)), &l); err != nil {
|
||||||
|
return nil, os.NewSyscallError("getsockopt", err)
|
||||||
|
}
|
||||||
|
return &v, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func setIPv6ICMPFilter(fd int, f *ICMPFilter) error {
|
||||||
|
return os.NewSyscallError("setsockopt", setsockopt(fd, ianaProtocolIPv6ICMP, sysSockoptICMPFilter, uintptr(unsafe.Pointer(&f.sysICMPFilter)), sysSizeofICMPFilter))
|
||||||
}
|
}
|
||||||
|
8
Godeps/_workspace/src/code.google.com/p/go.net/ipv6/sockopt_test.go
generated
vendored
8
Godeps/_workspace/src/code.google.com/p/go.net/ipv6/sockopt_test.go
generated
vendored
@ -24,7 +24,7 @@ func init() {
|
|||||||
var condFatalf = func() func(*testing.T, string, ...interface{}) {
|
var condFatalf = func() func(*testing.T, string, ...interface{}) {
|
||||||
// A few APIs are not implemented yet on some platforms.
|
// A few APIs are not implemented yet on some platforms.
|
||||||
switch runtime.GOOS {
|
switch runtime.GOOS {
|
||||||
case "darwin", "plan9", "windows":
|
case "darwin", "dragonfly", "plan9", "solaris", "windows":
|
||||||
return (*testing.T).Logf
|
return (*testing.T).Logf
|
||||||
}
|
}
|
||||||
return (*testing.T).Fatalf
|
return (*testing.T).Fatalf
|
||||||
@ -32,7 +32,7 @@ var condFatalf = func() func(*testing.T, string, ...interface{}) {
|
|||||||
|
|
||||||
func TestConnInitiatorPathMTU(t *testing.T) {
|
func TestConnInitiatorPathMTU(t *testing.T) {
|
||||||
switch runtime.GOOS {
|
switch runtime.GOOS {
|
||||||
case "plan9", "windows":
|
case "dragonfly", "plan9", "solaris", "windows":
|
||||||
t.Skipf("not supported on %q", runtime.GOOS)
|
t.Skipf("not supported on %q", runtime.GOOS)
|
||||||
}
|
}
|
||||||
if !supportsIPv6 {
|
if !supportsIPv6 {
|
||||||
@ -65,7 +65,7 @@ func TestConnInitiatorPathMTU(t *testing.T) {
|
|||||||
|
|
||||||
func TestConnResponderPathMTU(t *testing.T) {
|
func TestConnResponderPathMTU(t *testing.T) {
|
||||||
switch runtime.GOOS {
|
switch runtime.GOOS {
|
||||||
case "plan9", "windows":
|
case "dragonfly", "plan9", "solaris", "windows":
|
||||||
t.Skipf("not supported on %q", runtime.GOOS)
|
t.Skipf("not supported on %q", runtime.GOOS)
|
||||||
}
|
}
|
||||||
if !supportsIPv6 {
|
if !supportsIPv6 {
|
||||||
@ -98,7 +98,7 @@ func TestConnResponderPathMTU(t *testing.T) {
|
|||||||
|
|
||||||
func TestPacketConnChecksum(t *testing.T) {
|
func TestPacketConnChecksum(t *testing.T) {
|
||||||
switch runtime.GOOS {
|
switch runtime.GOOS {
|
||||||
case "plan9", "windows":
|
case "dragonfly", "plan9", "solaris", "windows":
|
||||||
t.Skipf("not supported on %q", runtime.GOOS)
|
t.Skipf("not supported on %q", runtime.GOOS)
|
||||||
}
|
}
|
||||||
if !supportsIPv6 {
|
if !supportsIPv6 {
|
||||||
|
23
Godeps/_workspace/src/code.google.com/p/go.net/ipv6/sys.go
generated
vendored
Normal file
23
Godeps/_workspace/src/code.google.com/p/go.net/ipv6/sys.go
generated
vendored
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
package ipv6
|
||||||
|
|
||||||
|
type sysSockoptLen uint32
|
||||||
|
|
||||||
|
const (
|
||||||
|
sysSizeofPacketInfo = 0x14
|
||||||
|
sysSizeofMulticastReq = 0x14
|
||||||
|
sysSizeofICMPFilter = 0x20
|
||||||
|
)
|
||||||
|
|
||||||
|
type sysPacketInfo struct {
|
||||||
|
IP [16]byte
|
||||||
|
IfIndex uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
type sysMulticastReq struct {
|
||||||
|
IP [16]byte
|
||||||
|
IfIndex uint32
|
||||||
|
}
|
48
Godeps/_workspace/src/code.google.com/p/go.net/ipv6/sys_bsd.go
generated
vendored
Normal file
48
Godeps/_workspace/src/code.google.com/p/go.net/ipv6/sys_bsd.go
generated
vendored
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
// 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 freebsd netbsd openbsd
|
||||||
|
|
||||||
|
package ipv6
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RFC 3493 options
|
||||||
|
const (
|
||||||
|
// See /usr/include/netinet6/in6.h.
|
||||||
|
sysSockoptUnicastHopLimit = 0x4
|
||||||
|
sysSockoptMulticastHopLimit = 0xa
|
||||||
|
sysSockoptMulticastInterface = 0x9
|
||||||
|
sysSockoptMulticastLoopback = 0xb
|
||||||
|
sysSockoptJoinGroup = 0xc
|
||||||
|
sysSockoptLeaveGroup = 0xd
|
||||||
|
)
|
||||||
|
|
||||||
|
// RFC 3542 options
|
||||||
|
const (
|
||||||
|
// See /usr/include/netinet6/in6.h.
|
||||||
|
sysSockoptReceiveTrafficClass = 0x39
|
||||||
|
sysSockoptTrafficClass = 0x3d
|
||||||
|
sysSockoptReceiveHopLimit = 0x25
|
||||||
|
sysSockoptHopLimit = 0x2f
|
||||||
|
sysSockoptReceivePacketInfo = 0x24
|
||||||
|
sysSockoptPacketInfo = 0x2e
|
||||||
|
sysSockoptReceivePathMTU = 0x2b
|
||||||
|
sysSockoptPathMTU = 0x2c
|
||||||
|
sysSockoptNextHop = 0x30
|
||||||
|
sysSockoptChecksum = 0x1a
|
||||||
|
|
||||||
|
// See /usr/include/netinet6/in6.h.
|
||||||
|
sysSockoptICMPFilter = 0x12
|
||||||
|
)
|
||||||
|
|
||||||
|
func setSockaddr(sa *syscall.RawSockaddrInet6, ip net.IP, ifindex int) {
|
||||||
|
sa.Len = syscall.SizeofSockaddrInet6
|
||||||
|
sa.Family = syscall.AF_INET6
|
||||||
|
copy(sa.Addr[:], ip)
|
||||||
|
sa.Scope_id = uint32(ifindex)
|
||||||
|
}
|
54
Godeps/_workspace/src/code.google.com/p/go.net/ipv6/sys_darwin.go
generated
vendored
Normal file
54
Godeps/_workspace/src/code.google.com/p/go.net/ipv6/sys_darwin.go
generated
vendored
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
package ipv6
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RFC 2292 options
|
||||||
|
const (
|
||||||
|
// See /usr/include/netinet6/in6.h.
|
||||||
|
sysSockopt2292HopLimit = 0x14
|
||||||
|
sysSockopt2292PacketInfo = 0x13
|
||||||
|
sysSockopt2292NextHop = 0x15
|
||||||
|
)
|
||||||
|
|
||||||
|
// RFC 3493 options
|
||||||
|
const (
|
||||||
|
// See /usr/include/netinet6/in6.h.
|
||||||
|
sysSockoptUnicastHopLimit = 0x4
|
||||||
|
sysSockoptMulticastHopLimit = 0xa
|
||||||
|
sysSockoptMulticastInterface = 0x9
|
||||||
|
sysSockoptMulticastLoopback = 0xb
|
||||||
|
sysSockoptJoinGroup = 0xc
|
||||||
|
sysSockoptLeaveGroup = 0xd
|
||||||
|
)
|
||||||
|
|
||||||
|
// RFC 3542 options
|
||||||
|
const (
|
||||||
|
// See /usr/include/netinet6/in6.h.
|
||||||
|
sysSockoptReceiveTrafficClass = 0x23
|
||||||
|
sysSockoptTrafficClass = 0x24
|
||||||
|
sysSockoptReceiveHopLimit = 0x25
|
||||||
|
sysSockoptHopLimit = 0x2f
|
||||||
|
sysSockoptReceivePacketInfo = 0x3d
|
||||||
|
sysSockoptPacketInfo = 0x2e
|
||||||
|
sysSockoptReceivePathMTU = 0x2b
|
||||||
|
sysSockoptPathMTU = 0x2c
|
||||||
|
sysSockoptNextHop = 0x30
|
||||||
|
sysSockoptChecksum = 0x1a
|
||||||
|
|
||||||
|
// See /usr/include/netinet6/in6.h.
|
||||||
|
sysSockoptICMPFilter = 0x12
|
||||||
|
)
|
||||||
|
|
||||||
|
func setSockaddr(sa *syscall.RawSockaddrInet6, ip net.IP, ifindex int) {
|
||||||
|
sa.Len = syscall.SizeofSockaddrInet6
|
||||||
|
sa.Family = syscall.AF_INET6
|
||||||
|
copy(sa.Addr[:], ip)
|
||||||
|
sa.Scope_id = uint32(ifindex)
|
||||||
|
}
|
45
Godeps/_workspace/src/code.google.com/p/go.net/ipv6/sys_linux.go
generated
vendored
Normal file
45
Godeps/_workspace/src/code.google.com/p/go.net/ipv6/sys_linux.go
generated
vendored
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
package ipv6
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RFC 3493 options
|
||||||
|
const (
|
||||||
|
// See /usr/include/linux/in6.h.
|
||||||
|
sysSockoptUnicastHopLimit = 0x10
|
||||||
|
sysSockoptMulticastHopLimit = 0x12
|
||||||
|
sysSockoptMulticastInterface = 0x11
|
||||||
|
sysSockoptMulticastLoopback = 0x13
|
||||||
|
sysSockoptJoinGroup = 0x14
|
||||||
|
sysSockoptLeaveGroup = 0x15
|
||||||
|
)
|
||||||
|
|
||||||
|
// RFC 3542 options
|
||||||
|
const (
|
||||||
|
// See /usr/include/linux/ipv6.h,in6.h.
|
||||||
|
sysSockoptReceiveTrafficClass = 0x42
|
||||||
|
sysSockoptTrafficClass = 0x43
|
||||||
|
sysSockoptReceiveHopLimit = 0x33
|
||||||
|
sysSockoptHopLimit = 0x34
|
||||||
|
sysSockoptReceivePacketInfo = 0x31
|
||||||
|
sysSockoptPacketInfo = 0x32
|
||||||
|
sysSockoptReceivePathMTU = 0x3c
|
||||||
|
sysSockoptPathMTU = 0x3d
|
||||||
|
sysSockoptNextHop = 0x9
|
||||||
|
sysSockoptChecksum = 0x7
|
||||||
|
|
||||||
|
// See /usr/include/linux/icmpv6.h.
|
||||||
|
sysSockoptICMPFilter = 0x1
|
||||||
|
)
|
||||||
|
|
||||||
|
func setSockaddr(sa *syscall.RawSockaddrInet6, ip net.IP, ifindex int) {
|
||||||
|
sa.Family = syscall.AF_INET6
|
||||||
|
copy(sa.Addr[:], ip)
|
||||||
|
sa.Scope_id = uint32(ifindex)
|
||||||
|
}
|
16
Godeps/_workspace/src/code.google.com/p/go.net/ipv6/sys_unix.go
generated
vendored
Normal file
16
Godeps/_workspace/src/code.google.com/p/go.net/ipv6/sys_unix.go
generated
vendored
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
// 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 darwin freebsd linux netbsd openbsd
|
||||||
|
|
||||||
|
package ipv6
|
||||||
|
|
||||||
|
import "syscall"
|
||||||
|
|
||||||
|
const sysSizeofMTUInfo = 0x20
|
||||||
|
|
||||||
|
type sysMTUInfo struct {
|
||||||
|
Addr syscall.RawSockaddrInet6
|
||||||
|
MTU uint32
|
||||||
|
}
|
33
Godeps/_workspace/src/code.google.com/p/go.net/ipv6/sys_windows.go
generated
vendored
Normal file
33
Godeps/_workspace/src/code.google.com/p/go.net/ipv6/sys_windows.go
generated
vendored
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
package ipv6
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RFC 3493 options
|
||||||
|
const (
|
||||||
|
// See ws2tcpip.h.
|
||||||
|
sysSockoptUnicastHopLimit = 0x4
|
||||||
|
sysSockoptMulticastHopLimit = 0xa
|
||||||
|
sysSockoptMulticastInterface = 0x9
|
||||||
|
sysSockoptMulticastLoopback = 0xb
|
||||||
|
sysSockoptJoinGroup = 0xc
|
||||||
|
sysSockoptLeaveGroup = 0xd
|
||||||
|
)
|
||||||
|
|
||||||
|
// RFC 3542 options
|
||||||
|
const (
|
||||||
|
// See ws2tcpip.h.
|
||||||
|
sysSockoptPacketInfo = 0x13
|
||||||
|
)
|
||||||
|
|
||||||
|
func setSockaddr(sa *syscall.RawSockaddrInet6, ip net.IP, ifindex int) {
|
||||||
|
sa.Family = syscall.AF_INET6
|
||||||
|
copy(sa.Addr[:], ip)
|
||||||
|
sa.Scope_id = uint32(ifindex)
|
||||||
|
}
|
42
Godeps/_workspace/src/code.google.com/p/go.net/ipv6/syscall_linux_386.go
generated
vendored
Normal file
42
Godeps/_workspace/src/code.google.com/p/go.net/ipv6/syscall_linux_386.go
generated
vendored
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
// Copyright 2009 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.
|
||||||
|
|
||||||
|
// This code is a duplicate of syscall/syscall_linux_386.go with small
|
||||||
|
// modifications.
|
||||||
|
|
||||||
|
package ipv6
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// On x86 Linux, all the socket calls go through an extra indirection,
|
||||||
|
// I think because the 5-register system call interface can't handle
|
||||||
|
// the 6-argument calls like sendto and recvfrom. Instead the
|
||||||
|
// arguments to the underlying system call are the number below and a
|
||||||
|
// pointer to an array of uintptr. We hide the pointer in the
|
||||||
|
// socketcall assembly to avoid allocation on every system call.
|
||||||
|
|
||||||
|
const (
|
||||||
|
// See /usr/include/linux/net.h.
|
||||||
|
_SETSOCKOPT = 14
|
||||||
|
_GETSOCKOPT = 15
|
||||||
|
)
|
||||||
|
|
||||||
|
var socketcall func(call int, a0, a1, a2, a3, a4, a5 uintptr) (int, syscall.Errno)
|
||||||
|
|
||||||
|
func getsockopt(fd int, level int, name int, v uintptr, l *sysSockoptLen) error {
|
||||||
|
if _, errno := socketcall(_GETSOCKOPT, uintptr(fd), uintptr(level), uintptr(name), uintptr(v), uintptr(unsafe.Pointer(l)), 0); errno != 0 {
|
||||||
|
return error(errno)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func setsockopt(fd int, level int, name int, v uintptr, l uintptr) error {
|
||||||
|
if _, errno := socketcall(_SETSOCKOPT, uintptr(fd), uintptr(level), uintptr(name), v, l, 0); errno != 0 {
|
||||||
|
return error(errno)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
56
Godeps/_workspace/src/code.google.com/p/go.net/ipv6/syscall_linux_386.s
generated
vendored
Normal file
56
Godeps/_workspace/src/code.google.com/p/go.net/ipv6/syscall_linux_386.s
generated
vendored
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
// Copyright 2009 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.
|
||||||
|
|
||||||
|
// This code is a duplicate of syscall/syscall_linux_386.s with small
|
||||||
|
// modifications.
|
||||||
|
|
||||||
|
#define SYS_SOCKETCALL 102 // from zsysnum_linux_386.go
|
||||||
|
|
||||||
|
// func socketcallnosplit7(call int, a0, a1, a2, a3, a4, a5 uintptr) (n int, errno int)
|
||||||
|
// Kernel interface gets call sub-number and pointer to a0 for Go 1.1.
|
||||||
|
TEXT ·socketcallnosplit7(SB),7,$0
|
||||||
|
CALL runtime·entersyscall(SB)
|
||||||
|
MOVL $SYS_SOCKETCALL, AX // syscall entry
|
||||||
|
MOVL 4(SP), BX // socket call number
|
||||||
|
LEAL 8(SP), CX // pointer to call arguments
|
||||||
|
MOVL $0, DX
|
||||||
|
MOVL $0, SI
|
||||||
|
MOVL $0, DI
|
||||||
|
CALL *runtime·_vdso(SB)
|
||||||
|
CMPL AX, $0xfffff001
|
||||||
|
JLS ok1
|
||||||
|
MOVL $-1, 32(SP) // n
|
||||||
|
NEGL AX
|
||||||
|
MOVL AX, 36(SP) // errno
|
||||||
|
CALL runtime·exitsyscall(SB)
|
||||||
|
RET
|
||||||
|
ok1:
|
||||||
|
MOVL AX, 32(SP) // n
|
||||||
|
MOVL $0, 36(SP) // errno
|
||||||
|
CALL runtime·exitsyscall(SB)
|
||||||
|
RET
|
||||||
|
|
||||||
|
// func socketcallnosplit4(call int, a0, a1, a2, a3, a4, a5 uintptr) (n int, errno int)
|
||||||
|
// Kernel interface gets call sub-number and pointer to a0 for Go 1.2.
|
||||||
|
TEXT ·socketcallnosplit4(SB),4,$0-40
|
||||||
|
CALL runtime·entersyscall(SB)
|
||||||
|
MOVL $SYS_SOCKETCALL, AX // syscall entry
|
||||||
|
MOVL 4(SP), BX // socket call number
|
||||||
|
LEAL 8(SP), CX // pointer to call arguments
|
||||||
|
MOVL $0, DX
|
||||||
|
MOVL $0, SI
|
||||||
|
MOVL $0, DI
|
||||||
|
CALL *runtime·_vdso(SB)
|
||||||
|
CMPL AX, $0xfffff001
|
||||||
|
JLS ok2
|
||||||
|
MOVL $-1, 32(SP) // n
|
||||||
|
NEGL AX
|
||||||
|
MOVL AX, 36(SP) // errno
|
||||||
|
CALL runtime·exitsyscall(SB)
|
||||||
|
RET
|
||||||
|
ok2:
|
||||||
|
MOVL AX, 32(SP) // n
|
||||||
|
MOVL $0, 36(SP) // errno
|
||||||
|
CALL runtime·exitsyscall(SB)
|
||||||
|
RET
|
15
Godeps/_workspace/src/code.google.com/p/go.net/ipv6/syscall_nosplit4_linux_386.go
generated
vendored
Normal file
15
Godeps/_workspace/src/code.google.com/p/go.net/ipv6/syscall_nosplit4_linux_386.go
generated
vendored
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
// 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 go1.2
|
||||||
|
|
||||||
|
package ipv6
|
||||||
|
|
||||||
|
import "syscall"
|
||||||
|
|
||||||
|
func socketcallnosplit4(call int, a0, a1, a2, a3, a4, a5 uintptr) (int, syscall.Errno)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
socketcall = socketcallnosplit4
|
||||||
|
}
|
15
Godeps/_workspace/src/code.google.com/p/go.net/ipv6/syscall_nosplit7_linux_386.go
generated
vendored
Normal file
15
Godeps/_workspace/src/code.google.com/p/go.net/ipv6/syscall_nosplit7_linux_386.go
generated
vendored
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
// 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 go1.1,!go1.2
|
||||||
|
|
||||||
|
package ipv6
|
||||||
|
|
||||||
|
import "syscall"
|
||||||
|
|
||||||
|
func socketcallnosplit7(call int, a0, a1, a2, a3, a4, a5 uintptr) (int, syscall.Errno)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
socketcall = socketcallnosplit7
|
||||||
|
}
|
26
Godeps/_workspace/src/code.google.com/p/go.net/ipv6/syscall_unix.go
generated
vendored
Normal file
26
Godeps/_workspace/src/code.google.com/p/go.net/ipv6/syscall_unix.go
generated
vendored
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
// 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 darwin freebsd linux,amd64 linux,arm netbsd openbsd
|
||||||
|
|
||||||
|
package ipv6
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getsockopt(fd int, level, name int, v uintptr, l *sysSockoptLen) error {
|
||||||
|
if _, _, errno := syscall.Syscall6(syscall.SYS_GETSOCKOPT, uintptr(fd), uintptr(level), uintptr(name), uintptr(v), uintptr(unsafe.Pointer(l)), 0); errno != 0 {
|
||||||
|
return error(errno)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func setsockopt(fd int, level int, name int, v uintptr, l uintptr) error {
|
||||||
|
if _, _, errno := syscall.Syscall6(syscall.SYS_SETSOCKOPT, uintptr(fd), uintptr(level), uintptr(name), uintptr(v), uintptr(l), 0); errno != 0 {
|
||||||
|
return error(errno)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
149
Godeps/_workspace/src/code.google.com/p/go.net/ipv6/unicast_test.go
generated
vendored
149
Godeps/_workspace/src/code.google.com/p/go.net/ipv6/unicast_test.go
generated
vendored
@ -5,89 +5,18 @@
|
|||||||
package ipv6_test
|
package ipv6_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"code.google.com/p/go.net/ipv6"
|
"code.google.com/p/go.net/ipv6"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func benchmarkUDPListener() (net.PacketConn, net.Addr, error) {
|
|
||||||
c, err := net.ListenPacket("udp6", "[::1]:0")
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
dst, err := net.ResolveUDPAddr("udp6", c.LocalAddr().String())
|
|
||||||
if err != nil {
|
|
||||||
c.Close()
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
return c, dst, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkReadWriteNetUDP(b *testing.B) {
|
|
||||||
c, dst, err := benchmarkUDPListener()
|
|
||||||
if err != nil {
|
|
||||||
b.Fatalf("benchmarkUDPListener failed: %v", err)
|
|
||||||
}
|
|
||||||
defer c.Close()
|
|
||||||
|
|
||||||
wb, rb := []byte("HELLO-R-U-THERE"), make([]byte, 128)
|
|
||||||
b.ResetTimer()
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
benchmarkReadWriteNetUDP(b, c, wb, rb, dst)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func benchmarkReadWriteNetUDP(b *testing.B, c net.PacketConn, wb, rb []byte, dst net.Addr) {
|
|
||||||
if _, err := c.WriteTo(wb, dst); err != nil {
|
|
||||||
b.Fatalf("net.PacketConn.WriteTo failed: %v", err)
|
|
||||||
}
|
|
||||||
if _, _, err := c.ReadFrom(rb); err != nil {
|
|
||||||
b.Fatalf("net.PacketConn.ReadFrom failed: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkReadWriteIPv6UDP(b *testing.B) {
|
|
||||||
c, dst, err := benchmarkUDPListener()
|
|
||||||
if err != nil {
|
|
||||||
b.Fatalf("benchmarkUDPListener failed: %v", err)
|
|
||||||
}
|
|
||||||
defer c.Close()
|
|
||||||
|
|
||||||
p := ipv6.NewPacketConn(c)
|
|
||||||
cf := ipv6.FlagTrafficClass | ipv6.FlagHopLimit | ipv6.FlagInterface | ipv6.FlagPathMTU
|
|
||||||
if err := p.SetControlMessage(cf, true); err != nil {
|
|
||||||
b.Fatalf("ipv6.PacketConn.SetControlMessage failed: %v", err)
|
|
||||||
}
|
|
||||||
ifi := loopbackInterface()
|
|
||||||
|
|
||||||
wb, rb := []byte("HELLO-R-U-THERE"), make([]byte, 128)
|
|
||||||
b.ResetTimer()
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
benchmarkReadWriteIPv6UDP(b, p, wb, rb, dst, ifi)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func benchmarkReadWriteIPv6UDP(b *testing.B, p *ipv6.PacketConn, wb, rb []byte, dst net.Addr, ifi *net.Interface) {
|
|
||||||
cm := ipv6.ControlMessage{
|
|
||||||
TrafficClass: DiffServAF11 | CongestionExperienced,
|
|
||||||
HopLimit: 1,
|
|
||||||
}
|
|
||||||
if ifi != nil {
|
|
||||||
cm.IfIndex = ifi.Index
|
|
||||||
}
|
|
||||||
if _, err := p.WriteTo(wb, &cm, dst); err != nil {
|
|
||||||
b.Fatalf("ipv6.PacketConn.WriteTo failed: %v", err)
|
|
||||||
}
|
|
||||||
if _, _, _, err := p.ReadFrom(rb); err != nil {
|
|
||||||
b.Fatalf("ipv6.PacketConn.ReadFrom failed: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestPacketConnReadWriteUnicastUDP(t *testing.T) {
|
func TestPacketConnReadWriteUnicastUDP(t *testing.T) {
|
||||||
switch runtime.GOOS {
|
switch runtime.GOOS {
|
||||||
case "plan9", "windows":
|
case "dragonfly", "plan9", "solaris", "windows":
|
||||||
t.Skipf("not supported on %q", runtime.GOOS)
|
t.Skipf("not supported on %q", runtime.GOOS)
|
||||||
}
|
}
|
||||||
if !supportsIPv6 {
|
if !supportsIPv6 {
|
||||||
@ -99,33 +28,47 @@ func TestPacketConnReadWriteUnicastUDP(t *testing.T) {
|
|||||||
t.Fatalf("net.ListenPacket failed: %v", err)
|
t.Fatalf("net.ListenPacket failed: %v", err)
|
||||||
}
|
}
|
||||||
defer c.Close()
|
defer c.Close()
|
||||||
|
p := ipv6.NewPacketConn(c)
|
||||||
|
defer p.Close()
|
||||||
|
|
||||||
dst, err := net.ResolveUDPAddr("udp6", c.LocalAddr().String())
|
dst, err := net.ResolveUDPAddr("udp6", c.LocalAddr().String())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("net.ResolveUDPAddr failed: %v", err)
|
t.Fatalf("net.ResolveUDPAddr failed: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
p := ipv6.NewPacketConn(c)
|
|
||||||
cm := ipv6.ControlMessage{
|
cm := ipv6.ControlMessage{
|
||||||
TrafficClass: DiffServAF11 | CongestionExperienced,
|
TrafficClass: DiffServAF11 | CongestionExperienced,
|
||||||
|
Src: net.IPv6loopback,
|
||||||
|
Dst: net.IPv6loopback,
|
||||||
}
|
}
|
||||||
cf := ipv6.FlagTrafficClass | ipv6.FlagHopLimit | ipv6.FlagInterface | ipv6.FlagPathMTU
|
cf := ipv6.FlagTrafficClass | ipv6.FlagHopLimit | ipv6.FlagSrc | ipv6.FlagDst | ipv6.FlagInterface | ipv6.FlagPathMTU
|
||||||
ifi := loopbackInterface()
|
ifi := loopbackInterface()
|
||||||
if ifi != nil {
|
if ifi != nil {
|
||||||
cm.IfIndex = ifi.Index
|
cm.IfIndex = ifi.Index
|
||||||
}
|
}
|
||||||
|
wb := []byte("HELLO-R-U-THERE")
|
||||||
|
|
||||||
for i, toggle := range []bool{true, false, true} {
|
for i, toggle := range []bool{true, false, true} {
|
||||||
if err := p.SetControlMessage(cf, toggle); err != nil {
|
if err := p.SetControlMessage(cf, toggle); err != nil {
|
||||||
t.Fatalf("ipv6.PacketConn.SetControlMessage failed: %v", err)
|
t.Fatalf("ipv6.PacketConn.SetControlMessage failed: %v", err)
|
||||||
}
|
}
|
||||||
cm.HopLimit = i + 1
|
cm.HopLimit = i + 1
|
||||||
if _, err := p.WriteTo([]byte("HELLO-R-U-THERE"), &cm, dst); err != nil {
|
if err := p.SetWriteDeadline(time.Now().Add(100 * time.Millisecond)); err != nil {
|
||||||
t.Fatalf("ipv6.PacketConn.WriteTo failed: %v", err)
|
t.Fatalf("ipv6.PacketConn.SetWriteDeadline failed: %v", err)
|
||||||
}
|
}
|
||||||
b := make([]byte, 128)
|
if n, err := p.WriteTo(wb, &cm, dst); err != nil {
|
||||||
if _, cm, _, err := p.ReadFrom(b); err != nil {
|
t.Fatalf("ipv6.PacketConn.WriteTo failed: %v", err)
|
||||||
|
} else if n != len(wb) {
|
||||||
|
t.Fatalf("ipv6.PacketConn.WriteTo failed: short write: %v", n)
|
||||||
|
}
|
||||||
|
rb := make([]byte, 128)
|
||||||
|
if err := p.SetReadDeadline(time.Now().Add(100 * time.Millisecond)); err != nil {
|
||||||
|
t.Fatalf("ipv6.PacketConn.SetReadDeadline failed: %v", err)
|
||||||
|
}
|
||||||
|
if n, cm, _, err := p.ReadFrom(rb); err != nil {
|
||||||
t.Fatalf("ipv6.PacketConn.ReadFrom failed: %v", err)
|
t.Fatalf("ipv6.PacketConn.ReadFrom failed: %v", err)
|
||||||
|
} else if !bytes.Equal(rb[:n], wb) {
|
||||||
|
t.Fatalf("got %v; expected %v", rb[:n], wb)
|
||||||
} else {
|
} else {
|
||||||
t.Logf("rcvd cmsg: %v", cm)
|
t.Logf("rcvd cmsg: %v", cm)
|
||||||
}
|
}
|
||||||
@ -134,7 +77,7 @@ func TestPacketConnReadWriteUnicastUDP(t *testing.T) {
|
|||||||
|
|
||||||
func TestPacketConnReadWriteUnicastICMP(t *testing.T) {
|
func TestPacketConnReadWriteUnicastICMP(t *testing.T) {
|
||||||
switch runtime.GOOS {
|
switch runtime.GOOS {
|
||||||
case "plan9", "windows":
|
case "dragonfly", "plan9", "solaris", "windows":
|
||||||
t.Skipf("not supported on %q", runtime.GOOS)
|
t.Skipf("not supported on %q", runtime.GOOS)
|
||||||
}
|
}
|
||||||
if !supportsIPv6 {
|
if !supportsIPv6 {
|
||||||
@ -149,15 +92,21 @@ func TestPacketConnReadWriteUnicastICMP(t *testing.T) {
|
|||||||
t.Fatalf("net.ListenPacket failed: %v", err)
|
t.Fatalf("net.ListenPacket failed: %v", err)
|
||||||
}
|
}
|
||||||
defer c.Close()
|
defer c.Close()
|
||||||
|
p := ipv6.NewPacketConn(c)
|
||||||
|
defer p.Close()
|
||||||
|
|
||||||
dst, err := net.ResolveIPAddr("ip6", "::1")
|
dst, err := net.ResolveIPAddr("ip6", "::1")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("net.ResolveIPAddr failed: %v", err)
|
t.Fatalf("net.ResolveIPAddr failed: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
p := ipv6.NewPacketConn(c)
|
pshicmp := ipv6PseudoHeader(c.LocalAddr().(*net.IPAddr).IP, dst.IP, ianaProtocolIPv6ICMP)
|
||||||
cm := ipv6.ControlMessage{TrafficClass: DiffServAF11 | CongestionExperienced}
|
cm := ipv6.ControlMessage{
|
||||||
cf := ipv6.FlagTrafficClass | ipv6.FlagHopLimit | ipv6.FlagInterface | ipv6.FlagPathMTU
|
TrafficClass: DiffServAF11 | CongestionExperienced,
|
||||||
|
Src: net.IPv6loopback,
|
||||||
|
Dst: net.IPv6loopback,
|
||||||
|
}
|
||||||
|
cf := ipv6.FlagTrafficClass | ipv6.FlagHopLimit | ipv6.FlagSrc | ipv6.FlagDst | ipv6.FlagInterface | ipv6.FlagPathMTU
|
||||||
ifi := loopbackInterface()
|
ifi := loopbackInterface()
|
||||||
if ifi != nil {
|
if ifi != nil {
|
||||||
cm.IfIndex = ifi.Index
|
cm.IfIndex = ifi.Index
|
||||||
@ -170,14 +119,26 @@ func TestPacketConnReadWriteUnicastICMP(t *testing.T) {
|
|||||||
t.Fatalf("ipv6.PacketConn.SetICMPFilter failed: %v", err)
|
t.Fatalf("ipv6.PacketConn.SetICMPFilter failed: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var psh []byte
|
||||||
for i, toggle := range []bool{true, false, true} {
|
for i, toggle := range []bool{true, false, true} {
|
||||||
|
if toggle {
|
||||||
|
psh = nil
|
||||||
|
if err := p.SetChecksum(true, 2); err != nil {
|
||||||
|
t.Fatalf("ipv6.PacketConn.SetChecksum failed: %v", err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
psh = pshicmp
|
||||||
|
// Some platforms never allow to disable the
|
||||||
|
// kernel checksum processing.
|
||||||
|
p.SetChecksum(false, -1)
|
||||||
|
}
|
||||||
wb, err := (&icmpMessage{
|
wb, err := (&icmpMessage{
|
||||||
Type: ipv6.ICMPTypeEchoRequest, Code: 0,
|
Type: ipv6.ICMPTypeEchoRequest, Code: 0,
|
||||||
Body: &icmpEcho{
|
Body: &icmpEcho{
|
||||||
ID: os.Getpid() & 0xffff, Seq: i + 1,
|
ID: os.Getpid() & 0xffff, Seq: i + 1,
|
||||||
Data: []byte("HELLO-R-U-THERE"),
|
Data: []byte("HELLO-R-U-THERE"),
|
||||||
},
|
},
|
||||||
}).Marshal()
|
}).Marshal(psh)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("icmpMessage.Marshal failed: %v", err)
|
t.Fatalf("icmpMessage.Marshal failed: %v", err)
|
||||||
}
|
}
|
||||||
@ -185,15 +146,23 @@ func TestPacketConnReadWriteUnicastICMP(t *testing.T) {
|
|||||||
t.Fatalf("ipv6.PacketConn.SetControlMessage failed: %v", err)
|
t.Fatalf("ipv6.PacketConn.SetControlMessage failed: %v", err)
|
||||||
}
|
}
|
||||||
cm.HopLimit = i + 1
|
cm.HopLimit = i + 1
|
||||||
if _, err := p.WriteTo(wb, &cm, dst); err != nil {
|
if err := p.SetWriteDeadline(time.Now().Add(100 * time.Millisecond)); err != nil {
|
||||||
t.Fatalf("ipv6.PacketConn.WriteTo failed: %v", err)
|
t.Fatalf("ipv6.PacketConn.SetWriteDeadline failed: %v", err)
|
||||||
}
|
}
|
||||||
b := make([]byte, 128)
|
if n, err := p.WriteTo(wb, &cm, dst); err != nil {
|
||||||
if n, cm, _, err := p.ReadFrom(b); err != nil {
|
t.Fatalf("ipv6.PacketConn.WriteTo failed: %v", err)
|
||||||
|
} else if n != len(wb) {
|
||||||
|
t.Fatalf("ipv6.PacketConn.WriteTo failed: short write: %v", n)
|
||||||
|
}
|
||||||
|
rb := make([]byte, 128)
|
||||||
|
if err := p.SetReadDeadline(time.Now().Add(100 * time.Millisecond)); err != nil {
|
||||||
|
t.Fatalf("ipv6.PacketConn.SetReadDeadline failed: %v", err)
|
||||||
|
}
|
||||||
|
if n, cm, _, err := p.ReadFrom(rb); err != nil {
|
||||||
t.Fatalf("ipv6.PacketConn.ReadFrom failed: %v", err)
|
t.Fatalf("ipv6.PacketConn.ReadFrom failed: %v", err)
|
||||||
} else {
|
} else {
|
||||||
t.Logf("rcvd cmsg: %v", cm)
|
t.Logf("rcvd cmsg: %v", cm)
|
||||||
if m, err := parseICMPMessage(b[:n]); err != nil {
|
if m, err := parseICMPMessage(rb[:n]); err != nil {
|
||||||
t.Fatalf("parseICMPMessage failed: %v", err)
|
t.Fatalf("parseICMPMessage failed: %v", err)
|
||||||
} else if m.Type != ipv6.ICMPTypeEchoReply || m.Code != 0 {
|
} else if m.Type != ipv6.ICMPTypeEchoReply || m.Code != 0 {
|
||||||
t.Fatalf("got type=%v, code=%v; expected type=%v, code=%v", m.Type, m.Code, ipv6.ICMPTypeEchoReply, 0)
|
t.Fatalf("got type=%v, code=%v; expected type=%v, code=%v", m.Type, m.Code, ipv6.ICMPTypeEchoReply, 0)
|
||||||
|
4
Godeps/_workspace/src/code.google.com/p/go.net/ipv6/unicastsockopt_test.go
generated
vendored
4
Godeps/_workspace/src/code.google.com/p/go.net/ipv6/unicastsockopt_test.go
generated
vendored
@ -14,7 +14,7 @@ import (
|
|||||||
|
|
||||||
func TestConnUnicastSocketOptions(t *testing.T) {
|
func TestConnUnicastSocketOptions(t *testing.T) {
|
||||||
switch runtime.GOOS {
|
switch runtime.GOOS {
|
||||||
case "plan9", "windows":
|
case "dragonfly", "plan9", "solaris", "windows":
|
||||||
t.Skipf("not supported on %q", runtime.GOOS)
|
t.Skipf("not supported on %q", runtime.GOOS)
|
||||||
}
|
}
|
||||||
if !supportsIPv6 {
|
if !supportsIPv6 {
|
||||||
@ -50,7 +50,7 @@ var packetConnUnicastSocketOptionTests = []struct {
|
|||||||
|
|
||||||
func TestPacketConnUnicastSocketOptions(t *testing.T) {
|
func TestPacketConnUnicastSocketOptions(t *testing.T) {
|
||||||
switch runtime.GOOS {
|
switch runtime.GOOS {
|
||||||
case "plan9", "windows":
|
case "dragonfly", "plan9", "solaris", "windows":
|
||||||
t.Skipf("not supported on %q", runtime.GOOS)
|
t.Skipf("not supported on %q", runtime.GOOS)
|
||||||
}
|
}
|
||||||
if !supportsIPv6 {
|
if !supportsIPv6 {
|
||||||
|
15
Godeps/_workspace/src/github.com/calmh/ini/ini.go
generated
vendored
15
Godeps/_workspace/src/github.com/calmh/ini/ini.go
generated
vendored
@ -218,3 +218,18 @@ func (c *Config) Set(sectionName, key, value string) {
|
|||||||
options: []option{{key, value}},
|
options: []option{{key, value}},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Delete removes the option from the specified section.
|
||||||
|
func (c *Config) Delete(section, key string) {
|
||||||
|
for sn, sect := range c.sections {
|
||||||
|
if sect.name == section {
|
||||||
|
for i, opt := range sect.options {
|
||||||
|
if opt.name == key {
|
||||||
|
c.sections[sn].options = append(sect.options[:i], sect.options[i+1:]...)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
38
Godeps/_workspace/src/github.com/calmh/ini/ini_test.go
generated
vendored
38
Godeps/_workspace/src/github.com/calmh/ini/ini_test.go
generated
vendored
@ -2,9 +2,10 @@ package ini_test
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"github.com/calmh/ini"
|
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/calmh/ini"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestParseValues(t *testing.T) {
|
func TestParseValues(t *testing.T) {
|
||||||
@ -136,6 +137,41 @@ baz2=quux2
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDelete(t *testing.T) {
|
||||||
|
buf := bytes.NewBufferString("[general]\nfoo=bar\nfoo2=bar2\nfoo3=baz\n")
|
||||||
|
cfg := ini.Parse(buf)
|
||||||
|
cfg.Delete("general", "foo")
|
||||||
|
out := new(bytes.Buffer)
|
||||||
|
cfg.Write(out)
|
||||||
|
correct := "[general]\nfoo2=bar2\nfoo3=baz\n\n"
|
||||||
|
|
||||||
|
if s := out.String(); s != correct {
|
||||||
|
t.Errorf("Incorrect INI after delete:\n%s", s)
|
||||||
|
}
|
||||||
|
|
||||||
|
buf = bytes.NewBufferString("[general]\nfoo=bar\nfoo2=bar2\nfoo3=baz\n")
|
||||||
|
cfg = ini.Parse(buf)
|
||||||
|
cfg.Delete("general", "foo2")
|
||||||
|
out = new(bytes.Buffer)
|
||||||
|
cfg.Write(out)
|
||||||
|
correct = "[general]\nfoo=bar\nfoo3=baz\n\n"
|
||||||
|
|
||||||
|
if s := out.String(); s != correct {
|
||||||
|
t.Errorf("Incorrect INI after delete:\n%s", s)
|
||||||
|
}
|
||||||
|
|
||||||
|
buf = bytes.NewBufferString("[general]\nfoo=bar\nfoo2=bar2\nfoo3=baz\n")
|
||||||
|
cfg = ini.Parse(buf)
|
||||||
|
cfg.Delete("general", "foo3")
|
||||||
|
out = new(bytes.Buffer)
|
||||||
|
cfg.Write(out)
|
||||||
|
correct = "[general]\nfoo=bar\nfoo2=bar2\n\n"
|
||||||
|
|
||||||
|
if s := out.String(); s != correct {
|
||||||
|
t.Errorf("Incorrect INI after delete:\n%s", s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestSetManyEquals(t *testing.T) {
|
func TestSetManyEquals(t *testing.T) {
|
||||||
buf := bytes.NewBufferString("[general]\nfoo=bar==\nfoo2=bar2==\n")
|
buf := bytes.NewBufferString("[general]\nfoo=bar==\nfoo2=bar2==\n")
|
||||||
cfg := ini.Parse(buf)
|
cfg := ini.Parse(buf)
|
||||||
|
50
Godeps/_workspace/src/github.com/codegangsta/inject/inject.go
generated
vendored
50
Godeps/_workspace/src/github.com/codegangsta/inject/inject.go
generated
vendored
@ -1,3 +1,4 @@
|
|||||||
|
// Package inject provides utilities for mapping and injecting dependencies in various ways.
|
||||||
package inject
|
package inject
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -5,24 +6,49 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Injector represents an interface for mapping and injecting dependencies into structs
|
||||||
|
// and function arguments.
|
||||||
type Injector interface {
|
type Injector interface {
|
||||||
Applicator
|
Applicator
|
||||||
Invoker
|
Invoker
|
||||||
TypeMapper
|
TypeMapper
|
||||||
|
// SetParent sets the parent of the injector. If the injector cannot find a
|
||||||
|
// dependency in its Type map it will check its parent before returning an
|
||||||
|
// error.
|
||||||
SetParent(Injector)
|
SetParent(Injector)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Applicator represents an interface for mapping dependencies to a struct.
|
||||||
type Applicator interface {
|
type Applicator interface {
|
||||||
|
// Maps dependencies in the Type map to each field in the struct
|
||||||
|
// that is tagged with 'inject'. Returns an error if the injection
|
||||||
|
// fails.
|
||||||
Apply(interface{}) error
|
Apply(interface{}) error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Invoker represents an interface for calling functions via reflection.
|
||||||
type Invoker interface {
|
type Invoker interface {
|
||||||
|
// Invoke attempts to call the interface{} provided as a function,
|
||||||
|
// providing dependencies for function arguments based on Type. Returns
|
||||||
|
// a slice of reflect.Value representing the returned values of the function.
|
||||||
|
// Returns an error if the injection fails.
|
||||||
Invoke(interface{}) ([]reflect.Value, error)
|
Invoke(interface{}) ([]reflect.Value, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TypeMapper represents an interface for mapping interface{} values based on type.
|
||||||
type TypeMapper interface {
|
type TypeMapper interface {
|
||||||
|
// Maps the interface{} value based on its immediate type from reflect.TypeOf.
|
||||||
Map(interface{}) TypeMapper
|
Map(interface{}) TypeMapper
|
||||||
|
// Maps the interface{} value based on the pointer of an Interface provided.
|
||||||
|
// This is really only useful for mapping a value as an interface, as interfaces
|
||||||
|
// cannot at this time be referenced directly without a pointer.
|
||||||
MapTo(interface{}, interface{}) TypeMapper
|
MapTo(interface{}, interface{}) TypeMapper
|
||||||
|
// Provides a possibility to directly insert a mapping based on type and value.
|
||||||
|
// This makes it possible to directly map type arguments not possible to instantiate
|
||||||
|
// with reflect like unidirectional channels.
|
||||||
|
Set(reflect.Type, reflect.Value) TypeMapper
|
||||||
|
// Returns the Value that is mapped to the current type. Returns a zeroed Value if
|
||||||
|
// the Type has not been mapped.
|
||||||
Get(reflect.Type) reflect.Value
|
Get(reflect.Type) reflect.Value
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,6 +57,8 @@ type injector struct {
|
|||||||
parent Injector
|
parent Injector
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// InterfaceOf dereferences a pointer to an Interface type.
|
||||||
|
// It panics if value is not an pointer to an interface.
|
||||||
func InterfaceOf(value interface{}) reflect.Type {
|
func InterfaceOf(value interface{}) reflect.Type {
|
||||||
t := reflect.TypeOf(value)
|
t := reflect.TypeOf(value)
|
||||||
|
|
||||||
@ -45,16 +73,22 @@ func InterfaceOf(value interface{}) reflect.Type {
|
|||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// New returns a new Injector.
|
||||||
func New() Injector {
|
func New() Injector {
|
||||||
return &injector{
|
return &injector{
|
||||||
values: make(map[reflect.Type]reflect.Value),
|
values: make(map[reflect.Type]reflect.Value),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Invoke attempts to call the interface{} provided as a function,
|
||||||
|
// providing dependencies for function arguments based on Type.
|
||||||
|
// Returns a slice of reflect.Value representing the returned values of the function.
|
||||||
|
// Returns an error if the injection fails.
|
||||||
|
// It panics if f is not a function
|
||||||
func (inj *injector) Invoke(f interface{}) ([]reflect.Value, error) {
|
func (inj *injector) Invoke(f interface{}) ([]reflect.Value, error) {
|
||||||
t := reflect.TypeOf(f)
|
t := reflect.TypeOf(f)
|
||||||
|
|
||||||
var in = make([]reflect.Value, t.NumIn())
|
var in = make([]reflect.Value, t.NumIn()) //Panic if t is not kind of Func
|
||||||
for i := 0; i < t.NumIn(); i++ {
|
for i := 0; i < t.NumIn(); i++ {
|
||||||
argType := t.In(i)
|
argType := t.In(i)
|
||||||
val := inj.Get(argType)
|
val := inj.Get(argType)
|
||||||
@ -68,6 +102,9 @@ func (inj *injector) Invoke(f interface{}) ([]reflect.Value, error) {
|
|||||||
return reflect.ValueOf(f).Call(in), nil
|
return reflect.ValueOf(f).Call(in), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Maps dependencies in the Type map to each field in the struct
|
||||||
|
// that is tagged with 'inject'.
|
||||||
|
// Returns an error if the injection fails.
|
||||||
func (inj *injector) Apply(val interface{}) error {
|
func (inj *injector) Apply(val interface{}) error {
|
||||||
v := reflect.ValueOf(val)
|
v := reflect.ValueOf(val)
|
||||||
|
|
||||||
@ -76,7 +113,7 @@ func (inj *injector) Apply(val interface{}) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if v.Kind() != reflect.Struct {
|
if v.Kind() != reflect.Struct {
|
||||||
return nil
|
return nil // Should not panic here ?
|
||||||
}
|
}
|
||||||
|
|
||||||
t := v.Type()
|
t := v.Type()
|
||||||
@ -99,6 +136,8 @@ func (inj *injector) Apply(val interface{}) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Maps the concrete value of val to its dynamic type using reflect.TypeOf,
|
||||||
|
// It returns the TypeMapper registered in.
|
||||||
func (i *injector) Map(val interface{}) TypeMapper {
|
func (i *injector) Map(val interface{}) TypeMapper {
|
||||||
i.values[reflect.TypeOf(val)] = reflect.ValueOf(val)
|
i.values[reflect.TypeOf(val)] = reflect.ValueOf(val)
|
||||||
return i
|
return i
|
||||||
@ -109,6 +148,13 @@ func (i *injector) MapTo(val interface{}, ifacePtr interface{}) TypeMapper {
|
|||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Maps the given reflect.Type to the given reflect.Value and returns
|
||||||
|
// the Typemapper the mapping has been registered in.
|
||||||
|
func (i *injector) Set(typ reflect.Type, val reflect.Value) TypeMapper {
|
||||||
|
i.values[typ] = val
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
func (i *injector) Get(t reflect.Type) reflect.Value {
|
func (i *injector) Get(t reflect.Type) reflect.Value {
|
||||||
val := i.values[t]
|
val := i.values[t]
|
||||||
if !val.IsValid() && i.parent != nil {
|
if !val.IsValid() && i.parent != nil {
|
||||||
|
34
Godeps/_workspace/src/github.com/codegangsta/inject/inject_test.go
generated
vendored
34
Godeps/_workspace/src/github.com/codegangsta/inject/inject_test.go
generated
vendored
@ -36,10 +36,20 @@ func Test_InjectorInvoke(t *testing.T) {
|
|||||||
injector.Map(dep)
|
injector.Map(dep)
|
||||||
dep2 := "another dep"
|
dep2 := "another dep"
|
||||||
injector.MapTo(dep2, (*SpecialString)(nil))
|
injector.MapTo(dep2, (*SpecialString)(nil))
|
||||||
|
dep3 := make(chan *SpecialString)
|
||||||
_, err := injector.Invoke(func(d1 string, d2 SpecialString) {
|
dep4 := make(chan *SpecialString)
|
||||||
|
typRecv := reflect.ChanOf(reflect.RecvDir, reflect.TypeOf(dep3).Elem())
|
||||||
|
typSend := reflect.ChanOf(reflect.SendDir, reflect.TypeOf(dep4).Elem())
|
||||||
|
injector.Set(typRecv, reflect.ValueOf(dep3))
|
||||||
|
injector.Set(typSend, reflect.ValueOf(dep4))
|
||||||
|
|
||||||
|
_, err := injector.Invoke(func(d1 string, d2 SpecialString, d3 <-chan *SpecialString, d4 chan<- *SpecialString) {
|
||||||
expect(t, d1, dep)
|
expect(t, d1, dep)
|
||||||
expect(t, d2, dep2)
|
expect(t, d2, dep2)
|
||||||
|
expect(t, reflect.TypeOf(d3).Elem(), reflect.TypeOf(dep3).Elem())
|
||||||
|
expect(t, reflect.TypeOf(d4).Elem(), reflect.TypeOf(dep4).Elem())
|
||||||
|
expect(t, reflect.TypeOf(d3).ChanDir(), reflect.RecvDir)
|
||||||
|
expect(t, reflect.TypeOf(d4).ChanDir(), reflect.SendDir)
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(t, err, nil)
|
expect(t, err, nil)
|
||||||
@ -92,6 +102,26 @@ func Test_InterfaceOf(t *testing.T) {
|
|||||||
iType = inject.InterfaceOf((*testing.T)(nil))
|
iType = inject.InterfaceOf((*testing.T)(nil))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Test_InjectorSet(t *testing.T) {
|
||||||
|
injector := inject.New()
|
||||||
|
typ := reflect.TypeOf("string")
|
||||||
|
typSend := reflect.ChanOf(reflect.SendDir, typ)
|
||||||
|
typRecv := reflect.ChanOf(reflect.RecvDir, typ)
|
||||||
|
|
||||||
|
// instantiating unidirectional channels is not possible using reflect
|
||||||
|
// http://golang.org/src/pkg/reflect/value.go?s=60463:60504#L2064
|
||||||
|
chanRecv := reflect.MakeChan(reflect.ChanOf(reflect.BothDir, typ), 0)
|
||||||
|
chanSend := reflect.MakeChan(reflect.ChanOf(reflect.BothDir, typ), 0)
|
||||||
|
|
||||||
|
injector.Set(typSend, chanSend)
|
||||||
|
injector.Set(typRecv, chanRecv)
|
||||||
|
|
||||||
|
expect(t, injector.Get(typSend).IsValid(), true)
|
||||||
|
expect(t, injector.Get(typRecv).IsValid(), true)
|
||||||
|
expect(t, injector.Get(chanSend.Type()).IsValid(), false)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
func Test_InjectorGet(t *testing.T) {
|
func Test_InjectorGet(t *testing.T) {
|
||||||
injector := inject.New()
|
injector := inject.New()
|
||||||
|
|
||||||
|
70
Godeps/_workspace/src/github.com/codegangsta/martini/README.md
generated
vendored
70
Godeps/_workspace/src/github.com/codegangsta/martini/README.md
generated
vendored
@ -1,7 +1,10 @@
|
|||||||
# Martini [![Build Status](https://drone.io/github.com/codegangsta/martini/status.png)](https://drone.io/github.com/codegangsta/martini/latest) [![GoDoc](https://godoc.org/github.com/codegangsta/martini?status.png)](http://godoc.org/github.com/codegangsta/martini)
|
# Martini [![wercker status](https://app.wercker.com/status/174bef7e3c999e103cacfe2770102266 "wercker status")](https://app.wercker.com/project/bykey/174bef7e3c999e103cacfe2770102266) [![GoDoc](https://godoc.org/github.com/codegangsta/martini?status.png)](http://godoc.org/github.com/codegangsta/martini)
|
||||||
|
|
||||||
Martini is a powerful package for quickly writing modular web applications/services in Golang.
|
Martini is a powerful package for quickly writing modular web applications/services in Golang.
|
||||||
|
|
||||||
|
Language Translations: [Simplified Chinese (zh_CN)](translations/README_zh_cn.md)
|
||||||
|
|
||||||
|
|
||||||
## Getting Started
|
## Getting Started
|
||||||
|
|
||||||
After installing Go and setting up your [GOPATH](http://golang.org/doc/code.html#GOPATH), create your first `.go` file. We'll call it `server.go`.
|
After installing Go and setting up your [GOPATH](http://golang.org/doc/code.html#GOPATH), create your first `.go` file. We'll call it `server.go`.
|
||||||
@ -41,7 +44,7 @@ Watch the [Demo Video](http://martini.codegangsta.io/#demo)
|
|||||||
## Features
|
## Features
|
||||||
* Extremely simple to use.
|
* Extremely simple to use.
|
||||||
* Non-intrusive design.
|
* Non-intrusive design.
|
||||||
* Play nice with other Golang packages.
|
* Plays nice with other Golang packages.
|
||||||
* Awesome path matching and routing.
|
* Awesome path matching and routing.
|
||||||
* Modular design - Easy to add functionality, easy to rip stuff out.
|
* Modular design - Easy to add functionality, easy to rip stuff out.
|
||||||
* Lots of good handlers/middlewares to use.
|
* Lots of good handlers/middlewares to use.
|
||||||
@ -49,7 +52,7 @@ Watch the [Demo Video](http://martini.codegangsta.io/#demo)
|
|||||||
* **Fully compatible with the [http.HandlerFunc](http://godoc.org/net/http#HandlerFunc) interface.**
|
* **Fully compatible with the [http.HandlerFunc](http://godoc.org/net/http#HandlerFunc) interface.**
|
||||||
|
|
||||||
## More Middleware
|
## More Middleware
|
||||||
For more middleware and functionality, check out the [martini-contrib](http://github.com/codegangsta/martini-contrib) repository.
|
For more middleware and functionality, check out the repositories in the [martini-contrib](https://github.com/martini-contrib) organization.
|
||||||
|
|
||||||
## Table of Contents
|
## Table of Contents
|
||||||
* [Classic Martini](#classic-martini)
|
* [Classic Martini](#classic-martini)
|
||||||
@ -59,6 +62,7 @@ For more middleware and functionality, check out the [martini-contrib](http://gi
|
|||||||
* [Serving Static Files](#serving-static-files)
|
* [Serving Static Files](#serving-static-files)
|
||||||
* [Middleware Handlers](#middleware-handlers)
|
* [Middleware Handlers](#middleware-handlers)
|
||||||
* [Next()](#next)
|
* [Next()](#next)
|
||||||
|
* [Martini Env](#martini-env)
|
||||||
* [FAQ](#faq)
|
* [FAQ](#faq)
|
||||||
|
|
||||||
## Classic Martini
|
## Classic Martini
|
||||||
@ -101,7 +105,7 @@ m.Get("/", func() (int, string) {
|
|||||||
#### Service Injection
|
#### Service Injection
|
||||||
Handlers are invoked via reflection. Martini makes use of *Dependency Injection* to resolve dependencies in a Handlers argument list. **This makes Martini completely compatible with golang's `http.HandlerFunc` interface.**
|
Handlers are invoked via reflection. Martini makes use of *Dependency Injection* to resolve dependencies in a Handlers argument list. **This makes Martini completely compatible with golang's `http.HandlerFunc` interface.**
|
||||||
|
|
||||||
If you add an argument to your Handler, Martini will search it's list of services and attempt to resolve the dependency via type assertion:
|
If you add an argument to your Handler, Martini will search its list of services and attempt to resolve the dependency via type assertion:
|
||||||
~~~ go
|
~~~ go
|
||||||
m.Get("/", func(res http.ResponseWriter, req *http.Request) { // res and req are injected by Martini
|
m.Get("/", func(res http.ResponseWriter, req *http.Request) { // res and req are injected by Martini
|
||||||
res.WriteHeader(200) // HTTP 200
|
res.WriteHeader(200) // HTTP 200
|
||||||
@ -173,6 +177,26 @@ m.Get("/secret", authorize, func() {
|
|||||||
})
|
})
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
|
Route groups can be added too using the Group method.
|
||||||
|
~~~ go
|
||||||
|
m.Group("/books", func(r Router) {
|
||||||
|
r.Get("/:id", GetBooks)
|
||||||
|
r.Post("/new", NewBook)
|
||||||
|
r.Put("/update/:id", UpdateBook)
|
||||||
|
r.Delete("/delete/:id", DeleteBook)
|
||||||
|
})
|
||||||
|
~~~
|
||||||
|
|
||||||
|
Just like you can pass middlewares to a handler you can pass middlewares to groups.
|
||||||
|
~~~ go
|
||||||
|
m.Group("/books", func(r Router) {
|
||||||
|
r.Get("/:id", GetBooks)
|
||||||
|
r.Post("/new", NewBook)
|
||||||
|
r.Put("/update/:id", UpdateBook)
|
||||||
|
r.Delete("/delete/:id", DeleteBook)
|
||||||
|
}, MyMiddleware1, MyMiddleware2)
|
||||||
|
~~~
|
||||||
|
|
||||||
### Services
|
### Services
|
||||||
Services are objects that are available to be injected into a Handler's argument list. You can map a service on a *Global* or *Request* level.
|
Services are objects that are available to be injected into a Handler's argument list. You can map a service on a *Global* or *Request* level.
|
||||||
|
|
||||||
@ -219,7 +243,7 @@ m.Use(func() {
|
|||||||
})
|
})
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
You can have full control over the middleware stack with the `Handlers` function:
|
You can have full control over the middleware stack with the `Handlers` function. This will replace any handlers that have been previously set:
|
||||||
~~~ go
|
~~~ go
|
||||||
m.Handlers(
|
m.Handlers(
|
||||||
Middleware1,
|
Middleware1,
|
||||||
@ -251,17 +275,28 @@ m.Use(func(c martini.Context, log *log.Logger){
|
|||||||
})
|
})
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
|
## Martini Env
|
||||||
|
|
||||||
|
Some Martini handlers make use of the `martini.Env` global variable to provide special functionality for development environments vs production environments. It is reccomended that the `MARTINI_ENV=production` environment variable to be set when deploying a Martini server into a production environment.
|
||||||
|
|
||||||
## FAQ
|
## FAQ
|
||||||
|
|
||||||
### Where do I find middleware X?
|
### Where do I find middleware X?
|
||||||
|
|
||||||
Start by looking in the [martini-contrib](http://github.com/codegangsta/martini-contrib) package. If it is not there feel free to put up a Pull Request for one.
|
Start by looking in the [martini-contrib](https://github.com/martini-contrib) projects. If it is not there feel free to contact a martini-contrib team member about adding a new repo to the organization.
|
||||||
|
|
||||||
* [auth](https://github.com/codegangsta/martini-contrib/tree/master/auth) - Handlers for authentication.
|
* [auth](https://github.com/martini-contrib/auth) - Handlers for authentication.
|
||||||
* [form](https://github.com/codegangsta/martini-contrib/tree/master/form) - Handler for parsing and mapping form fields.
|
* [binding](https://github.com/martini-contrib/binding) - Handler for mapping/validating a raw request into a structure.
|
||||||
* [gzip](https://github.com/codegangsta/martini-contrib/tree/master/gzip) - Handler for adding gzip compress to requests
|
* [gzip](https://github.com/martini-contrib/gzip) - Handler for adding gzip compress to requests
|
||||||
* [render](https://github.com/codegangsta/martini-contrib/tree/master/render) - Handler that provides a service for easily rendering JSON and HTML templates.
|
* [render](https://github.com/martini-contrib/render) - Handler that provides a service for easily rendering JSON and HTML templates.
|
||||||
* [acceptlang](https://github.com/codegangsta/martini-contrib/tree/master/acceptlang) - Handler for parsing the `Accept-Language` HTTP header.
|
* [acceptlang](https://github.com/martini-contrib/acceptlang) - Handler for parsing the `Accept-Language` HTTP header.
|
||||||
|
* [sessions](https://github.com/martini-contrib/sessions) - Handler that provides a Session service.
|
||||||
|
* [strip](https://github.com/martini-contrib/strip) - URL Prefix stripping.
|
||||||
|
* [method](https://github.com/martini-contrib/method) - HTTP method overriding via Header or form fields.
|
||||||
|
* [secure](https://github.com/martini-contrib/secure) - Implements a few quick security wins.
|
||||||
|
* [encoder](https://github.com/martini-contrib/encoder) - Encoder service for rendering data in several formats and content negotiation.
|
||||||
|
* [cors](https://github.com/martini-contrib/cors) - Handler that enables CORS support.
|
||||||
|
* [oauth2](https://github.com/martini-contrib/oauth2) - Handler that provides OAuth 2.0 login for Martini apps. Google Sign-in, Facebook Connect and Github login is supported.
|
||||||
|
|
||||||
### How do I integrate with existing servers?
|
### How do I integrate with existing servers?
|
||||||
|
|
||||||
@ -287,17 +322,24 @@ func init() {
|
|||||||
|
|
||||||
### How do I change the port/host?
|
### How do I change the port/host?
|
||||||
|
|
||||||
Martini's `Run` function looks for the PORT environment variable and uses that. Otherwise Martini will default to port 3000.
|
Martini's `Run` function looks for the PORT and HOST environment variables and uses those. Otherwise Martini will default to localhost:3000.
|
||||||
To have more flexibility over port and host, use the `http.ListenAndServe` function instead.
|
To have more flexibility over port and host, use the `http.ListenAndServe` function instead.
|
||||||
|
|
||||||
~~~ go
|
~~~ go
|
||||||
m := martini.Classic()
|
m := martini.Classic()
|
||||||
// ...
|
// ...
|
||||||
http.ListenAndServe(":8080", m)
|
log.Fatal(http.ListenAndServe(":8080", m))
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
|
### Live code reload?
|
||||||
|
|
||||||
|
[gin](https://github.com/codegangsta/gin) and [fresh](https://github.com/pilu/fresh) both live reload martini apps.
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
Martini is meant to be kept tiny and clean. Most contributions should end up in the [martini-contrib](http://github.com/codegangsta/martini-contrib) repository. If you do have a contribution for the core of Martini feel free to put up a Pull Request.
|
Martini is meant to be kept tiny and clean. Most contributions should end up in a repository in the [martini-contrib](https://github.com/martini-contrib) organization. If you do have a contribution for the core of Martini feel free to put up a Pull Request.
|
||||||
|
|
||||||
## About
|
## About
|
||||||
|
|
||||||
|
Inspired by [express](https://github.com/visionmedia/express) and [sinatra](https://github.com/sinatra/sinatra)
|
||||||
|
|
||||||
Martini is obsessively designed by none other than the [Code Gangsta](http://codegangsta.io/)
|
Martini is obsessively designed by none other than the [Code Gangsta](http://codegangsta.io/)
|
||||||
|
10
Godeps/_workspace/src/github.com/codegangsta/martini/env.go
generated
vendored
10
Godeps/_workspace/src/github.com/codegangsta/martini/env.go
generated
vendored
@ -4,6 +4,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Envs
|
||||||
const (
|
const (
|
||||||
Dev string = "development"
|
Dev string = "development"
|
||||||
Prod string = "production"
|
Prod string = "production"
|
||||||
@ -11,11 +12,14 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Env is the environment that Martini is executing in. The MARTINI_ENV is read on initialization to set this variable.
|
// Env is the environment that Martini is executing in. The MARTINI_ENV is read on initialization to set this variable.
|
||||||
var Env string = Dev
|
var Env = Dev
|
||||||
|
|
||||||
func init() {
|
func setENV(e string) {
|
||||||
e := os.Getenv("MARTINI_ENV")
|
|
||||||
if len(e) > 0 {
|
if len(e) > 0 {
|
||||||
Env = e
|
Env = e
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
setENV(os.Getenv("MARTINI_ENV"))
|
||||||
|
}
|
||||||
|
22
Godeps/_workspace/src/github.com/codegangsta/martini/env_test.go
generated
vendored
Normal file
22
Godeps/_workspace/src/github.com/codegangsta/martini/env_test.go
generated
vendored
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
package martini
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_SetENV(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
in string
|
||||||
|
out string
|
||||||
|
}{
|
||||||
|
{"", "development"},
|
||||||
|
{"not_development", "not_development"},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
setENV(test.in)
|
||||||
|
if Env != test.out {
|
||||||
|
expect(t, Env, test.out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
6
Godeps/_workspace/src/github.com/codegangsta/martini/go_version.go
generated
vendored
6
Godeps/_workspace/src/github.com/codegangsta/martini/go_version.go
generated
vendored
@ -1,3 +1,7 @@
|
|||||||
// +build !go1.1
|
// +build !go1.1
|
||||||
|
|
||||||
"martini requires go 1.1 or greater to build"
|
package martini
|
||||||
|
|
||||||
|
func MartiniDoesNotSupportGo1Point0() {
|
||||||
|
"Martini requires Go 1.1 or greater."
|
||||||
|
}
|
||||||
|
4
Godeps/_workspace/src/github.com/codegangsta/martini/logger.go
generated
vendored
4
Godeps/_workspace/src/github.com/codegangsta/martini/logger.go
generated
vendored
@ -12,9 +12,7 @@ func Logger() Handler {
|
|||||||
start := time.Now()
|
start := time.Now()
|
||||||
log.Printf("Started %s %s", req.Method, req.URL.Path)
|
log.Printf("Started %s %s", req.Method, req.URL.Path)
|
||||||
|
|
||||||
rw := NewResponseWriter(res)
|
rw := res.(ResponseWriter)
|
||||||
c.MapTo(rw, (*http.ResponseWriter)(nil))
|
|
||||||
|
|
||||||
c.Next()
|
c.Next()
|
||||||
|
|
||||||
log.Printf("Completed %v %s in %v\n", rw.Status(), http.StatusText(rw.Status()), time.Since(start))
|
log.Printf("Completed %v %s in %v\n", rw.Status(), http.StatusText(rw.Status()), time.Since(start))
|
||||||
|
70
Godeps/_workspace/src/github.com/codegangsta/martini/martini.go
generated
vendored
70
Godeps/_workspace/src/github.com/codegangsta/martini/martini.go
generated
vendored
@ -18,11 +18,12 @@
|
|||||||
package martini
|
package martini
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/codegangsta/inject"
|
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
|
"github.com/codegangsta/inject"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Martini represents the top level web application. inject.Injector methods can be invoked to map services on a global level.
|
// Martini represents the top level web application. inject.Injector methods can be invoked to map services on a global level.
|
||||||
@ -35,11 +36,27 @@ type Martini struct {
|
|||||||
|
|
||||||
// New creates a bare bones Martini instance. Use this method if you want to have full control over the middleware that is used.
|
// New creates a bare bones Martini instance. Use this method if you want to have full control over the middleware that is used.
|
||||||
func New() *Martini {
|
func New() *Martini {
|
||||||
m := &Martini{inject.New(), []Handler{}, func() {}, log.New(os.Stdout, "[martini] ", 0)}
|
m := &Martini{Injector: inject.New(), action: func() {}, logger: log.New(os.Stdout, "[martini] ", 0)}
|
||||||
m.Map(m.logger)
|
m.Map(m.logger)
|
||||||
|
m.Map(defaultReturnHandler())
|
||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handlers sets the entire middleware stack with the given Handlers. This will clear any current middleware handlers.
|
||||||
|
// Will panic if any of the handlers is not a callable function
|
||||||
|
func (m *Martini) Handlers(handlers ...Handler) {
|
||||||
|
m.handlers = make([]Handler, 0)
|
||||||
|
for _, handler := range handlers {
|
||||||
|
m.Use(handler)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Action sets the handler that will be called after all the middleware has been invoked. This is set to martini.Router in a martini.Classic().
|
||||||
|
func (m *Martini) Action(handler Handler) {
|
||||||
|
validateHandler(handler)
|
||||||
|
m.action = handler
|
||||||
|
}
|
||||||
|
|
||||||
// Use adds a middleware Handler to the stack. Will panic if the handler is not a callable func. Middleware Handlers are invoked in the order that they are added.
|
// Use adds a middleware Handler to the stack. Will panic if the handler is not a callable func. Middleware Handlers are invoked in the order that they are added.
|
||||||
func (m *Martini) Use(handler Handler) {
|
func (m *Martini) Use(handler Handler) {
|
||||||
validateHandler(handler)
|
validateHandler(handler)
|
||||||
@ -52,34 +69,21 @@ func (m *Martini) ServeHTTP(res http.ResponseWriter, req *http.Request) {
|
|||||||
m.createContext(res, req).run()
|
m.createContext(res, req).run()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Action sets the handler that will be called after all the middleware has been invoked. This is set to martini.Router in a martini.Classic().
|
|
||||||
func (m *Martini) Action(handler Handler) {
|
|
||||||
validateHandler(handler)
|
|
||||||
m.action = handler
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run the http server. Listening on os.GetEnv("PORT") or 3000 by default.
|
// Run the http server. Listening on os.GetEnv("PORT") or 3000 by default.
|
||||||
func (m *Martini) Run() {
|
func (m *Martini) Run() {
|
||||||
port := os.Getenv("PORT")
|
port := os.Getenv("PORT")
|
||||||
if len(port) == 0 {
|
if port == "" {
|
||||||
port = "3000"
|
port = "3000"
|
||||||
}
|
}
|
||||||
|
|
||||||
m.logger.Println("listening on port " + port)
|
host := os.Getenv("HOST")
|
||||||
m.logger.Fatalln(http.ListenAndServe(":"+port, m))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handlers sets the entire middleware stack with the given Handlers. This will clear any current middleware handlers.
|
m.logger.Println("listening on " + host + ":" + port)
|
||||||
// Will panic if any of the handlers is not a callable function
|
m.logger.Fatalln(http.ListenAndServe(host+":"+port, m))
|
||||||
func (m *Martini) Handlers(handlers ...Handler) {
|
|
||||||
m.handlers = make([]Handler, 0)
|
|
||||||
for _, handler := range handlers {
|
|
||||||
m.Use(handler)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Martini) createContext(res http.ResponseWriter, req *http.Request) *context {
|
func (m *Martini) createContext(res http.ResponseWriter, req *http.Request) *context {
|
||||||
c := &context{inject.New(), append(m.handlers, m.action), NewResponseWriter(res), 0}
|
c := &context{inject.New(), m.handlers, m.action, NewResponseWriter(res), 0}
|
||||||
c.SetParent(m)
|
c.SetParent(m)
|
||||||
c.MapTo(c, (*Context)(nil))
|
c.MapTo(c, (*Context)(nil))
|
||||||
c.MapTo(c.rw, (*http.ResponseWriter)(nil))
|
c.MapTo(c.rw, (*http.ResponseWriter)(nil))
|
||||||
@ -93,13 +97,15 @@ type ClassicMartini struct {
|
|||||||
Router
|
Router
|
||||||
}
|
}
|
||||||
|
|
||||||
// Classic creates a classic Martini with some basic default middleware - martini.Logger, martini.Recovery, and martini.Static.
|
// Classic creates a classic Martini with some basic default middleware - martini.Logger, martini.Recovery and martini.Static.
|
||||||
|
// Classic also maps martini.Routes as a service.
|
||||||
func Classic() *ClassicMartini {
|
func Classic() *ClassicMartini {
|
||||||
r := NewRouter()
|
r := NewRouter()
|
||||||
m := New()
|
m := New()
|
||||||
m.Use(Logger())
|
m.Use(Logger())
|
||||||
m.Use(Recovery())
|
m.Use(Recovery())
|
||||||
m.Use(Static("public"))
|
m.Use(Static("public"))
|
||||||
|
m.MapTo(r, (*Routes)(nil))
|
||||||
m.Action(r.Handle)
|
m.Action(r.Handle)
|
||||||
return &ClassicMartini{m, r}
|
return &ClassicMartini{m, r}
|
||||||
}
|
}
|
||||||
@ -121,34 +127,46 @@ type Context interface {
|
|||||||
// the other Handlers have been executed. This works really well for any operations that must
|
// the other Handlers have been executed. This works really well for any operations that must
|
||||||
// happen after an http request
|
// happen after an http request
|
||||||
Next()
|
Next()
|
||||||
written() bool
|
// Written returns whether or not the response for this context has been written.
|
||||||
|
Written() bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type context struct {
|
type context struct {
|
||||||
inject.Injector
|
inject.Injector
|
||||||
handlers []Handler
|
handlers []Handler
|
||||||
|
action Handler
|
||||||
rw ResponseWriter
|
rw ResponseWriter
|
||||||
index int
|
index int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *context) handler() Handler {
|
||||||
|
if c.index < len(c.handlers) {
|
||||||
|
return c.handlers[c.index]
|
||||||
|
}
|
||||||
|
if c.index == len(c.handlers) {
|
||||||
|
return c.action
|
||||||
|
}
|
||||||
|
panic("invalid index for context handler")
|
||||||
|
}
|
||||||
|
|
||||||
func (c *context) Next() {
|
func (c *context) Next() {
|
||||||
c.index += 1
|
c.index += 1
|
||||||
c.run()
|
c.run()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *context) written() bool {
|
func (c *context) Written() bool {
|
||||||
return c.rw.Written()
|
return c.rw.Written()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *context) run() {
|
func (c *context) run() {
|
||||||
for c.index < len(c.handlers) {
|
for c.index <= len(c.handlers) {
|
||||||
_, err := c.Invoke(c.handlers[c.index])
|
_, err := c.Invoke(c.handler())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
c.index += 1
|
c.index += 1
|
||||||
|
|
||||||
if c.rw.Written() {
|
if c.Written() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
38
Godeps/_workspace/src/github.com/codegangsta/martini/martini_test.go
generated
vendored
38
Godeps/_workspace/src/github.com/codegangsta/martini/martini_test.go
generated
vendored
@ -22,7 +22,14 @@ func refute(t *testing.T, a interface{}, b interface{}) {
|
|||||||
|
|
||||||
func Test_New(t *testing.T) {
|
func Test_New(t *testing.T) {
|
||||||
m := New()
|
m := New()
|
||||||
refute(t, m, nil)
|
if m == nil {
|
||||||
|
t.Error("martini.New() cannot return nil")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Martini_Run(t *testing.T) {
|
||||||
|
// just test that Run doesn't bomb
|
||||||
|
go New().Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_Martini_ServeHTTP(t *testing.T) {
|
func Test_Martini_ServeHTTP(t *testing.T) {
|
||||||
@ -103,3 +110,32 @@ func Test_Martini_EarlyWrite(t *testing.T) {
|
|||||||
expect(t, result, "foobar")
|
expect(t, result, "foobar")
|
||||||
expect(t, response.Code, http.StatusOK)
|
expect(t, response.Code, http.StatusOK)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Test_Martini_Written(t *testing.T) {
|
||||||
|
response := httptest.NewRecorder()
|
||||||
|
|
||||||
|
m := New()
|
||||||
|
m.Handlers(func(res http.ResponseWriter) {
|
||||||
|
res.WriteHeader(http.StatusOK)
|
||||||
|
})
|
||||||
|
|
||||||
|
ctx := m.createContext(response, (*http.Request)(nil))
|
||||||
|
expect(t, ctx.Written(), false)
|
||||||
|
|
||||||
|
ctx.run()
|
||||||
|
expect(t, ctx.Written(), true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Martini_Basic_NoRace(t *testing.T) {
|
||||||
|
m := New()
|
||||||
|
handlers := []Handler{func() {}, func() {}}
|
||||||
|
// Ensure append will not realloc to trigger the race condition
|
||||||
|
m.handlers = handlers[:1]
|
||||||
|
req, _ := http.NewRequest("GET", "/", nil)
|
||||||
|
for i := 0; i < 2; i++ {
|
||||||
|
go func() {
|
||||||
|
response := httptest.NewRecorder()
|
||||||
|
m.ServeHTTP(response, req)
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
127
Godeps/_workspace/src/github.com/codegangsta/martini/recovery.go
generated
vendored
127
Godeps/_workspace/src/github.com/codegangsta/martini/recovery.go
generated
vendored
@ -1,18 +1,139 @@
|
|||||||
package martini
|
package martini
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"runtime/debug"
|
"runtime"
|
||||||
|
|
||||||
|
"github.com/codegangsta/inject"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
panicHtml = `<html>
|
||||||
|
<head><title>PANIC: %s</title>
|
||||||
|
<style type="text/css">
|
||||||
|
html, body {
|
||||||
|
font-family: "Roboto", sans-serif;
|
||||||
|
color: #333333;
|
||||||
|
background-color: #ea5343;
|
||||||
|
margin: 0px;
|
||||||
|
}
|
||||||
|
h1 {
|
||||||
|
color: #d04526;
|
||||||
|
background-color: #ffffff;
|
||||||
|
padding: 20px;
|
||||||
|
border-bottom: 1px dashed #2b3848;
|
||||||
|
}
|
||||||
|
pre {
|
||||||
|
margin: 20px;
|
||||||
|
padding: 20px;
|
||||||
|
border: 2px solid #2b3848;
|
||||||
|
background-color: #ffffff;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head><body>
|
||||||
|
<h1>PANIC</h1>
|
||||||
|
<pre style="font-weight: bold;">%s</pre>
|
||||||
|
<pre>%s</pre>
|
||||||
|
</body>
|
||||||
|
</html>`
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
dunno = []byte("???")
|
||||||
|
centerDot = []byte("·")
|
||||||
|
dot = []byte(".")
|
||||||
|
slash = []byte("/")
|
||||||
|
)
|
||||||
|
|
||||||
|
// stack returns a nicely formated stack frame, skipping skip frames
|
||||||
|
func stack(skip int) []byte {
|
||||||
|
buf := new(bytes.Buffer) // the returned data
|
||||||
|
// As we loop, we open files and read them. These variables record the currently
|
||||||
|
// loaded file.
|
||||||
|
var lines [][]byte
|
||||||
|
var lastFile string
|
||||||
|
for i := skip; ; i++ { // Skip the expected number of frames
|
||||||
|
pc, file, line, ok := runtime.Caller(i)
|
||||||
|
if !ok {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
// Print this much at least. If we can't find the source, it won't show.
|
||||||
|
fmt.Fprintf(buf, "%s:%d (0x%x)\n", file, line, pc)
|
||||||
|
if file != lastFile {
|
||||||
|
data, err := ioutil.ReadFile(file)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
lines = bytes.Split(data, []byte{'\n'})
|
||||||
|
lastFile = file
|
||||||
|
}
|
||||||
|
fmt.Fprintf(buf, "\t%s: %s\n", function(pc), source(lines, line))
|
||||||
|
}
|
||||||
|
return buf.Bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
// source returns a space-trimmed slice of the n'th line.
|
||||||
|
func source(lines [][]byte, n int) []byte {
|
||||||
|
n-- // in stack trace, lines are 1-indexed but our array is 0-indexed
|
||||||
|
if n < 0 || n >= len(lines) {
|
||||||
|
return dunno
|
||||||
|
}
|
||||||
|
return bytes.TrimSpace(lines[n])
|
||||||
|
}
|
||||||
|
|
||||||
|
// function returns, if possible, the name of the function containing the PC.
|
||||||
|
func function(pc uintptr) []byte {
|
||||||
|
fn := runtime.FuncForPC(pc)
|
||||||
|
if fn == nil {
|
||||||
|
return dunno
|
||||||
|
}
|
||||||
|
name := []byte(fn.Name())
|
||||||
|
// The name includes the path name to the package, which is unnecessary
|
||||||
|
// since the file name is already included. Plus, it has center dots.
|
||||||
|
// That is, we see
|
||||||
|
// runtime/debug.*T·ptrmethod
|
||||||
|
// and want
|
||||||
|
// *T.ptrmethod
|
||||||
|
// Also the package path might contains dot (e.g. code.google.com/...),
|
||||||
|
// so first eliminate the path prefix
|
||||||
|
if lastslash := bytes.LastIndex(name, slash); lastslash >= 0 {
|
||||||
|
name = name[lastslash+1:]
|
||||||
|
}
|
||||||
|
if period := bytes.Index(name, dot); period >= 0 {
|
||||||
|
name = name[period+1:]
|
||||||
|
}
|
||||||
|
name = bytes.Replace(name, centerDot, dot, -1)
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
|
||||||
// Recovery returns a middleware that recovers from any panics and writes a 500 if there was one.
|
// Recovery returns a middleware that recovers from any panics and writes a 500 if there was one.
|
||||||
|
// While Martini is in development mode, Recovery will also output the panic as HTML.
|
||||||
func Recovery() Handler {
|
func Recovery() Handler {
|
||||||
return func(res http.ResponseWriter, c Context, logger *log.Logger) {
|
return func(c Context, log *log.Logger) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := recover(); err != nil {
|
if err := recover(); err != nil {
|
||||||
|
stack := stack(3)
|
||||||
|
log.Printf("PANIC: %s\n%s", err, stack)
|
||||||
|
|
||||||
|
// Lookup the current responsewriter
|
||||||
|
val := c.Get(inject.InterfaceOf((*http.ResponseWriter)(nil)))
|
||||||
|
res := val.Interface().(http.ResponseWriter)
|
||||||
|
|
||||||
|
// respond with panic message while in development mode
|
||||||
|
var body []byte
|
||||||
|
if Env == Dev {
|
||||||
|
res.Header().Set("Content-Type", "text/html")
|
||||||
|
body = []byte(fmt.Sprintf(panicHtml, err, err, stack))
|
||||||
|
}
|
||||||
|
|
||||||
res.WriteHeader(http.StatusInternalServerError)
|
res.WriteHeader(http.StatusInternalServerError)
|
||||||
logger.Printf("PANIC: %s\n%s", err, debug.Stack())
|
if nil != body {
|
||||||
|
res.Write(body)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
25
Godeps/_workspace/src/github.com/codegangsta/martini/recovery_test.go
generated
vendored
25
Godeps/_workspace/src/github.com/codegangsta/martini/recovery_test.go
generated
vendored
@ -12,15 +12,38 @@ func Test_Recovery(t *testing.T) {
|
|||||||
buff := bytes.NewBufferString("")
|
buff := bytes.NewBufferString("")
|
||||||
recorder := httptest.NewRecorder()
|
recorder := httptest.NewRecorder()
|
||||||
|
|
||||||
|
setENV(Dev)
|
||||||
m := New()
|
m := New()
|
||||||
// replace log for testing
|
// replace log for testing
|
||||||
m.Map(log.New(buff, "[martini] ", 0))
|
m.Map(log.New(buff, "[martini] ", 0))
|
||||||
|
m.Use(func(res http.ResponseWriter, req *http.Request) {
|
||||||
|
res.Header().Set("Content-Type", "unpredictable")
|
||||||
|
})
|
||||||
m.Use(Recovery())
|
m.Use(Recovery())
|
||||||
m.Use(func(res http.ResponseWriter, req *http.Request) {
|
m.Use(func(res http.ResponseWriter, req *http.Request) {
|
||||||
panic("here is a panic!")
|
panic("here is a panic!")
|
||||||
})
|
})
|
||||||
m.ServeHTTP(recorder, (*http.Request)(nil))
|
m.ServeHTTP(recorder, (*http.Request)(nil))
|
||||||
expect(t, recorder.Code, http.StatusInternalServerError)
|
expect(t, recorder.Code, http.StatusInternalServerError)
|
||||||
|
expect(t, recorder.HeaderMap.Get("Content-Type"), "text/html")
|
||||||
|
refute(t, recorder.Body.Len(), 0)
|
||||||
refute(t, len(buff.String()), 0)
|
refute(t, len(buff.String()), 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Recovery_ResponseWriter(t *testing.T) {
|
||||||
|
recorder := httptest.NewRecorder()
|
||||||
|
recorder2 := httptest.NewRecorder()
|
||||||
|
|
||||||
|
setENV(Dev)
|
||||||
|
m := New()
|
||||||
|
m.Use(Recovery())
|
||||||
|
m.Use(func(c Context) {
|
||||||
|
c.MapTo(recorder2, (*http.ResponseWriter)(nil))
|
||||||
|
panic("here is a panic!")
|
||||||
|
})
|
||||||
|
m.ServeHTTP(recorder, (*http.Request)(nil))
|
||||||
|
|
||||||
|
expect(t, recorder2.Code, http.StatusInternalServerError)
|
||||||
|
expect(t, recorder2.HeaderMap.Get("Content-Type"), "text/html")
|
||||||
|
refute(t, recorder2.Body.Len(), 0)
|
||||||
}
|
}
|
||||||
|
40
Godeps/_workspace/src/github.com/codegangsta/martini/response_writer.go
generated
vendored
40
Godeps/_workspace/src/github.com/codegangsta/martini/response_writer.go
generated
vendored
@ -12,26 +12,35 @@ import (
|
|||||||
// if the functionality calls for it.
|
// if the functionality calls for it.
|
||||||
type ResponseWriter interface {
|
type ResponseWriter interface {
|
||||||
http.ResponseWriter
|
http.ResponseWriter
|
||||||
|
http.Flusher
|
||||||
// Status returns the status code of the response or 0 if the response has not been written.
|
// Status returns the status code of the response or 0 if the response has not been written.
|
||||||
Status() int
|
Status() int
|
||||||
// Written returns whether or not the ResponseWriter has been written.
|
// Written returns whether or not the ResponseWriter has been written.
|
||||||
Written() bool
|
Written() bool
|
||||||
// Size returns the size of the response body.
|
// Size returns the size of the response body.
|
||||||
Size() int
|
Size() int
|
||||||
|
// Before allows for a function to be called before the ResponseWriter has been written to. This is
|
||||||
|
// useful for setting headers or any other operations that must happen before a response has been written.
|
||||||
|
Before(BeforeFunc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BeforeFunc is a function that is called before the ResponseWriter has been written to.
|
||||||
|
type BeforeFunc func(ResponseWriter)
|
||||||
|
|
||||||
// NewResponseWriter creates a ResponseWriter that wraps an http.ResponseWriter
|
// NewResponseWriter creates a ResponseWriter that wraps an http.ResponseWriter
|
||||||
func NewResponseWriter(rw http.ResponseWriter) ResponseWriter {
|
func NewResponseWriter(rw http.ResponseWriter) ResponseWriter {
|
||||||
return &responseWriter{rw, 0, 0}
|
return &responseWriter{rw, 0, 0, nil}
|
||||||
}
|
}
|
||||||
|
|
||||||
type responseWriter struct {
|
type responseWriter struct {
|
||||||
http.ResponseWriter
|
http.ResponseWriter
|
||||||
status int
|
status int
|
||||||
size int
|
size int
|
||||||
|
beforeFuncs []BeforeFunc
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rw *responseWriter) WriteHeader(s int) {
|
func (rw *responseWriter) WriteHeader(s int) {
|
||||||
|
rw.callBefore()
|
||||||
rw.ResponseWriter.WriteHeader(s)
|
rw.ResponseWriter.WriteHeader(s)
|
||||||
rw.status = s
|
rw.status = s
|
||||||
}
|
}
|
||||||
@ -39,7 +48,7 @@ func (rw *responseWriter) WriteHeader(s int) {
|
|||||||
func (rw *responseWriter) Write(b []byte) (int, error) {
|
func (rw *responseWriter) Write(b []byte) (int, error) {
|
||||||
if !rw.Written() {
|
if !rw.Written() {
|
||||||
// The status will be StatusOK if WriteHeader has not been called yet
|
// The status will be StatusOK if WriteHeader has not been called yet
|
||||||
rw.status = http.StatusOK
|
rw.WriteHeader(http.StatusOK)
|
||||||
}
|
}
|
||||||
size, err := rw.ResponseWriter.Write(b)
|
size, err := rw.ResponseWriter.Write(b)
|
||||||
rw.size += size
|
rw.size += size
|
||||||
@ -58,10 +67,31 @@ func (rw *responseWriter) Written() bool {
|
|||||||
return rw.status != 0
|
return rw.status != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (rw *responseWriter) Before(before BeforeFunc) {
|
||||||
|
rw.beforeFuncs = append(rw.beforeFuncs, before)
|
||||||
|
}
|
||||||
|
|
||||||
func (rw *responseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
func (rw *responseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
||||||
hijacker, ok := rw.ResponseWriter.(http.Hijacker)
|
hijacker, ok := rw.ResponseWriter.(http.Hijacker)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, nil, fmt.Errorf("ResponseWriter doesn't support Hijacker interface")
|
return nil, nil, fmt.Errorf("the ResponseWriter doesn't support the Hijacker interface")
|
||||||
}
|
}
|
||||||
return hijacker.Hijack()
|
return hijacker.Hijack()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (rw *responseWriter) CloseNotify() <-chan bool {
|
||||||
|
return rw.ResponseWriter.(http.CloseNotifier).CloseNotify()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rw *responseWriter) callBefore() {
|
||||||
|
for i := len(rw.beforeFuncs) - 1; i >= 0; i-- {
|
||||||
|
rw.beforeFuncs[i](rw)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rw *responseWriter) Flush() {
|
||||||
|
flusher, ok := rw.ResponseWriter.(http.Flusher)
|
||||||
|
if ok {
|
||||||
|
flusher.Flush()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
112
Godeps/_workspace/src/github.com/codegangsta/martini/response_writer_test.go
generated
vendored
112
Godeps/_workspace/src/github.com/codegangsta/martini/response_writer_test.go
generated
vendored
@ -2,12 +2,34 @@ package martini
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type closeNotifyingRecorder struct {
|
||||||
|
*httptest.ResponseRecorder
|
||||||
|
closed chan bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func newCloseNotifyingRecorder() *closeNotifyingRecorder {
|
||||||
|
return &closeNotifyingRecorder{
|
||||||
|
httptest.NewRecorder(),
|
||||||
|
make(chan bool, 1),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *closeNotifyingRecorder) close() {
|
||||||
|
c.closed <- true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *closeNotifyingRecorder) CloseNotify() <-chan bool {
|
||||||
|
return c.closed
|
||||||
|
}
|
||||||
|
|
||||||
type hijackableResponse struct {
|
type hijackableResponse struct {
|
||||||
Hijacked bool
|
Hijacked bool
|
||||||
}
|
}
|
||||||
@ -63,6 +85,27 @@ func Test_ResponseWriter_WritingHeader(t *testing.T) {
|
|||||||
expect(t, rw.Size(), 0)
|
expect(t, rw.Size(), 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Test_ResponseWriter_Before(t *testing.T) {
|
||||||
|
rec := httptest.NewRecorder()
|
||||||
|
rw := NewResponseWriter(rec)
|
||||||
|
result := ""
|
||||||
|
|
||||||
|
rw.Before(func(ResponseWriter) {
|
||||||
|
result += "foo"
|
||||||
|
})
|
||||||
|
rw.Before(func(ResponseWriter) {
|
||||||
|
result += "bar"
|
||||||
|
})
|
||||||
|
|
||||||
|
rw.WriteHeader(http.StatusNotFound)
|
||||||
|
|
||||||
|
expect(t, rec.Code, rw.Status())
|
||||||
|
expect(t, rec.Body.String(), "")
|
||||||
|
expect(t, rw.Status(), http.StatusNotFound)
|
||||||
|
expect(t, rw.Size(), 0)
|
||||||
|
expect(t, result, "barfoo")
|
||||||
|
}
|
||||||
|
|
||||||
func Test_ResponseWriter_Hijack(t *testing.T) {
|
func Test_ResponseWriter_Hijack(t *testing.T) {
|
||||||
hijackable := newHijackableResponse()
|
hijackable := newHijackableResponse()
|
||||||
rw := NewResponseWriter(hijackable)
|
rw := NewResponseWriter(hijackable)
|
||||||
@ -74,3 +117,72 @@ func Test_ResponseWriter_Hijack(t *testing.T) {
|
|||||||
}
|
}
|
||||||
expect(t, hijackable.Hijacked, true)
|
expect(t, hijackable.Hijacked, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Test_ResponseWrite_Hijack_NotOK(t *testing.T) {
|
||||||
|
hijackable := new(http.ResponseWriter)
|
||||||
|
rw := NewResponseWriter(*hijackable)
|
||||||
|
hijacker, ok := rw.(http.Hijacker)
|
||||||
|
expect(t, ok, true)
|
||||||
|
_, _, err := hijacker.Hijack()
|
||||||
|
|
||||||
|
refute(t, err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_ResponseWriter_CloseNotify(t *testing.T) {
|
||||||
|
rec := newCloseNotifyingRecorder()
|
||||||
|
rw := NewResponseWriter(rec)
|
||||||
|
closed := false
|
||||||
|
notifier := rw.(http.CloseNotifier).CloseNotify()
|
||||||
|
rec.close()
|
||||||
|
select {
|
||||||
|
case <-notifier:
|
||||||
|
closed = true
|
||||||
|
case <-time.After(time.Second):
|
||||||
|
}
|
||||||
|
expect(t, closed, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_ResponseWriter_Flusher(t *testing.T) {
|
||||||
|
|
||||||
|
rec := httptest.NewRecorder()
|
||||||
|
rw := NewResponseWriter(rec)
|
||||||
|
|
||||||
|
_, ok := rw.(http.Flusher)
|
||||||
|
expect(t, ok, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_ResponseWriter_FlusherHandler(t *testing.T) {
|
||||||
|
|
||||||
|
// New martini instance
|
||||||
|
m := Classic()
|
||||||
|
|
||||||
|
m.Get("/events", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
|
f, ok := w.(http.Flusher)
|
||||||
|
expect(t, ok, true)
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "text/event-stream")
|
||||||
|
w.Header().Set("Cache-Control", "no-cache")
|
||||||
|
w.Header().Set("Connection", "keep-alive")
|
||||||
|
|
||||||
|
for i := 0; i < 2; i++ {
|
||||||
|
time.Sleep(10 * time.Millisecond)
|
||||||
|
io.WriteString(w, "data: Hello\n\n")
|
||||||
|
f.Flush()
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
recorder := httptest.NewRecorder()
|
||||||
|
r, _ := http.NewRequest("GET", "/events", nil)
|
||||||
|
m.ServeHTTP(recorder, r)
|
||||||
|
|
||||||
|
if recorder.Code != 200 {
|
||||||
|
t.Error("Response not 200")
|
||||||
|
}
|
||||||
|
|
||||||
|
if recorder.Body.String() != "data: Hello\n\ndata: Hello\n\n" {
|
||||||
|
t.Error("Didn't receive correct body, got:", recorder.Body.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
43
Godeps/_workspace/src/github.com/codegangsta/martini/return_handler.go
generated
vendored
Normal file
43
Godeps/_workspace/src/github.com/codegangsta/martini/return_handler.go
generated
vendored
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
package martini
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/codegangsta/inject"
|
||||||
|
"net/http"
|
||||||
|
"reflect"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ReturnHandler is a service that Martini provides that is called
|
||||||
|
// when a route handler returns something. The ReturnHandler is
|
||||||
|
// responsible for writing to the ResponseWriter based on the values
|
||||||
|
// that are passed into this function.
|
||||||
|
type ReturnHandler func(Context, []reflect.Value)
|
||||||
|
|
||||||
|
func defaultReturnHandler() ReturnHandler {
|
||||||
|
return func(ctx Context, vals []reflect.Value) {
|
||||||
|
rv := ctx.Get(inject.InterfaceOf((*http.ResponseWriter)(nil)))
|
||||||
|
res := rv.Interface().(http.ResponseWriter)
|
||||||
|
var responseVal reflect.Value
|
||||||
|
if len(vals) > 1 && vals[0].Kind() == reflect.Int {
|
||||||
|
res.WriteHeader(int(vals[0].Int()))
|
||||||
|
responseVal = vals[1]
|
||||||
|
} else if len(vals) > 0 {
|
||||||
|
responseVal = vals[0]
|
||||||
|
}
|
||||||
|
if canDeref(responseVal) {
|
||||||
|
responseVal = responseVal.Elem()
|
||||||
|
}
|
||||||
|
if isByteSlice(responseVal) {
|
||||||
|
res.Write(responseVal.Bytes())
|
||||||
|
} else {
|
||||||
|
res.Write([]byte(responseVal.String()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func isByteSlice(val reflect.Value) bool {
|
||||||
|
return val.Kind() == reflect.Slice && val.Type().Elem().Kind() == reflect.Uint8
|
||||||
|
}
|
||||||
|
|
||||||
|
func canDeref(val reflect.Value) bool {
|
||||||
|
return val.Kind() == reflect.Interface || val.Kind() == reflect.Ptr
|
||||||
|
}
|
146
Godeps/_workspace/src/github.com/codegangsta/martini/router.go
generated
vendored
146
Godeps/_workspace/src/github.com/codegangsta/martini/router.go
generated
vendored
@ -2,7 +2,6 @@ package martini
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/codegangsta/inject"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"reflect"
|
"reflect"
|
||||||
"regexp"
|
"regexp"
|
||||||
@ -14,6 +13,10 @@ type Params map[string]string
|
|||||||
|
|
||||||
// Router is Martini's de-facto routing interface. Supports HTTP verbs, stacked handlers, and dependency injection.
|
// Router is Martini's de-facto routing interface. Supports HTTP verbs, stacked handlers, and dependency injection.
|
||||||
type Router interface {
|
type Router interface {
|
||||||
|
Routes
|
||||||
|
|
||||||
|
// Group adds a group where related routes can be added.
|
||||||
|
Group(string, func(Router), ...Handler)
|
||||||
// Get adds a route for a HTTP GET request to the specified matching pattern.
|
// Get adds a route for a HTTP GET request to the specified matching pattern.
|
||||||
Get(string, ...Handler) Route
|
Get(string, ...Handler) Route
|
||||||
// Patch adds a route for a HTTP PATCH request to the specified matching pattern.
|
// Patch adds a route for a HTTP PATCH request to the specified matching pattern.
|
||||||
@ -26,24 +29,46 @@ type Router interface {
|
|||||||
Delete(string, ...Handler) Route
|
Delete(string, ...Handler) Route
|
||||||
// Options adds a route for a HTTP OPTIONS request to the specified matching pattern.
|
// Options adds a route for a HTTP OPTIONS request to the specified matching pattern.
|
||||||
Options(string, ...Handler) Route
|
Options(string, ...Handler) Route
|
||||||
|
// Head adds a route for a HTTP HEAD request to the specified matching pattern.
|
||||||
|
Head(string, ...Handler) Route
|
||||||
// Any adds a route for any HTTP method request to the specified matching pattern.
|
// Any adds a route for any HTTP method request to the specified matching pattern.
|
||||||
Any(string, ...Handler) Route
|
Any(string, ...Handler) Route
|
||||||
|
|
||||||
// NotFound sets the handler that is called when a no route matches a request. Throws a basic 404 by default.
|
// NotFound sets the handlers that are called when a no route matches a request. Throws a basic 404 by default.
|
||||||
NotFound(Handler)
|
NotFound(...Handler)
|
||||||
|
|
||||||
// Handle is the entry point for routing. This is used as a martini.Handler
|
// Handle is the entry point for routing. This is used as a martini.Handler
|
||||||
Handle(http.ResponseWriter, *http.Request, Context)
|
Handle(http.ResponseWriter, *http.Request, Context)
|
||||||
}
|
}
|
||||||
|
|
||||||
type router struct {
|
type router struct {
|
||||||
routes []*route
|
routes []*route
|
||||||
notFound Handler
|
notFounds []Handler
|
||||||
|
groups []group
|
||||||
|
}
|
||||||
|
|
||||||
|
type group struct {
|
||||||
|
pattern string
|
||||||
|
handlers []Handler
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewRouter creates a new Router instance.
|
// NewRouter creates a new Router instance.
|
||||||
|
// If you aren't using ClassicMartini, then you can add Routes as a
|
||||||
|
// service with:
|
||||||
|
//
|
||||||
|
// m := martini.New()
|
||||||
|
// r := martini.NewRouter()
|
||||||
|
// m.MapTo(r, (*martini.Routes)(nil))
|
||||||
|
//
|
||||||
|
// If you are using ClassicMartini, then this is done for you.
|
||||||
func NewRouter() Router {
|
func NewRouter() Router {
|
||||||
return &router{notFound: http.NotFound}
|
return &router{notFounds: []Handler{http.NotFound}, groups: make([]group, 0)}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *router) Group(pattern string, fn func(Router), h ...Handler) {
|
||||||
|
r.groups = append(r.groups, group{pattern, h})
|
||||||
|
fn(r)
|
||||||
|
r.groups = r.groups[:len(r.groups)-1]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *router) Get(pattern string, h ...Handler) Route {
|
func (r *router) Get(pattern string, h ...Handler) Route {
|
||||||
@ -70,6 +95,10 @@ func (r *router) Options(pattern string, h ...Handler) Route {
|
|||||||
return r.addRoute("OPTIONS", pattern, h)
|
return r.addRoute("OPTIONS", pattern, h)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *router) Head(pattern string, h ...Handler) Route {
|
||||||
|
return r.addRoute("HEAD", pattern, h)
|
||||||
|
}
|
||||||
|
|
||||||
func (r *router) Any(pattern string, h ...Handler) Route {
|
func (r *router) Any(pattern string, h ...Handler) Route {
|
||||||
return r.addRoute("*", pattern, h)
|
return r.addRoute("*", pattern, h)
|
||||||
}
|
}
|
||||||
@ -80,38 +109,52 @@ func (r *router) Handle(res http.ResponseWriter, req *http.Request, context Cont
|
|||||||
if ok {
|
if ok {
|
||||||
params := Params(vals)
|
params := Params(vals)
|
||||||
context.Map(params)
|
context.Map(params)
|
||||||
r := routes{}
|
route.Handle(context, res)
|
||||||
context.MapTo(r, (*Routes)(nil))
|
|
||||||
_, err := context.Invoke(route.Handle)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// no routes exist, 404
|
// no routes exist, 404
|
||||||
_, err := context.Invoke(r.notFound)
|
c := &routeContext{context, 0, r.notFounds}
|
||||||
if err != nil {
|
context.MapTo(c, (*Context)(nil))
|
||||||
panic(err)
|
c.run()
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *router) NotFound(handler Handler) {
|
func (r *router) NotFound(handler ...Handler) {
|
||||||
r.notFound = handler
|
r.notFounds = handler
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *router) addRoute(method string, pattern string, handlers []Handler) *route {
|
func (r *router) addRoute(method string, pattern string, handlers []Handler) *route {
|
||||||
|
if len(r.groups) > 0 {
|
||||||
|
group := r.groups[len(r.groups)-1]
|
||||||
|
pattern = group.pattern + pattern
|
||||||
|
h := make([]Handler, len(group.handlers)+len(handlers))
|
||||||
|
copy(h, group.handlers)
|
||||||
|
copy(h[len(group.handlers):], handlers)
|
||||||
|
handlers = h
|
||||||
|
}
|
||||||
|
|
||||||
route := newRoute(method, pattern, handlers)
|
route := newRoute(method, pattern, handlers)
|
||||||
route.Validate()
|
route.Validate()
|
||||||
r.routes = append(r.routes, route)
|
r.routes = append(r.routes, route)
|
||||||
return route
|
return route
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *router) findRoute(name string) *route {
|
||||||
|
for _, route := range r.routes {
|
||||||
|
if route.name == name {
|
||||||
|
return route
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Route is an interface representing a Route in Martini's routing layer.
|
// Route is an interface representing a Route in Martini's routing layer.
|
||||||
type Route interface {
|
type Route interface {
|
||||||
// URLWith returns a rendering of the Route's url with the given string params.
|
// URLWith returns a rendering of the Route's url with the given string params.
|
||||||
URLWith([]string) string
|
URLWith([]string) string
|
||||||
|
Name(string)
|
||||||
}
|
}
|
||||||
|
|
||||||
type route struct {
|
type route struct {
|
||||||
@ -119,10 +162,11 @@ type route struct {
|
|||||||
regex *regexp.Regexp
|
regex *regexp.Regexp
|
||||||
handlers []Handler
|
handlers []Handler
|
||||||
pattern string
|
pattern string
|
||||||
|
name string
|
||||||
}
|
}
|
||||||
|
|
||||||
func newRoute(method string, pattern string, handlers []Handler) *route {
|
func newRoute(method string, pattern string, handlers []Handler) *route {
|
||||||
route := route{method, nil, handlers, pattern}
|
route := route{method, nil, handlers, pattern, ""}
|
||||||
r := regexp.MustCompile(`:[^/#?()\.\\]+`)
|
r := regexp.MustCompile(`:[^/#?()\.\\]+`)
|
||||||
pattern = r.ReplaceAllStringFunc(pattern, func(m string) string {
|
pattern = r.ReplaceAllStringFunc(pattern, func(m string) string {
|
||||||
return fmt.Sprintf(`(?P<%s>[^/#?]+)`, m[1:])
|
return fmt.Sprintf(`(?P<%s>[^/#?]+)`, m[1:])
|
||||||
@ -138,9 +182,13 @@ func newRoute(method string, pattern string, handlers []Handler) *route {
|
|||||||
return &route
|
return &route
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r route) MatchMethod(method string) bool {
|
||||||
|
return r.method == "*" || method == r.method || (method == "HEAD" && r.method == "GET")
|
||||||
|
}
|
||||||
|
|
||||||
func (r route) Match(method string, path string) (bool, map[string]string) {
|
func (r route) Match(method string, path string) (bool, map[string]string) {
|
||||||
// add Any method matching support
|
// add Any method matching support
|
||||||
if r.method != "*" && method != r.method {
|
if !r.MatchMethod(method) {
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -191,16 +239,26 @@ func (r *route) URLWith(args []string) string {
|
|||||||
return r.pattern
|
return r.pattern
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *route) Name(name string) {
|
||||||
|
r.name = name
|
||||||
|
}
|
||||||
|
|
||||||
// Routes is a helper service for Martini's routing layer.
|
// Routes is a helper service for Martini's routing layer.
|
||||||
type Routes interface {
|
type Routes interface {
|
||||||
// URLFor returns a rendered URL for the given route. Optional params can be passed to fulfill named parameters in the route.
|
// URLFor returns a rendered URL for the given route. Optional params can be passed to fulfill named parameters in the route.
|
||||||
URLFor(route Route, params ...interface{}) string
|
URLFor(name string, params ...interface{}) string
|
||||||
|
// MethodsFor returns an array of methods available for the path
|
||||||
|
MethodsFor(path string) []string
|
||||||
}
|
}
|
||||||
|
|
||||||
type routes struct{}
|
|
||||||
|
|
||||||
// URLFor returns the url for the given route name.
|
// URLFor returns the url for the given route name.
|
||||||
func (r routes) URLFor(route Route, params ...interface{}) string {
|
func (r *router) URLFor(name string, params ...interface{}) string {
|
||||||
|
route := r.findRoute(name)
|
||||||
|
|
||||||
|
if route == nil {
|
||||||
|
panic("route not found")
|
||||||
|
}
|
||||||
|
|
||||||
var args []string
|
var args []string
|
||||||
for _, param := range params {
|
for _, param := range params {
|
||||||
switch v := param.(type) {
|
switch v := param.(type) {
|
||||||
@ -210,7 +268,7 @@ func (r routes) URLFor(route Route, params ...interface{}) string {
|
|||||||
args = append(args, v)
|
args = append(args, v)
|
||||||
default:
|
default:
|
||||||
if v != nil {
|
if v != nil {
|
||||||
panic("Arguments passed to UrlFor must be integers or strings")
|
panic("Arguments passed to URLFor must be integers or strings")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -218,6 +276,27 @@ func (r routes) URLFor(route Route, params ...interface{}) string {
|
|||||||
return route.URLWith(args)
|
return route.URLWith(args)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func hasMethod(methods []string, method string) bool {
|
||||||
|
for _, v := range methods {
|
||||||
|
if v == method {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// MethodsFor returns all methods available for path
|
||||||
|
func (r *router) MethodsFor(path string) []string {
|
||||||
|
methods := []string{}
|
||||||
|
for _, route := range r.routes {
|
||||||
|
matches := route.regex.FindStringSubmatch(path)
|
||||||
|
if len(matches) > 0 && matches[0] == path && !hasMethod(methods, route.method) {
|
||||||
|
methods = append(methods, route.method)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return methods
|
||||||
|
}
|
||||||
|
|
||||||
type routeContext struct {
|
type routeContext struct {
|
||||||
Context
|
Context
|
||||||
index int
|
index int
|
||||||
@ -238,17 +317,14 @@ func (r *routeContext) run() {
|
|||||||
}
|
}
|
||||||
r.index += 1
|
r.index += 1
|
||||||
|
|
||||||
// if the handler returned something, write it to
|
// if the handler returned something, write it to the http response
|
||||||
// the http response
|
if len(vals) > 0 {
|
||||||
rv := r.Get(inject.InterfaceOf((*http.ResponseWriter)(nil)))
|
ev := r.Get(reflect.TypeOf(ReturnHandler(nil)))
|
||||||
res := rv.Interface().(http.ResponseWriter)
|
handleReturn := ev.Interface().(ReturnHandler)
|
||||||
if len(vals) > 1 && vals[0].Kind() == reflect.Int {
|
handleReturn(r, vals)
|
||||||
res.WriteHeader(int(vals[0].Int()))
|
|
||||||
res.Write([]byte(vals[1].String()))
|
|
||||||
} else if len(vals) > 0 {
|
|
||||||
res.Write([]byte(vals[0].String()))
|
|
||||||
}
|
}
|
||||||
if r.written() {
|
|
||||||
|
if r.Written() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
253
Godeps/_workspace/src/github.com/codegangsta/martini/router_test.go
generated
vendored
253
Godeps/_workspace/src/github.com/codegangsta/martini/router_test.go
generated
vendored
@ -3,6 +3,7 @@ package martini
|
|||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -10,47 +11,41 @@ func Test_Routing(t *testing.T) {
|
|||||||
router := NewRouter()
|
router := NewRouter()
|
||||||
recorder := httptest.NewRecorder()
|
recorder := httptest.NewRecorder()
|
||||||
|
|
||||||
req, err := http.NewRequest("GET", "http://localhost:3000/foo", nil)
|
req, _ := http.NewRequest("GET", "http://localhost:3000/foo", nil)
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
context := New().createContext(recorder, req)
|
context := New().createContext(recorder, req)
|
||||||
|
|
||||||
req2, err := http.NewRequest("POST", "http://localhost:3000/bar/bat", nil)
|
req2, _ := http.NewRequest("POST", "http://localhost:3000/bar/bat", nil)
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
context2 := New().createContext(recorder, req2)
|
context2 := New().createContext(recorder, req2)
|
||||||
|
|
||||||
req3, err := http.NewRequest("DELETE", "http://localhost:3000/baz", nil)
|
req3, _ := http.NewRequest("DELETE", "http://localhost:3000/baz", nil)
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
context3 := New().createContext(recorder, req3)
|
context3 := New().createContext(recorder, req3)
|
||||||
|
|
||||||
req4, err := http.NewRequest("PATCH", "http://localhost:3000/bar/foo", nil)
|
req4, _ := http.NewRequest("PATCH", "http://localhost:3000/bar/foo", nil)
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
context4 := New().createContext(recorder, req4)
|
context4 := New().createContext(recorder, req4)
|
||||||
|
|
||||||
req5, err := http.NewRequest("GET", "http://localhost:3000/fez/this/should/match", nil)
|
req5, _ := http.NewRequest("GET", "http://localhost:3000/fez/this/should/match", nil)
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
context5 := New().createContext(recorder, req5)
|
context5 := New().createContext(recorder, req5)
|
||||||
|
|
||||||
req6, err := http.NewRequest("PUT", "http://localhost:3000/pop/blah/blah/blah/bap/foo/", nil)
|
req6, _ := http.NewRequest("PUT", "http://localhost:3000/pop/blah/blah/blah/bap/foo/", nil)
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
context6 := New().createContext(recorder, req6)
|
context6 := New().createContext(recorder, req6)
|
||||||
|
|
||||||
req7, err := http.NewRequest("DELETE", "http://localhost:3000/wap//pow", nil)
|
req7, _ := http.NewRequest("DELETE", "http://localhost:3000/wap//pow", nil)
|
||||||
if err != nil {
|
context7 := New().createContext(recorder, req7)
|
||||||
t.Error(err)
|
|
||||||
}
|
req8, _ := http.NewRequest("HEAD", "http://localhost:3000/wap//pow", nil)
|
||||||
context7 := New().createContext(recorder, req6)
|
context8 := New().createContext(recorder, req8)
|
||||||
|
|
||||||
|
req9, _ := http.NewRequest("OPTIONS", "http://localhost:3000/opts", nil)
|
||||||
|
context9 := New().createContext(recorder, req9)
|
||||||
|
|
||||||
|
req10, _ := http.NewRequest("HEAD", "http://localhost:3000/foo", nil)
|
||||||
|
context10 := New().createContext(recorder, req10)
|
||||||
|
|
||||||
|
req11, _ := http.NewRequest("GET", "http://localhost:3000/bazz/inga", nil)
|
||||||
|
context11 := New().createContext(recorder, req11)
|
||||||
|
|
||||||
|
req12, _ := http.NewRequest("POST", "http://localhost:3000/bazz/inga", nil)
|
||||||
|
context12 := New().createContext(recorder, req12)
|
||||||
|
|
||||||
result := ""
|
result := ""
|
||||||
router.Get("/foo", func(req *http.Request) {
|
router.Get("/foo", func(req *http.Request) {
|
||||||
@ -84,6 +79,26 @@ func Test_Routing(t *testing.T) {
|
|||||||
expect(t, params["_1"], "")
|
expect(t, params["_1"], "")
|
||||||
result += "wappow"
|
result += "wappow"
|
||||||
})
|
})
|
||||||
|
router.Options("/opts", func() {
|
||||||
|
result += "opts"
|
||||||
|
})
|
||||||
|
router.Head("/wap/**/pow", func(params Params) {
|
||||||
|
expect(t, params["_1"], "")
|
||||||
|
result += "wappow"
|
||||||
|
})
|
||||||
|
router.Group("/bazz", func(r Router) {
|
||||||
|
r.Get("/inga", func() {
|
||||||
|
result += "get"
|
||||||
|
})
|
||||||
|
|
||||||
|
r.Post("/inga", func() {
|
||||||
|
result += "post"
|
||||||
|
})
|
||||||
|
}, func() {
|
||||||
|
result += "bazz"
|
||||||
|
}, func() {
|
||||||
|
result += "inga"
|
||||||
|
})
|
||||||
|
|
||||||
router.Handle(recorder, req, context)
|
router.Handle(recorder, req, context)
|
||||||
router.Handle(recorder, req2, context2)
|
router.Handle(recorder, req2, context2)
|
||||||
@ -92,7 +107,12 @@ func Test_Routing(t *testing.T) {
|
|||||||
router.Handle(recorder, req5, context5)
|
router.Handle(recorder, req5, context5)
|
||||||
router.Handle(recorder, req6, context6)
|
router.Handle(recorder, req6, context6)
|
||||||
router.Handle(recorder, req7, context7)
|
router.Handle(recorder, req7, context7)
|
||||||
expect(t, result, "foobarbatbarfoofezpopbapwappow")
|
router.Handle(recorder, req8, context8)
|
||||||
|
router.Handle(recorder, req9, context9)
|
||||||
|
router.Handle(recorder, req10, context10)
|
||||||
|
router.Handle(recorder, req11, context11)
|
||||||
|
router.Handle(recorder, req12, context12)
|
||||||
|
expect(t, result, "foobarbatbarfoofezpopbapwappowwappowoptsfoobazzingagetbazzingapost")
|
||||||
expect(t, recorder.Code, http.StatusNotFound)
|
expect(t, recorder.Code, http.StatusNotFound)
|
||||||
expect(t, recorder.Body.String(), "404 page not found\n")
|
expect(t, recorder.Body.String(), "404 page not found\n")
|
||||||
}
|
}
|
||||||
@ -108,13 +128,16 @@ func Test_RouterHandlerStatusCode(t *testing.T) {
|
|||||||
router.Get("/baz", func() (string, string) {
|
router.Get("/baz", func() (string, string) {
|
||||||
return "baz", "BAZ!"
|
return "baz", "BAZ!"
|
||||||
})
|
})
|
||||||
|
router.Get("/bytes", func() []byte {
|
||||||
|
return []byte("Bytes!")
|
||||||
|
})
|
||||||
|
router.Get("/interface", func() interface{} {
|
||||||
|
return "Interface!"
|
||||||
|
})
|
||||||
|
|
||||||
// code should be 200 if none is returned from the handler
|
// code should be 200 if none is returned from the handler
|
||||||
recorder := httptest.NewRecorder()
|
recorder := httptest.NewRecorder()
|
||||||
req, err := http.NewRequest("GET", "http://localhost:3000/foo", nil)
|
req, _ := http.NewRequest("GET", "http://localhost:3000/foo", nil)
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
context := New().createContext(recorder, req)
|
context := New().createContext(recorder, req)
|
||||||
router.Handle(recorder, req, context)
|
router.Handle(recorder, req, context)
|
||||||
expect(t, recorder.Code, http.StatusOK)
|
expect(t, recorder.Code, http.StatusOK)
|
||||||
@ -122,10 +145,7 @@ func Test_RouterHandlerStatusCode(t *testing.T) {
|
|||||||
|
|
||||||
// if a status code is returned, it should be used
|
// if a status code is returned, it should be used
|
||||||
recorder = httptest.NewRecorder()
|
recorder = httptest.NewRecorder()
|
||||||
req, err = http.NewRequest("GET", "http://localhost:3000/bar", nil)
|
req, _ = http.NewRequest("GET", "http://localhost:3000/bar", nil)
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
context = New().createContext(recorder, req)
|
context = New().createContext(recorder, req)
|
||||||
router.Handle(recorder, req, context)
|
router.Handle(recorder, req, context)
|
||||||
expect(t, recorder.Code, http.StatusForbidden)
|
expect(t, recorder.Code, http.StatusForbidden)
|
||||||
@ -133,24 +153,34 @@ func Test_RouterHandlerStatusCode(t *testing.T) {
|
|||||||
|
|
||||||
// shouldn't use the first returned value as a status code if not an integer
|
// shouldn't use the first returned value as a status code if not an integer
|
||||||
recorder = httptest.NewRecorder()
|
recorder = httptest.NewRecorder()
|
||||||
req, err = http.NewRequest("GET", "http://localhost:3000/baz", nil)
|
req, _ = http.NewRequest("GET", "http://localhost:3000/baz", nil)
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
context = New().createContext(recorder, req)
|
context = New().createContext(recorder, req)
|
||||||
router.Handle(recorder, req, context)
|
router.Handle(recorder, req, context)
|
||||||
expect(t, recorder.Code, http.StatusOK)
|
expect(t, recorder.Code, http.StatusOK)
|
||||||
expect(t, recorder.Body.String(), "baz")
|
expect(t, recorder.Body.String(), "baz")
|
||||||
|
|
||||||
|
// Should render bytes as a return value as well.
|
||||||
|
recorder = httptest.NewRecorder()
|
||||||
|
req, _ = http.NewRequest("GET", "http://localhost:3000/bytes", nil)
|
||||||
|
context = New().createContext(recorder, req)
|
||||||
|
router.Handle(recorder, req, context)
|
||||||
|
expect(t, recorder.Code, http.StatusOK)
|
||||||
|
expect(t, recorder.Body.String(), "Bytes!")
|
||||||
|
|
||||||
|
// Should render interface{} values.
|
||||||
|
recorder = httptest.NewRecorder()
|
||||||
|
req, _ = http.NewRequest("GET", "http://localhost:3000/interface", nil)
|
||||||
|
context = New().createContext(recorder, req)
|
||||||
|
router.Handle(recorder, req, context)
|
||||||
|
expect(t, recorder.Code, http.StatusOK)
|
||||||
|
expect(t, recorder.Body.String(), "Interface!")
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_RouterHandlerStacking(t *testing.T) {
|
func Test_RouterHandlerStacking(t *testing.T) {
|
||||||
router := NewRouter()
|
router := NewRouter()
|
||||||
recorder := httptest.NewRecorder()
|
recorder := httptest.NewRecorder()
|
||||||
|
|
||||||
req, err := http.NewRequest("GET", "http://localhost:3000/foo", nil)
|
req, _ := http.NewRequest("GET", "http://localhost:3000/foo", nil)
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
context := New().createContext(recorder, req)
|
context := New().createContext(recorder, req)
|
||||||
|
|
||||||
result := ""
|
result := ""
|
||||||
@ -209,6 +239,37 @@ func Test_RouteMatching(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Test_MethodsFor(t *testing.T) {
|
||||||
|
router := NewRouter()
|
||||||
|
recorder := httptest.NewRecorder()
|
||||||
|
|
||||||
|
req, _ := http.NewRequest("POST", "http://localhost:3000/foo", nil)
|
||||||
|
context := New().createContext(recorder, req)
|
||||||
|
context.MapTo(router, (*Routes)(nil))
|
||||||
|
router.Post("/foo/bar", func() {
|
||||||
|
})
|
||||||
|
|
||||||
|
router.Post("/fo", func() {
|
||||||
|
})
|
||||||
|
|
||||||
|
router.Get("/foo", func() {
|
||||||
|
})
|
||||||
|
|
||||||
|
router.Put("/foo", func() {
|
||||||
|
})
|
||||||
|
|
||||||
|
router.NotFound(func(routes Routes, w http.ResponseWriter, r *http.Request) {
|
||||||
|
methods := routes.MethodsFor(r.URL.Path)
|
||||||
|
if len(methods) != 0 {
|
||||||
|
w.Header().Set("Allow", strings.Join(methods, ","))
|
||||||
|
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
router.Handle(recorder, req, context)
|
||||||
|
expect(t, recorder.Code, http.StatusMethodNotAllowed)
|
||||||
|
expect(t, recorder.Header().Get("Allow"), "GET,PUT")
|
||||||
|
}
|
||||||
|
|
||||||
func Test_NotFound(t *testing.T) {
|
func Test_NotFound(t *testing.T) {
|
||||||
router := NewRouter()
|
router := NewRouter()
|
||||||
recorder := httptest.NewRecorder()
|
recorder := httptest.NewRecorder()
|
||||||
@ -225,6 +286,81 @@ func Test_NotFound(t *testing.T) {
|
|||||||
expect(t, recorder.Body.String(), "Nope\n")
|
expect(t, recorder.Body.String(), "Nope\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Test_NotFoundAsHandler(t *testing.T) {
|
||||||
|
router := NewRouter()
|
||||||
|
recorder := httptest.NewRecorder()
|
||||||
|
|
||||||
|
req, _ := http.NewRequest("GET", "http://localhost:3000/foo", nil)
|
||||||
|
context := New().createContext(recorder, req)
|
||||||
|
|
||||||
|
router.NotFound(func() string {
|
||||||
|
return "not found"
|
||||||
|
})
|
||||||
|
|
||||||
|
router.Handle(recorder, req, context)
|
||||||
|
expect(t, recorder.Code, http.StatusOK)
|
||||||
|
expect(t, recorder.Body.String(), "not found")
|
||||||
|
|
||||||
|
recorder = httptest.NewRecorder()
|
||||||
|
|
||||||
|
context = New().createContext(recorder, req)
|
||||||
|
|
||||||
|
router.NotFound(func() (int, string) {
|
||||||
|
return 404, "not found"
|
||||||
|
})
|
||||||
|
|
||||||
|
router.Handle(recorder, req, context)
|
||||||
|
expect(t, recorder.Code, http.StatusNotFound)
|
||||||
|
expect(t, recorder.Body.String(), "not found")
|
||||||
|
|
||||||
|
recorder = httptest.NewRecorder()
|
||||||
|
|
||||||
|
context = New().createContext(recorder, req)
|
||||||
|
|
||||||
|
router.NotFound(func() (int, string) {
|
||||||
|
return 200, ""
|
||||||
|
})
|
||||||
|
|
||||||
|
router.Handle(recorder, req, context)
|
||||||
|
expect(t, recorder.Code, http.StatusOK)
|
||||||
|
expect(t, recorder.Body.String(), "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_NotFoundStacking(t *testing.T) {
|
||||||
|
router := NewRouter()
|
||||||
|
recorder := httptest.NewRecorder()
|
||||||
|
|
||||||
|
req, _ := http.NewRequest("GET", "http://localhost:3000/foo", nil)
|
||||||
|
context := New().createContext(recorder, req)
|
||||||
|
|
||||||
|
result := ""
|
||||||
|
|
||||||
|
f1 := func() {
|
||||||
|
result += "foo"
|
||||||
|
}
|
||||||
|
|
||||||
|
f2 := func(c Context) {
|
||||||
|
result += "bar"
|
||||||
|
c.Next()
|
||||||
|
result += "bing"
|
||||||
|
}
|
||||||
|
|
||||||
|
f3 := func() string {
|
||||||
|
result += "bat"
|
||||||
|
return "Not Found"
|
||||||
|
}
|
||||||
|
|
||||||
|
f4 := func() {
|
||||||
|
result += "baz"
|
||||||
|
}
|
||||||
|
|
||||||
|
router.NotFound(f1, f2, f3, f4)
|
||||||
|
|
||||||
|
router.Handle(recorder, req, context)
|
||||||
|
expect(t, result, "foobarbatbing")
|
||||||
|
expect(t, recorder.Body.String(), "Not Found")
|
||||||
|
}
|
||||||
|
|
||||||
func Test_Any(t *testing.T) {
|
func Test_Any(t *testing.T) {
|
||||||
router := NewRouter()
|
router := NewRouter()
|
||||||
router.Any("/foo", func(res http.ResponseWriter) {
|
router.Any("/foo", func(res http.ResponseWriter) {
|
||||||
@ -250,28 +386,25 @@ func Test_Any(t *testing.T) {
|
|||||||
|
|
||||||
func Test_URLFor(t *testing.T) {
|
func Test_URLFor(t *testing.T) {
|
||||||
router := NewRouter()
|
router := NewRouter()
|
||||||
var barIDNameRoute, fooRoute, barRoute Route
|
|
||||||
|
|
||||||
fooRoute = router.Get("/foo", func() {
|
router.Get("/foo", func() {
|
||||||
// Nothing
|
// Nothing
|
||||||
})
|
}).Name("foo")
|
||||||
|
|
||||||
barRoute = router.Post("/bar/:id", func(params Params) {
|
router.Post("/bar/:id", func(params Params) {
|
||||||
// Nothing
|
// Nothing
|
||||||
})
|
}).Name("bar")
|
||||||
|
|
||||||
barIDNameRoute = router.Get("/bar/:id/:name", func(params Params, routes Routes) {
|
router.Get("/bar/:id/:name", func(params Params, routes Routes) {
|
||||||
expect(t, routes.URLFor(fooRoute, nil), "/foo")
|
expect(t, routes.URLFor("foo", nil), "/foo")
|
||||||
expect(t, routes.URLFor(barRoute, 5), "/bar/5")
|
expect(t, routes.URLFor("bar", 5), "/bar/5")
|
||||||
expect(t, routes.URLFor(barIDNameRoute, 5, "john"), "/bar/5/john")
|
expect(t, routes.URLFor("bar_id", 5, "john"), "/bar/5/john")
|
||||||
})
|
}).Name("bar_id")
|
||||||
|
|
||||||
// code should be 200 if none is returned from the handler
|
// code should be 200 if none is returned from the handler
|
||||||
recorder := httptest.NewRecorder()
|
recorder := httptest.NewRecorder()
|
||||||
req, err := http.NewRequest("GET", "http://localhost:3000/bar/foo/bar", nil)
|
req, _ := http.NewRequest("GET", "http://localhost:3000/bar/foo/bar", nil)
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
context := New().createContext(recorder, req)
|
context := New().createContext(recorder, req)
|
||||||
|
context.MapTo(router, (*Routes)(nil))
|
||||||
router.Handle(recorder, req, context)
|
router.Handle(recorder, req, context)
|
||||||
}
|
}
|
||||||
|
71
Godeps/_workspace/src/github.com/codegangsta/martini/static.go
generated
vendored
71
Godeps/_workspace/src/github.com/codegangsta/martini/static.go
generated
vendored
@ -7,11 +7,61 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// StaticOptions is a struct for specifying configuration options for the martini.Static middleware.
|
||||||
|
type StaticOptions struct {
|
||||||
|
// Prefix is the optional prefix used to serve the static directory content
|
||||||
|
Prefix string
|
||||||
|
// SkipLogging will disable [Static] log messages when a static file is served.
|
||||||
|
SkipLogging bool
|
||||||
|
// IndexFile defines which file to serve as index if it exists.
|
||||||
|
IndexFile string
|
||||||
|
// Expires defines which user-defined function to use for producing a HTTP Expires Header
|
||||||
|
// https://developers.google.com/speed/docs/insights/LeverageBrowserCaching
|
||||||
|
Expires func() string
|
||||||
|
}
|
||||||
|
|
||||||
|
func prepareStaticOptions(options []StaticOptions) StaticOptions {
|
||||||
|
var opt StaticOptions
|
||||||
|
if len(options) > 0 {
|
||||||
|
opt = options[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defaults
|
||||||
|
if len(opt.IndexFile) == 0 {
|
||||||
|
opt.IndexFile = "index.html"
|
||||||
|
}
|
||||||
|
// Normalize the prefix if provided
|
||||||
|
if opt.Prefix != "" {
|
||||||
|
// Ensure we have a leading '/'
|
||||||
|
if opt.Prefix[0] != '/' {
|
||||||
|
opt.Prefix = "/" + opt.Prefix
|
||||||
|
}
|
||||||
|
// Remove any trailing '/'
|
||||||
|
opt.Prefix = strings.TrimRight(opt.Prefix, "/")
|
||||||
|
}
|
||||||
|
return opt
|
||||||
|
}
|
||||||
|
|
||||||
// Static returns a middleware handler that serves static files in the given directory.
|
// Static returns a middleware handler that serves static files in the given directory.
|
||||||
func Static(directory string) Handler {
|
func Static(directory string, staticOpt ...StaticOptions) Handler {
|
||||||
dir := http.Dir(directory)
|
dir := http.Dir(directory)
|
||||||
|
opt := prepareStaticOptions(staticOpt)
|
||||||
|
|
||||||
return func(res http.ResponseWriter, req *http.Request, log *log.Logger) {
|
return func(res http.ResponseWriter, req *http.Request, log *log.Logger) {
|
||||||
|
if req.Method != "GET" && req.Method != "HEAD" {
|
||||||
|
return
|
||||||
|
}
|
||||||
file := req.URL.Path
|
file := req.URL.Path
|
||||||
|
// if we have a prefix, filter requests by stripping the prefix
|
||||||
|
if opt.Prefix != "" {
|
||||||
|
if !strings.HasPrefix(file, opt.Prefix) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
file = file[len(opt.Prefix):]
|
||||||
|
if file != "" && file[0] != '/' {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
f, err := dir.Open(file)
|
f, err := dir.Open(file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// discard the error?
|
// discard the error?
|
||||||
@ -24,16 +74,15 @@ func Static(directory string) Handler {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to serve index.html
|
// try to serve index file
|
||||||
if fi.IsDir() {
|
if fi.IsDir() {
|
||||||
|
|
||||||
// redirect if missing trailing slash
|
// redirect if missing trailing slash
|
||||||
if !strings.HasSuffix(file, "/") {
|
if !strings.HasSuffix(req.URL.Path, "/") {
|
||||||
http.Redirect(res, req, file+"/", http.StatusFound)
|
http.Redirect(res, req, req.URL.Path+"/", http.StatusFound)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
file = path.Join(file, "index.html")
|
file = path.Join(file, opt.IndexFile)
|
||||||
f, err = dir.Open(file)
|
f, err = dir.Open(file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
@ -46,7 +95,15 @@ func Static(directory string) Handler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Println("[Static] Serving " + file)
|
if !opt.SkipLogging {
|
||||||
|
log.Println("[Static] Serving " + file)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add an Expires header to the static content
|
||||||
|
if opt.Expires != nil {
|
||||||
|
res.Header().Set("Expires", opt.Expires())
|
||||||
|
}
|
||||||
|
|
||||||
http.ServeContent(res, req, file, fi.ModTime(), f)
|
http.ServeContent(res, req, file, fi.ModTime(), f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
200
Godeps/_workspace/src/github.com/codegangsta/martini/static_test.go
generated
vendored
Normal file
200
Godeps/_workspace/src/github.com/codegangsta/martini/static_test.go
generated
vendored
Normal file
@ -0,0 +1,200 @@
|
|||||||
|
package martini
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/codegangsta/inject"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_Static(t *testing.T) {
|
||||||
|
response := httptest.NewRecorder()
|
||||||
|
response.Body = new(bytes.Buffer)
|
||||||
|
|
||||||
|
m := New()
|
||||||
|
r := NewRouter()
|
||||||
|
|
||||||
|
m.Use(Static("."))
|
||||||
|
m.Action(r.Handle)
|
||||||
|
|
||||||
|
req, err := http.NewRequest("GET", "http://localhost:3000/martini.go", nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
m.ServeHTTP(response, req)
|
||||||
|
expect(t, response.Code, http.StatusOK)
|
||||||
|
expect(t, response.Header().Get("Expires"), "")
|
||||||
|
if response.Body.Len() == 0 {
|
||||||
|
t.Errorf("Got empty body for GET request")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Static_Head(t *testing.T) {
|
||||||
|
response := httptest.NewRecorder()
|
||||||
|
response.Body = new(bytes.Buffer)
|
||||||
|
|
||||||
|
m := New()
|
||||||
|
r := NewRouter()
|
||||||
|
|
||||||
|
m.Use(Static("."))
|
||||||
|
m.Action(r.Handle)
|
||||||
|
|
||||||
|
req, err := http.NewRequest("HEAD", "http://localhost:3000/martini.go", nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
m.ServeHTTP(response, req)
|
||||||
|
expect(t, response.Code, http.StatusOK)
|
||||||
|
if response.Body.Len() != 0 {
|
||||||
|
t.Errorf("Got non-empty body for HEAD request")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Static_As_Post(t *testing.T) {
|
||||||
|
response := httptest.NewRecorder()
|
||||||
|
|
||||||
|
m := New()
|
||||||
|
r := NewRouter()
|
||||||
|
|
||||||
|
m.Use(Static("."))
|
||||||
|
m.Action(r.Handle)
|
||||||
|
|
||||||
|
req, err := http.NewRequest("POST", "http://localhost:3000/martini.go", nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
m.ServeHTTP(response, req)
|
||||||
|
expect(t, response.Code, http.StatusNotFound)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Static_BadDir(t *testing.T) {
|
||||||
|
response := httptest.NewRecorder()
|
||||||
|
|
||||||
|
m := Classic()
|
||||||
|
|
||||||
|
req, err := http.NewRequest("GET", "http://localhost:3000/martini.go", nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
m.ServeHTTP(response, req)
|
||||||
|
refute(t, response.Code, http.StatusOK)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Static_Options_Logging(t *testing.T) {
|
||||||
|
response := httptest.NewRecorder()
|
||||||
|
|
||||||
|
var buffer bytes.Buffer
|
||||||
|
m := &Martini{Injector: inject.New(), action: func() {}, logger: log.New(&buffer, "[martini] ", 0)}
|
||||||
|
m.Map(m.logger)
|
||||||
|
m.Map(defaultReturnHandler())
|
||||||
|
|
||||||
|
opt := StaticOptions{}
|
||||||
|
m.Use(Static(".", opt))
|
||||||
|
|
||||||
|
req, err := http.NewRequest("GET", "http://localhost:3000/martini.go", nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
m.ServeHTTP(response, req)
|
||||||
|
expect(t, response.Code, http.StatusOK)
|
||||||
|
expect(t, buffer.String(), "[martini] [Static] Serving /martini.go\n")
|
||||||
|
|
||||||
|
// Now without logging
|
||||||
|
m.Handlers()
|
||||||
|
buffer.Reset()
|
||||||
|
|
||||||
|
// This should disable logging
|
||||||
|
opt.SkipLogging = true
|
||||||
|
m.Use(Static(".", opt))
|
||||||
|
|
||||||
|
m.ServeHTTP(response, req)
|
||||||
|
expect(t, response.Code, http.StatusOK)
|
||||||
|
expect(t, buffer.String(), "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Static_Options_ServeIndex(t *testing.T) {
|
||||||
|
response := httptest.NewRecorder()
|
||||||
|
|
||||||
|
var buffer bytes.Buffer
|
||||||
|
m := &Martini{Injector: inject.New(), action: func() {}, logger: log.New(&buffer, "[martini] ", 0)}
|
||||||
|
m.Map(m.logger)
|
||||||
|
m.Map(defaultReturnHandler())
|
||||||
|
|
||||||
|
opt := StaticOptions{IndexFile: "martini.go"} // Define martini.go as index file
|
||||||
|
m.Use(Static(".", opt))
|
||||||
|
|
||||||
|
req, err := http.NewRequest("GET", "http://localhost:3000/", nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
m.ServeHTTP(response, req)
|
||||||
|
expect(t, response.Code, http.StatusOK)
|
||||||
|
expect(t, buffer.String(), "[martini] [Static] Serving /martini.go\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Static_Options_Prefix(t *testing.T) {
|
||||||
|
response := httptest.NewRecorder()
|
||||||
|
|
||||||
|
var buffer bytes.Buffer
|
||||||
|
m := &Martini{Injector: inject.New(), action: func() {}, logger: log.New(&buffer, "[martini] ", 0)}
|
||||||
|
m.Map(m.logger)
|
||||||
|
m.Map(defaultReturnHandler())
|
||||||
|
|
||||||
|
// Serve current directory under /public
|
||||||
|
m.Use(Static(".", StaticOptions{Prefix: "/public"}))
|
||||||
|
|
||||||
|
// Check file content behaviour
|
||||||
|
req, err := http.NewRequest("GET", "http://localhost:3000/public/martini.go", nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
m.ServeHTTP(response, req)
|
||||||
|
expect(t, response.Code, http.StatusOK)
|
||||||
|
expect(t, buffer.String(), "[martini] [Static] Serving /martini.go\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Static_Options_Expires(t *testing.T) {
|
||||||
|
response := httptest.NewRecorder()
|
||||||
|
|
||||||
|
var buffer bytes.Buffer
|
||||||
|
m := &Martini{Injector: inject.New(), action: func() {}, logger: log.New(&buffer, "[martini] ", 0)}
|
||||||
|
m.Map(m.logger)
|
||||||
|
m.Map(defaultReturnHandler())
|
||||||
|
|
||||||
|
// Serve current directory under /public
|
||||||
|
m.Use(Static(".", StaticOptions{Expires: func() string { return "46" }}))
|
||||||
|
|
||||||
|
// Check file content behaviour
|
||||||
|
req, err := http.NewRequest("GET", "http://localhost:3000/martini.go", nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
m.ServeHTTP(response, req)
|
||||||
|
expect(t, response.Header().Get("Expires"), "46")
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Static_Redirect(t *testing.T) {
|
||||||
|
response := httptest.NewRecorder()
|
||||||
|
|
||||||
|
m := New()
|
||||||
|
m.Use(Static(".", StaticOptions{Prefix: "/public"}))
|
||||||
|
|
||||||
|
req, err := http.NewRequest("GET", "http://localhost:3000/public", nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
m.ServeHTTP(response, req)
|
||||||
|
expect(t, response.Code, http.StatusFound)
|
||||||
|
expect(t, response.Header().Get("Location"), "/public/")
|
||||||
|
}
|
311
Godeps/_workspace/src/github.com/codegangsta/martini/translations/README_zh_cn.md
generated
vendored
Normal file
311
Godeps/_workspace/src/github.com/codegangsta/martini/translations/README_zh_cn.md
generated
vendored
Normal file
@ -0,0 +1,311 @@
|
|||||||
|
# Martini [![wercker status](https://app.wercker.com/status/174bef7e3c999e103cacfe2770102266 "wercker status")](https://app.wercker.com/project/bykey/174bef7e3c999e103cacfe2770102266) [![GoDoc](https://godoc.org/github.com/codegangsta/martini?status.png)](http://godoc.org/github.com/codegangsta/martini)
|
||||||
|
|
||||||
|
Martini是一个强大为了编写模块化Web应用而生的GO语言框架.
|
||||||
|
|
||||||
|
## 第一个应用
|
||||||
|
|
||||||
|
在你安装了GO语言和设置了你的[GOPATH](http://golang.org/doc/code.html#GOPATH)之后, 创建你的自己的`.go`文件, 这里我们假设它的名字叫做 `server.go`.
|
||||||
|
|
||||||
|
~~~ go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "github.com/codegangsta/martini"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
m := martini.Classic()
|
||||||
|
m.Get("/", func() string {
|
||||||
|
return "Hello world!"
|
||||||
|
})
|
||||||
|
m.Run()
|
||||||
|
}
|
||||||
|
~~~
|
||||||
|
|
||||||
|
然后安装Martini的包. (注意Martini需要Go语言1.1或者以上的版本支持):
|
||||||
|
~~~
|
||||||
|
go get github.com/codegangsta/martini
|
||||||
|
~~~
|
||||||
|
|
||||||
|
最后运行你的服务:
|
||||||
|
~~~
|
||||||
|
go run server.go
|
||||||
|
~~~
|
||||||
|
|
||||||
|
这时你将会有一个Martini的服务监听了, 地址是: `localhost:3000`.
|
||||||
|
|
||||||
|
## 获得帮助
|
||||||
|
|
||||||
|
请加入: [邮件列表](https://groups.google.com/forum/#!forum/martini-go)
|
||||||
|
|
||||||
|
或者可以查看在线演示地址: [演示视频](http://martini.codegangsta.io/#demo)
|
||||||
|
|
||||||
|
## 功能列表
|
||||||
|
* 使用极其简单.
|
||||||
|
* 无侵入式的设计.
|
||||||
|
* 很好的与其他的Go语言包协同使用.
|
||||||
|
* 超赞的路径匹配和路由.
|
||||||
|
* 模块化的设计 - 容易插入功能件,也容易将其拔出来.
|
||||||
|
* 已有很多的中间件可以直接使用.
|
||||||
|
* 框架内已拥有很好的开箱即用的功能支持.
|
||||||
|
* **完全兼容[http.HandlerFunc](http://godoc.org/net/http#HandlerFunc)接口.**
|
||||||
|
|
||||||
|
## 更多中间件
|
||||||
|
更多的中间件和功能组件, 请查看代码仓库: [martini-contrib](https://github.com/martini-contrib).
|
||||||
|
|
||||||
|
## 目录
|
||||||
|
* [核心 Martini](#classic-martini)
|
||||||
|
* [处理器](#handlers)
|
||||||
|
* [路由](#routing)
|
||||||
|
* [服务](#services)
|
||||||
|
* [服务静态文件](#serving-static-files)
|
||||||
|
* [中间件处理器](#middleware-handlers)
|
||||||
|
* [Next()](#next)
|
||||||
|
* [常见问答](#faq)
|
||||||
|
|
||||||
|
## 核心 Martini
|
||||||
|
为了更快速的启用Martini, [martini.Classic()](http://godoc.org/github.com/codegangsta/martini#Classic) 提供了一些默认的方便Web开发的工具:
|
||||||
|
~~~ go
|
||||||
|
m := martini.Classic()
|
||||||
|
// ... middleware and routing goes here
|
||||||
|
m.Run()
|
||||||
|
~~~
|
||||||
|
|
||||||
|
下面是Martini核心已经包含的功能 [martini.Classic()](http://godoc.org/github.com/codegangsta/martini#Classic):
|
||||||
|
* Request/Response Logging (请求/相应日志) - [martini.Logger](http://godoc.org/github.com/codegangsta/martini#Logger)
|
||||||
|
* Panic Recovery (容错) - [martini.Recovery](http://godoc.org/github.com/codegangsta/martini#Recovery)
|
||||||
|
* Static File serving (静态文件服务) - [martini.Static](http://godoc.org/github.com/codegangsta/martini#Static)
|
||||||
|
* Routing (路由) - [martini.Router](http://godoc.org/github.com/codegangsta/martini#Router)
|
||||||
|
|
||||||
|
### 处理器
|
||||||
|
处理器是Martini的灵魂和核心所在. 一个处理器基本上可以是任何的函数:
|
||||||
|
~~~ go
|
||||||
|
m.Get("/", func() {
|
||||||
|
println("hello world")
|
||||||
|
})
|
||||||
|
~~~
|
||||||
|
|
||||||
|
#### 返回值
|
||||||
|
当一个处理器返回结果的时候, Martini将会把返回值作为字符串写入到当前的[http.ResponseWriter](http://godoc.org/net/http#ResponseWriter)里面:
|
||||||
|
~~~ go
|
||||||
|
m.Get("/", func() string {
|
||||||
|
return "hello world" // HTTP 200 : "hello world"
|
||||||
|
})
|
||||||
|
~~~
|
||||||
|
|
||||||
|
另外你也可以选择性的返回多一个状态码:
|
||||||
|
~~~ go
|
||||||
|
m.Get("/", func() (int, string) {
|
||||||
|
return 418, "i'm a teapot" // HTTP 418 : "i'm a teapot"
|
||||||
|
})
|
||||||
|
~~~
|
||||||
|
|
||||||
|
#### 服务的注入
|
||||||
|
处理器是通过反射来调用的. Martini 通过*Dependency Injection* *(依赖注入)* 来为处理器注入参数列表. **这样使得Martini与Go语言的`http.HandlerFunc`接口完全兼容.**
|
||||||
|
|
||||||
|
如果你加入一个参数到你的处理器, Martini将会搜索它参数列表中的服务,并且通过类型判断来解决依赖关系:
|
||||||
|
~~~ go
|
||||||
|
m.Get("/", func(res http.ResponseWriter, req *http.Request) { // res 和 req 是通过Martini注入的
|
||||||
|
res.WriteHeader(200) // HTTP 200
|
||||||
|
})
|
||||||
|
~~~
|
||||||
|
|
||||||
|
下面的这些服务已经被包含在核心Martini中: [martini.Classic()](http://godoc.org/github.com/codegangsta/martini#Classic):
|
||||||
|
* [*log.Logger](http://godoc.org/log#Logger) - Martini的全局日志.
|
||||||
|
* [martini.Context](http://godoc.org/github.com/codegangsta/martini#Context) - http request context (请求上下文).
|
||||||
|
* [martini.Params](http://godoc.org/github.com/codegangsta/martini#Params) - `map[string]string` of named params found by route matching. (名字和参数键值对的参数列表)
|
||||||
|
* [martini.Routes](http://godoc.org/github.com/codegangsta/martini#Routes) - Route helper service. (路由协助处理)
|
||||||
|
* [http.ResponseWriter](http://godoc.org/net/http/#ResponseWriter) - http Response writer interface. (响应结果的流接口)
|
||||||
|
* [*http.Request](http://godoc.org/net/http/#Request) - http Request. (http请求)
|
||||||
|
|
||||||
|
### 路由
|
||||||
|
在Martini中, 路由是一个HTTP方法配对一个URL匹配模型. 每一个路由可以对应一个或多个处理器方法:
|
||||||
|
~~~ go
|
||||||
|
m.Get("/", func() {
|
||||||
|
// 显示
|
||||||
|
})
|
||||||
|
|
||||||
|
m.Patch("/", func() {
|
||||||
|
// 更新
|
||||||
|
})
|
||||||
|
|
||||||
|
m.Post("/", func() {
|
||||||
|
// 创建
|
||||||
|
})
|
||||||
|
|
||||||
|
m.Put("/", func() {
|
||||||
|
// 替换
|
||||||
|
})
|
||||||
|
|
||||||
|
m.Delete("/", func() {
|
||||||
|
// 删除
|
||||||
|
})
|
||||||
|
|
||||||
|
m.Options("/", func() {
|
||||||
|
// http 选项
|
||||||
|
})
|
||||||
|
|
||||||
|
m.NotFound(func() {
|
||||||
|
// 处理 404
|
||||||
|
})
|
||||||
|
~~~
|
||||||
|
|
||||||
|
路由匹配的顺序是按照他们被定义的顺序执行的. 最先被定义的路由将会首先被用户请求匹配并调用.
|
||||||
|
|
||||||
|
路由模型可能包含参数列表, 可以通过[martini.Params](http://godoc.org/github.com/codegangsta/martini#Params)服务来获取:
|
||||||
|
~~~ go
|
||||||
|
m.Get("/hello/:name", func(params martini.Params) string {
|
||||||
|
return "Hello " + params["name"]
|
||||||
|
})
|
||||||
|
~~~
|
||||||
|
|
||||||
|
路由匹配可以通过正则表达式或者glob的形式:
|
||||||
|
~~~ go
|
||||||
|
m.Get("/hello/**", func(params martini.Params) string {
|
||||||
|
return "Hello " + params["_1"]
|
||||||
|
})
|
||||||
|
~~~
|
||||||
|
|
||||||
|
路由处理器可以被相互叠加使用, 例如很有用的地方可以是在验证和授权的时候:
|
||||||
|
~~~ go
|
||||||
|
m.Get("/secret", authorize, func() {
|
||||||
|
// 该方法将会在authorize方法没有输出结果的时候执行.
|
||||||
|
})
|
||||||
|
~~~
|
||||||
|
|
||||||
|
### 服务
|
||||||
|
服务即是被注入到处理器中的参数. 你可以映射一个服务到 *全局* 或者 *请求* 的级别.
|
||||||
|
|
||||||
|
|
||||||
|
#### 全局映射
|
||||||
|
如果一个Martini实现了inject.Injector的接口, 那么映射成为一个服务就非常简单:
|
||||||
|
~~~ go
|
||||||
|
db := &MyDatabase{}
|
||||||
|
m := martini.Classic()
|
||||||
|
m.Map(db) // *MyDatabase 这个服务将可以在所有的处理器中被使用到.
|
||||||
|
// ...
|
||||||
|
m.Run()
|
||||||
|
~~~
|
||||||
|
|
||||||
|
#### 请求级别的映射
|
||||||
|
映射在请求级别的服务可以用[martini.Context](http://godoc.org/github.com/codegangsta/martini#Context)来完成:
|
||||||
|
~~~ go
|
||||||
|
func MyCustomLoggerHandler(c martini.Context, req *http.Request) {
|
||||||
|
logger := &MyCustomLogger{req}
|
||||||
|
c.Map(logger) // 映射成为了 *MyCustomLogger
|
||||||
|
}
|
||||||
|
~~~
|
||||||
|
|
||||||
|
#### 映射值到接口
|
||||||
|
关于服务最强悍的地方之一就是它能够映射服务到接口. 例如说, 假设你想要覆盖[http.ResponseWriter](http://godoc.org/net/http#ResponseWriter)成为一个对象, 那么你可以封装它并包含你自己的额外操作, 你可以如下这样来编写你的处理器:
|
||||||
|
~~~ go
|
||||||
|
func WrapResponseWriter(res http.ResponseWriter, c martini.Context) {
|
||||||
|
rw := NewSpecialResponseWriter(res)
|
||||||
|
c.MapTo(rw, (*http.ResponseWriter)(nil)) // 覆盖 ResponseWriter 成为我们封装过的 ResponseWriter
|
||||||
|
}
|
||||||
|
~~~
|
||||||
|
|
||||||
|
### 服务静态文件
|
||||||
|
[martini.Classic()](http://godoc.org/github.com/codegangsta/martini#Classic) 默认会服务位于你服务器环境根目录下的"public"文件夹.
|
||||||
|
你可以通过加入[martini.Static](http://godoc.org/github.com/codegangsta/martini#Static)的处理器来加入更多的静态文件服务的文件夹.
|
||||||
|
~~~ go
|
||||||
|
m.Use(martini.Static("assets")) // 也会服务静态文件于"assets"的文件夹
|
||||||
|
~~~
|
||||||
|
|
||||||
|
## 中间件处理器
|
||||||
|
中间件处理器是工作于请求和路由之间的. 本质上来说和Martini其他的处理器没有分别. 你可以像如下这样添加一个中间件处理器到它的堆中:
|
||||||
|
~~~ go
|
||||||
|
m.Use(func() {
|
||||||
|
// 做一些中间件该做的事情
|
||||||
|
})
|
||||||
|
~~~
|
||||||
|
|
||||||
|
你可以通过`Handlers`函数对中间件堆有完全的控制. 它将会替换掉之前的任何设置过的处理器:
|
||||||
|
~~~ go
|
||||||
|
m.Handlers(
|
||||||
|
Middleware1,
|
||||||
|
Middleware2,
|
||||||
|
Middleware3,
|
||||||
|
)
|
||||||
|
~~~
|
||||||
|
|
||||||
|
中间件处理器可以非常好处理一些功能,像logging(日志), authorization(授权), authentication(认证), sessions(会话), error pages(错误页面), 以及任何其他的操作需要在http请求发生之前或者之后的:
|
||||||
|
|
||||||
|
~~~ go
|
||||||
|
// 验证api密匙
|
||||||
|
m.Use(func(res http.ResponseWriter, req *http.Request) {
|
||||||
|
if req.Header.Get("X-API-KEY") != "secret123" {
|
||||||
|
res.WriteHeader(http.StatusUnauthorized)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
~~~
|
||||||
|
|
||||||
|
### Next()
|
||||||
|
[Context.Next()](http://godoc.org/github.com/codegangsta/martini#Context)是一个可选的函数用于中间件处理器暂时放弃执行直到其他的处理器都执行完毕. 这样就可以很好的处理在http请求完成后需要做的操作.
|
||||||
|
~~~ go
|
||||||
|
// log 记录请求完成前后 (*译者注: 很巧妙,掌声鼓励.)
|
||||||
|
m.Use(func(c martini.Context, log *log.Logger){
|
||||||
|
log.Println("before a request")
|
||||||
|
|
||||||
|
c.Next()
|
||||||
|
|
||||||
|
log.Println("after a request")
|
||||||
|
})
|
||||||
|
~~~
|
||||||
|
|
||||||
|
## 常见问答
|
||||||
|
|
||||||
|
### 我在哪里可以找到中间件资源?
|
||||||
|
|
||||||
|
可以查看 [martini-contrib](https://github.com/martini-contrib) 项目. 如果看了觉得没有什么好货色, 可以联系martini-contrib的团队成员为你创建一个新的代码资源库.
|
||||||
|
|
||||||
|
* [auth](https://github.com/martini-contrib/auth) - 认证处理器.
|
||||||
|
* [binding](https://github.com/martini-contrib/binding) - 映射/验证raw请求到结构体(structure)里的处理器
|
||||||
|
* [gzip](https://github.com/martini-contrib/gzip) - 加入giz支持的处理器
|
||||||
|
* [render](https://github.com/martini-contrib/render) - 渲染JSON和HTML模板的处理器.
|
||||||
|
* [acceptlang](https://github.com/martini-contrib/acceptlang) - 解析`Accept-Language` HTTP报头的处理器.
|
||||||
|
* [sessions](https://github.com/martini-contrib/sessions) - 提供会话服务支持的处理器.
|
||||||
|
* [strip](https://github.com/martini-contrib/strip) - URL Prefix stripping.
|
||||||
|
* [method](https://github.com/martini-contrib/method) - HTTP method overriding via Header or form fields.
|
||||||
|
* [secure](https://github.com/martini-contrib/secure) - Implements a few quick security wins.
|
||||||
|
* [encoder](https://github.com/martini-contrib/encoder) - Encoder service for rendering data in several formats and content negotiation.
|
||||||
|
|
||||||
|
### 我如何整合到我现有的服务器中?
|
||||||
|
|
||||||
|
由于Martini实现了 `http.Handler`, 所以它可以很简单的应用到现有Go服务器的子集中. 例如说这是一段在Google App Engine中的示例:
|
||||||
|
|
||||||
|
~~~ go
|
||||||
|
package hello
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"github.com/codegangsta/martini"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m := martini.Classic()
|
||||||
|
m.Get("/", func() string {
|
||||||
|
return "Hello world!"
|
||||||
|
})
|
||||||
|
http.Handle("/", m)
|
||||||
|
}
|
||||||
|
~~~
|
||||||
|
|
||||||
|
### 我如何修改port/host?
|
||||||
|
|
||||||
|
Martini的`Run`函数会检查PORT和HOST的环境变量并使用它们. 否则Martini将会默认使用localhost:3000
|
||||||
|
如果想要自定义PORT和HOST, 使用`http.ListenAndServe`函数来代替.
|
||||||
|
|
||||||
|
~~~ go
|
||||||
|
m := martini.Classic()
|
||||||
|
// ...
|
||||||
|
http.ListenAndServe(":8080", m)
|
||||||
|
~~~
|
||||||
|
|
||||||
|
## 贡献
|
||||||
|
Martini项目想要保持简单且干净的代码. 大部分的代码应该贡献到[martini-contrib](https://github.com/martini-contrib)组织中作为一个项目. 如果你想要贡献Martini的核心代码也可以发起一个Pull Request.
|
||||||
|
|
||||||
|
## 关于
|
||||||
|
|
||||||
|
灵感来自于 [express](https://github.com/visionmedia/express) 和 [sinatra](https://github.com/sinatra/sinatra)
|
||||||
|
|
||||||
|
Martini作者 [Code Gangsta](http://codegangsta.io/)
|
||||||
|
译者: [Leon](http://github.com/leonli)
|
1
Godeps/_workspace/src/github.com/codegangsta/martini/wercker.yml
generated
vendored
Normal file
1
Godeps/_workspace/src/github.com/codegangsta/martini/wercker.yml
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
box: wercker/golang@1.1.1
|
Loading…
Reference in New Issue
Block a user