|
@@ -197,37 +197,58 @@ func htons(h uint16) uint16 {
|
|
|
|
|
|
var ntohs = htons
|
|
var ntohs = htons
|
|
|
|
|
|
-func setNumOstreams(fd, num int) error {
|
|
|
|
- param := InitMsg{
|
|
|
|
- NumOstreams: uint16(num),
|
|
|
|
- }
|
|
|
|
- optlen := unsafe.Sizeof(param)
|
|
|
|
- _, _, err := setsockopt(fd, SCTP_INITMSG, uintptr(unsafe.Pointer(¶m)), uintptr(optlen))
|
|
|
|
|
|
+// setInitOpts sets options for an SCTP association initialization
|
|
|
|
+// see https://tools.ietf.org/html/rfc4960#page-25
|
|
|
|
+func setInitOpts(fd int, options InitMsg) error {
|
|
|
|
+ optlen := unsafe.Sizeof(options)
|
|
|
|
+ _, _, err := setsockopt(fd, SCTP_INITMSG, uintptr(unsafe.Pointer(&options)), uintptr(optlen))
|
|
return err
|
|
return err
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+func setNumOstreams(fd, num int) error {
|
|
|
|
+ return setInitOpts(fd, InitMsg{NumOstreams: uint16(num)})
|
|
|
|
+}
|
|
|
|
+
|
|
type SCTPAddr struct {
|
|
type SCTPAddr struct {
|
|
- IP []net.IP
|
|
|
|
- Port int
|
|
|
|
|
|
+ IPAddrs []net.IPAddr
|
|
|
|
+ Port int
|
|
}
|
|
}
|
|
|
|
|
|
func (a *SCTPAddr) ToRawSockAddrBuf() []byte {
|
|
func (a *SCTPAddr) ToRawSockAddrBuf() []byte {
|
|
- buf := []byte{}
|
|
|
|
p := htons(uint16(a.Port))
|
|
p := htons(uint16(a.Port))
|
|
- for _, ip := range a.IP {
|
|
|
|
- if ip.To4() != nil {
|
|
|
|
|
|
+ if len(a.IPAddrs) == 0 { // if a.IPAddrs list is empty - fall back to IPv4 zero addr
|
|
|
|
+ s := syscall.RawSockaddrInet4{
|
|
|
|
+ Family: syscall.AF_INET,
|
|
|
|
+ Port: p,
|
|
|
|
+ }
|
|
|
|
+ copy(s.Addr[:], net.IPv4zero)
|
|
|
|
+ return toBuf(s)
|
|
|
|
+ }
|
|
|
|
+ buf := []byte{}
|
|
|
|
+ for _, ip := range a.IPAddrs {
|
|
|
|
+ ipBytes := ip.IP
|
|
|
|
+ if len(ipBytes) == 0 {
|
|
|
|
+ ipBytes = net.IPv4zero
|
|
|
|
+ }
|
|
|
|
+ if ip4 := ipBytes.To4(); ip4 != nil {
|
|
s := syscall.RawSockaddrInet4{
|
|
s := syscall.RawSockaddrInet4{
|
|
Family: syscall.AF_INET,
|
|
Family: syscall.AF_INET,
|
|
Port: p,
|
|
Port: p,
|
|
}
|
|
}
|
|
- copy(s.Addr[:], ip.To4())
|
|
|
|
|
|
+ copy(s.Addr[:], ip4)
|
|
buf = append(buf, toBuf(s)...)
|
|
buf = append(buf, toBuf(s)...)
|
|
} else {
|
|
} else {
|
|
|
|
+ var scopeid uint32
|
|
|
|
+ ifi, err := net.InterfaceByName(ip.Zone)
|
|
|
|
+ if err == nil {
|
|
|
|
+ scopeid = uint32(ifi.Index)
|
|
|
|
+ }
|
|
s := syscall.RawSockaddrInet6{
|
|
s := syscall.RawSockaddrInet6{
|
|
- Family: syscall.AF_INET6,
|
|
|
|
- Port: p,
|
|
|
|
|
|
+ Family: syscall.AF_INET6,
|
|
|
|
+ Port: p,
|
|
|
|
+ Scope_id: scopeid,
|
|
}
|
|
}
|
|
- copy(s.Addr[:], ip)
|
|
|
|
|
|
+ copy(s.Addr[:], ipBytes)
|
|
buf = append(buf, toBuf(s)...)
|
|
buf = append(buf, toBuf(s)...)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -237,15 +258,15 @@ func (a *SCTPAddr) ToRawSockAddrBuf() []byte {
|
|
func (a *SCTPAddr) String() string {
|
|
func (a *SCTPAddr) String() string {
|
|
var b bytes.Buffer
|
|
var b bytes.Buffer
|
|
|
|
|
|
- for n, i := range a.IP {
|
|
|
|
- if a.IP[n].To4() != nil {
|
|
|
|
|
|
+ for n, i := range a.IPAddrs {
|
|
|
|
+ if i.IP.To4() != nil {
|
|
b.WriteString(i.String())
|
|
b.WriteString(i.String())
|
|
- } else if a.IP[n].To16() != nil {
|
|
|
|
|
|
+ } else if i.IP.To16() != nil {
|
|
b.WriteRune('[')
|
|
b.WriteRune('[')
|
|
b.WriteString(i.String())
|
|
b.WriteString(i.String())
|
|
b.WriteRune(']')
|
|
b.WriteRune(']')
|
|
}
|
|
}
|
|
- if n < len(a.IP)-1 {
|
|
|
|
|
|
+ if n < len(a.IPAddrs)-1 {
|
|
b.WriteRune('/')
|
|
b.WriteRune('/')
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -260,6 +281,7 @@ func ResolveSCTPAddr(network, addrs string) (*SCTPAddr, error) {
|
|
tcpnet := ""
|
|
tcpnet := ""
|
|
switch network {
|
|
switch network {
|
|
case "", "sctp":
|
|
case "", "sctp":
|
|
|
|
+ tcpnet = "tcp"
|
|
case "sctp4":
|
|
case "sctp4":
|
|
tcpnet = "tcp4"
|
|
tcpnet = "tcp4"
|
|
case "sctp6":
|
|
case "sctp6":
|
|
@@ -271,26 +293,26 @@ func ResolveSCTPAddr(network, addrs string) (*SCTPAddr, error) {
|
|
if len(elems) == 0 {
|
|
if len(elems) == 0 {
|
|
return nil, fmt.Errorf("invalid input: %s", addrs)
|
|
return nil, fmt.Errorf("invalid input: %s", addrs)
|
|
}
|
|
}
|
|
- ipaddrs := make([]net.IP, 0, len(elems))
|
|
|
|
|
|
+ ipaddrs := make([]net.IPAddr, 0, len(elems))
|
|
for _, e := range elems[:len(elems)-1] {
|
|
for _, e := range elems[:len(elems)-1] {
|
|
tcpa, err := net.ResolveTCPAddr(tcpnet, e+":")
|
|
tcpa, err := net.ResolveTCPAddr(tcpnet, e+":")
|
|
if err != nil {
|
|
if err != nil {
|
|
return nil, err
|
|
return nil, err
|
|
}
|
|
}
|
|
- ipaddrs = append(ipaddrs, tcpa.IP)
|
|
|
|
|
|
+ ipaddrs = append(ipaddrs, net.IPAddr{IP: tcpa.IP, Zone: tcpa.Zone})
|
|
}
|
|
}
|
|
tcpa, err := net.ResolveTCPAddr(tcpnet, elems[len(elems)-1])
|
|
tcpa, err := net.ResolveTCPAddr(tcpnet, elems[len(elems)-1])
|
|
if err != nil {
|
|
if err != nil {
|
|
return nil, err
|
|
return nil, err
|
|
}
|
|
}
|
|
if tcpa.IP != nil {
|
|
if tcpa.IP != nil {
|
|
- ipaddrs = append(ipaddrs, tcpa.IP)
|
|
|
|
|
|
+ ipaddrs = append(ipaddrs, net.IPAddr{IP: tcpa.IP, Zone: tcpa.Zone})
|
|
} else {
|
|
} else {
|
|
ipaddrs = nil
|
|
ipaddrs = nil
|
|
}
|
|
}
|
|
return &SCTPAddr{
|
|
return &SCTPAddr{
|
|
- IP: ipaddrs,
|
|
|
|
- Port: tcpa.Port,
|
|
|
|
|
|
+ IPAddrs: ipaddrs,
|
|
|
|
+ Port: tcpa.Port,
|
|
}, nil
|
|
}, nil
|
|
}
|
|
}
|
|
|
|
|
|
@@ -357,15 +379,12 @@ func (c *SCTPConn) Read(b []byte) (int, error) {
|
|
}
|
|
}
|
|
|
|
|
|
func (c *SCTPConn) SetInitMsg(numOstreams, maxInstreams, maxAttempts, maxInitTimeout int) error {
|
|
func (c *SCTPConn) SetInitMsg(numOstreams, maxInstreams, maxAttempts, maxInitTimeout int) error {
|
|
- param := InitMsg{
|
|
|
|
|
|
+ return setInitOpts(c.fd(), InitMsg{
|
|
NumOstreams: uint16(numOstreams),
|
|
NumOstreams: uint16(numOstreams),
|
|
MaxInstreams: uint16(maxInstreams),
|
|
MaxInstreams: uint16(maxInstreams),
|
|
MaxAttempts: uint16(maxAttempts),
|
|
MaxAttempts: uint16(maxAttempts),
|
|
MaxInitTimeout: uint16(maxInitTimeout),
|
|
MaxInitTimeout: uint16(maxInitTimeout),
|
|
- }
|
|
|
|
- optlen := unsafe.Sizeof(param)
|
|
|
|
- _, _, err := setsockopt(c.fd(), SCTP_INITMSG, uintptr(unsafe.Pointer(¶m)), uintptr(optlen))
|
|
|
|
- return err
|
|
|
|
|
|
+ })
|
|
}
|
|
}
|
|
|
|
|
|
func (c *SCTPConn) SubscribeEvents(flags int) error {
|
|
func (c *SCTPConn) SubscribeEvents(flags int) error {
|
|
@@ -473,7 +492,7 @@ func (c *SCTPConn) GetDefaultSentParam() (*SndRcvInfo, error) {
|
|
|
|
|
|
func resolveFromRawAddr(ptr unsafe.Pointer, n int) (*SCTPAddr, error) {
|
|
func resolveFromRawAddr(ptr unsafe.Pointer, n int) (*SCTPAddr, error) {
|
|
addr := &SCTPAddr{
|
|
addr := &SCTPAddr{
|
|
- IP: make([]net.IP, n),
|
|
|
|
|
|
+ IPAddrs: make([]net.IPAddr, n),
|
|
}
|
|
}
|
|
|
|
|
|
switch family := (*(*syscall.RawSockaddrAny)(ptr)).Addr.Family; family {
|
|
switch family := (*(*syscall.RawSockaddrAny)(ptr)).Addr.Family; family {
|
|
@@ -484,7 +503,7 @@ func resolveFromRawAddr(ptr unsafe.Pointer, n int) (*SCTPAddr, error) {
|
|
for i := 0; i < n; i++ {
|
|
for i := 0; i < n; i++ {
|
|
a := *(*syscall.RawSockaddrInet4)(unsafe.Pointer(
|
|
a := *(*syscall.RawSockaddrInet4)(unsafe.Pointer(
|
|
uintptr(ptr) + size*uintptr(i)))
|
|
uintptr(ptr) + size*uintptr(i)))
|
|
- addr.IP[i] = a.Addr[:]
|
|
|
|
|
|
+ addr.IPAddrs[i] = net.IPAddr{IP: a.Addr[:]}
|
|
}
|
|
}
|
|
case syscall.AF_INET6:
|
|
case syscall.AF_INET6:
|
|
addr.Port = int(ntohs(uint16((*(*syscall.RawSockaddrInet4)(ptr)).Port)))
|
|
addr.Port = int(ntohs(uint16((*(*syscall.RawSockaddrInet4)(ptr)).Port)))
|
|
@@ -493,7 +512,12 @@ func resolveFromRawAddr(ptr unsafe.Pointer, n int) (*SCTPAddr, error) {
|
|
for i := 0; i < n; i++ {
|
|
for i := 0; i < n; i++ {
|
|
a := *(*syscall.RawSockaddrInet6)(unsafe.Pointer(
|
|
a := *(*syscall.RawSockaddrInet6)(unsafe.Pointer(
|
|
uintptr(ptr) + size*uintptr(i)))
|
|
uintptr(ptr) + size*uintptr(i)))
|
|
- addr.IP[i] = a.Addr[:]
|
|
|
|
|
|
+ var zone string
|
|
|
|
+ ifi, err := net.InterfaceByIndex(int(a.Scope_id))
|
|
|
|
+ if err == nil {
|
|
|
|
+ zone = ifi.Name
|
|
|
|
+ }
|
|
|
|
+ addr.IPAddrs[i] = net.IPAddr{IP: a.Addr[:], Zone: zone}
|
|
}
|
|
}
|
|
default:
|
|
default:
|
|
return nil, fmt.Errorf("unknown address family: %d", family)
|
|
return nil, fmt.Errorf("unknown address family: %d", family)
|