├── .gitignore ├── go.mod ├── codegen ├── generate.sh ├── types_sctp.go └── constants_sctp.go ├── checkptr_test.go ├── LICENSE ├── endian.go ├── example ├── packet │ ├── client │ │ └── main.go │ └── server │ │ └── main.go ├── simple │ ├── client │ │ └── main.go │ └── server │ │ └── main.go └── epoll │ └── epoll.go ├── epoll.go ├── README.md ├── sctp_addr.go ├── sctp_listener.go ├── sctp_constants.go ├── sctp_conn.go ├── test_test.go ├── sctp.go └── sctp_structs.go /.gitignore: -------------------------------------------------------------------------------- 1 | /.idea/ 2 | /codegen/_obj/ 3 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/thebagchi/sctp-go 2 | 3 | go 1.17 4 | -------------------------------------------------------------------------------- /codegen/generate.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | echo "Generating sctp constants from /usr/include/linux/sctp.h" 3 | go tool cgo -godefs -srcdir . constants_sctp.go > ../sctp_constants.go 4 | gofmt -w ../sctp_constants.go 5 | 6 | echo "Generating sctp types from /usr/include/linux/sctp.h" 7 | go tool cgo -godefs -srcdir . types_sctp.go > ../sctp_types.go 8 | gofmt -w ../sctp_types.go -------------------------------------------------------------------------------- /checkptr_test.go: -------------------------------------------------------------------------------- 1 | package sctp_go 2 | 3 | import ( 4 | "fmt" 5 | "syscall" 6 | "testing" 7 | ) 8 | 9 | //go:generate go test -count=1 -race -timeout 30s -run ^TestPtr$ github.com/thebagchi/sctp-go 10 | //go:generate go test -count=1 -gcflags=all=-d=checkptr -timeout 30s -run ^TestPtr$ github.com/thebagchi/sctp-go 11 | 12 | func TestPtr(t *testing.T) { 13 | 14 | addr, err := MakeSCTPAddr("sctp", "::1/127.0.0.1:12345") 15 | if nil != err { 16 | fmt.Println("Error: ", err) 17 | t.FailNow() 18 | } 19 | 20 | server, err := ListenSCTP( 21 | "sctp", 22 | syscall.SOCK_STREAM, 23 | addr, 24 | &SCTPInitMsg{ 25 | NumOutStreams: 0xffff, 26 | MaxInStreams: 0, 27 | MaxAttempts: 0, 28 | MaxInitTimeout: 0, 29 | }, 30 | ) 31 | 32 | if nil != err { 33 | fmt.Println("Error: ", err) 34 | t.FailNow() 35 | } 36 | 37 | defer server.Close() 38 | 39 | if local := server.Addr(); nil != local { 40 | fmt.Println("Addr: ", local) 41 | } else { 42 | fmt.Println("Error: ", err) 43 | t.FailNow() 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Sandeep Bagchi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /endian.go: -------------------------------------------------------------------------------- 1 | package sctp_go 2 | 3 | import ( 4 | "encoding/binary" 5 | ) 6 | 7 | func HostToNetworkShort(number uint16) uint16 { 8 | if endian == binary.LittleEndian { 9 | return (number << 8 & 0xff00) | (number >> 8 & 0x00ff) 10 | } 11 | return number 12 | } 13 | 14 | func NetworkToHostShort(number uint16) uint16 { 15 | if endian == binary.LittleEndian { 16 | return (number << 8 & 0xff00) | (number >> 8 & 0x00ff) 17 | } 18 | return number 19 | } 20 | 21 | func HostToNetwork(number uint32) uint32 { 22 | if endian == binary.LittleEndian { 23 | return uint32(HostToNetworkShort(uint16(number)))<<16 | uint32(HostToNetworkShort(uint16(number>>16))) 24 | } 25 | return number 26 | } 27 | 28 | func NetworkToHost(number uint32) uint32 { 29 | if endian == binary.LittleEndian { 30 | return uint32(NetworkToHostShort(uint16(number)))<<16 | uint32(NetworkToHostShort(uint16(number>>16))) 31 | } 32 | return number 33 | } 34 | 35 | func HostToNetworkLong(number uint64) uint64 { 36 | if endian == binary.LittleEndian { 37 | return uint64(HostToNetwork(uint32(number)))<<32 | uint64(HostToNetwork(uint32(number>>32))) 38 | } 39 | return number 40 | } 41 | 42 | func NetworkToHostLong(number uint64) uint64 { 43 | if endian == binary.LittleEndian { 44 | return uint64(NetworkToHost(uint32(number)))<<32 | uint64(NetworkToHost(uint32(number>>32))) 45 | } 46 | return number 47 | } 48 | -------------------------------------------------------------------------------- /example/packet/client/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "syscall" 7 | 8 | sctp "github.com/thebagchi/sctp-go" 9 | ) 10 | 11 | func main() { 12 | local, err := sctp.MakeSCTPAddr("sctp4", "127.0.0.1:54321") 13 | if nil != err { 14 | fmt.Println("Error: ", err) 15 | os.Exit(1) 16 | } 17 | remote, err := sctp.MakeSCTPAddr("sctp4", "127.0.0.1:12345") 18 | if nil != err { 19 | fmt.Println("Error: ", err) 20 | os.Exit(2) 21 | } 22 | 23 | client, err := sctp.ListenSCTP( 24 | "sctp4", 25 | syscall.SOCK_SEQPACKET, 26 | local, 27 | &sctp.SCTPInitMsg{ 28 | NumOutStreams: 0xffff, 29 | MaxInStreams: 0, 30 | MaxAttempts: 0, 31 | MaxInitTimeout: 0, 32 | }, 33 | ) 34 | if nil != err { 35 | fmt.Println("Error: ", err) 36 | os.Exit(3) 37 | } 38 | 39 | defer client.Close() 40 | assoc, err := client.Connect(remote) 41 | if nil != err { 42 | fmt.Println("Error: ", err) 43 | os.Exit(4) 44 | } 45 | 46 | length, err := client.SendMsg( 47 | []byte("HELLO WORLD"), 48 | &sctp.SCTPSndRcvInfo{ 49 | AssocId: int32(assoc), 50 | Ppid: 0, 51 | Stream: 0, 52 | Flags: 0, 53 | }, 54 | ) 55 | if nil != err { 56 | fmt.Println("Error: ", err) 57 | } else { 58 | fmt.Println("Sent bytes: ", length) 59 | } 60 | 61 | err = client.Disconnect(assoc) 62 | if nil != err { 63 | fmt.Println("Error: ", err) 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /example/simple/client/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/hex" 5 | "fmt" 6 | "os" 7 | 8 | sctp "github.com/thebagchi/sctp-go" 9 | ) 10 | 11 | func main() { 12 | local, err := sctp.MakeSCTPAddr("sctp4", "127.0.0.1:54321") 13 | if nil != err { 14 | fmt.Println("Error: ", err) 15 | os.Exit(1) 16 | } 17 | remote, err := sctp.MakeSCTPAddr("sctp4", "127.0.0.1:12345") 18 | if nil != err { 19 | fmt.Println("Error: ", err) 20 | os.Exit(2) 21 | } 22 | conn, err := sctp.DialSCTP( 23 | "sctp4", 24 | local, 25 | remote, 26 | &sctp.SCTPInitMsg{ 27 | NumOutStreams: 0xFFFF, 28 | MaxInStreams: 0, 29 | MaxAttempts: 0, 30 | MaxInitTimeout: 0, 31 | }, 32 | ) 33 | if nil != err { 34 | fmt.Println("Error: ", err) 35 | os.Exit(3) 36 | } 37 | defer conn.Close() 38 | 39 | if init, err := conn.GetInitMsg(); nil == err { 40 | fmt.Println(hex.Dump(sctp.Pack(init))) 41 | } 42 | 43 | if peer, err := conn.GetPrimaryPeerAddr(); nil == err { 44 | fmt.Println("Peer: ", peer) 45 | } else { 46 | fmt.Println("Error: ", err) 47 | } 48 | 49 | if remote := conn.RemoteAddr(); nil != remote { 50 | fmt.Println("Peer: ", remote) 51 | } else { 52 | fmt.Println("Error: remote addr not received") 53 | } 54 | 55 | if local := conn.LocalAddr(); nil != local { 56 | fmt.Println("Local: ", local) 57 | } else { 58 | fmt.Println("Error: local addr not received") 59 | } 60 | 61 | length, err := conn.SendMsg([]byte("HELLO WORLD"), nil) 62 | if nil != err { 63 | fmt.Println("Error: ", err) 64 | } else { 65 | fmt.Println("Sent bytes", length) 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /example/simple/server/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/hex" 5 | "fmt" 6 | "os" 7 | "syscall" 8 | 9 | sctp "github.com/thebagchi/sctp-go" 10 | ) 11 | 12 | func HandleClient(conn *sctp.SCTPConn) { 13 | if nil == conn { 14 | return 15 | } 16 | var ( 17 | data = make([]byte, 8192) 18 | flag = 0 19 | ) 20 | for { 21 | info := &sctp.SCTPSndRcvInfo{} 22 | len, err := conn.RecvMsg(data, info, &flag) 23 | if nil != err { 24 | fmt.Println("Error: ", err) 25 | break 26 | } 27 | if len == 0 { 28 | fmt.Println("Connection terminated!!!") 29 | break 30 | } else { 31 | fmt.Println("Rcvd bytes: ", len) 32 | buffer := data[:len] 33 | fmt.Println(hex.Dump(buffer)) 34 | fmt.Println(hex.Dump(sctp.Pack(info))) 35 | } 36 | } 37 | } 38 | 39 | func main() { 40 | 41 | addr, err := sctp.MakeSCTPAddr("sctp4", "127.0.0.1:12345") 42 | if nil != err { 43 | fmt.Println("Error: ", err) 44 | os.Exit(1) 45 | } 46 | 47 | server, err := sctp.ListenSCTP( 48 | "sctp4", 49 | syscall.SOCK_STREAM, 50 | addr, 51 | &sctp.SCTPInitMsg{ 52 | NumOutStreams: 0xffff, 53 | MaxInStreams: 0, 54 | MaxAttempts: 0, 55 | MaxInitTimeout: 0, 56 | }, 57 | ) 58 | if nil != err { 59 | fmt.Println("Error: ", err) 60 | os.Exit(2) 61 | } 62 | 63 | defer server.Close() 64 | 65 | if local := server.Addr(); nil != local { 66 | fmt.Println("Addr: ", local) 67 | } else { 68 | fmt.Println("Error: local addr not received") 69 | } 70 | 71 | for { 72 | conn, err := server.AcceptSCTP() 73 | if nil != err { 74 | fmt.Println("Error: ", err) 75 | continue 76 | } 77 | if remote := conn.RemoteAddr(); nil != remote { 78 | fmt.Println("New connection from: ", remote) 79 | } 80 | go HandleClient(conn) 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /example/epoll/epoll.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "syscall" 6 | "time" 7 | 8 | sctp "github.com/thebagchi/sctp-go" 9 | ) 10 | 11 | func main() { 12 | 13 | if err := sctp.GetPoller().Init(); nil != err { 14 | fmt.Println(err.Error()) 15 | return 16 | } 17 | 18 | defer sctp.GetPoller().Finalize() 19 | 20 | address := "127.0.0.1:12345" 21 | addr, err := sctp.MakeSCTPAddr("sctp", address) 22 | if nil != err { 23 | fmt.Println(err.Error()) 24 | return 25 | } 26 | receiver, err := sctp.ListenSCTP( 27 | "sctp", 28 | syscall.SOCK_SEQPACKET, 29 | addr, 30 | &sctp.SCTPInitMsg{ 31 | NumOutStreams: 10, 32 | MaxInStreams: 10, 33 | MaxAttempts: 10, 34 | MaxInitTimeout: 0, 35 | }, 36 | ) 37 | if nil != err { 38 | fmt.Println(err.Error()) 39 | return 40 | } 41 | events, err := receiver.GetEventSubscribe() 42 | if nil != err { 43 | fmt.Println("Error: ", err) 44 | } 45 | if nil != events { 46 | events.DataIoEvent = 1 47 | events.AssociationEvent = 1 48 | events.ShutdownEvent = 1 49 | err = receiver.SetEventSubscribe(events) 50 | if nil != err { 51 | fmt.Println("Error: ", err) 52 | } 53 | } 54 | go func() { 55 | fmt.Println("Registering fd: ", receiver.FD()) 56 | sctp.GetPoller().Add(receiver.FD(), func() { 57 | info := &sctp.SCTPSndRcvInfo{} 58 | flag := 0 59 | data := make([]byte, 8192) 60 | _, err := receiver.RecvMsg(data, info, &flag) 61 | if err != nil { 62 | fmt.Println("Error: ", err) 63 | } 64 | }) 65 | sctp.GetPoller().Loop() 66 | }() 67 | fmt.Println("sctp receiver started: ", time.Now()) 68 | time.Sleep(30 * time.Second) 69 | fmt.Println("sctp receiver closing: ", time.Now()) 70 | sctp.GetPoller().Del(receiver.FD()) 71 | err = receiver.Close() 72 | if err != nil { 73 | fmt.Println(err.Error()) 74 | return 75 | } 76 | fmt.Println("sctp receiver closed") 77 | time.Sleep(60 * time.Second) 78 | } 79 | -------------------------------------------------------------------------------- /example/packet/server/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/hex" 5 | "fmt" 6 | "os" 7 | "syscall" 8 | 9 | sctp "github.com/thebagchi/sctp-go" 10 | ) 11 | 12 | func main() { 13 | addr, err := sctp.MakeSCTPAddr("sctp4", "127.0.0.1:12345") 14 | if nil != err { 15 | fmt.Println("Error: ", err) 16 | os.Exit(1) 17 | } 18 | 19 | server, err := sctp.ListenSCTP( 20 | "sctp4", 21 | syscall.SOCK_SEQPACKET, 22 | addr, 23 | &sctp.SCTPInitMsg{ 24 | NumOutStreams: 0xffff, 25 | MaxInStreams: 0, 26 | MaxAttempts: 0, 27 | MaxInitTimeout: 0, 28 | }, 29 | ) 30 | 31 | if nil != err { 32 | fmt.Println("Error: ", err) 33 | os.Exit(2) 34 | } 35 | 36 | defer server.Close() 37 | 38 | if local := server.Addr(); nil != local { 39 | fmt.Println("Addr: ", local) 40 | } else { 41 | fmt.Println("Error: local addr not received") 42 | } 43 | 44 | events, err := server.GetEventSubscribe() 45 | if nil != err { 46 | fmt.Println("Error: ", err) 47 | } 48 | if nil != events { 49 | events.DataIoEvent = 1 50 | events.AssociationEvent = 1 51 | events.ShutdownEvent = 1 52 | 53 | err = server.SetEventSubscribe(events) 54 | if nil != err { 55 | fmt.Println("Error: ", err) 56 | } 57 | } 58 | { 59 | var ( 60 | data = make([]byte, 8192) 61 | flag = 0 62 | ) 63 | for { 64 | info := &sctp.SCTPSndRcvInfo{} 65 | len, err := server.RecvMsg(data, info, &flag) 66 | if nil != err { 67 | fmt.Println("Error: ", err) 68 | break 69 | } 70 | if len == 0 { 71 | fmt.Println("Connection terminated!!!") 72 | break 73 | } else { 74 | if flag&sctp.SCTP_MSG_NOTIFICATION > 0 { 75 | notification, err := sctp.ParseNotification(data[:len]) 76 | if nil != err { 77 | fmt.Println("Error: ", err) 78 | } else { 79 | fmt.Println( 80 | "Notification received: ", 81 | sctp.NotificationName(notification.GetType()), 82 | notification.GetType(), 83 | ) 84 | if notification.GetType() == sctp.SCTP_ASSOC_CHANGE { 85 | if event, ok := notification.(*sctp.SCTPAssocChange); ok { 86 | fmt.Println(event.State, event.Flags, event.AssocId) 87 | } 88 | } 89 | } 90 | } else { 91 | fmt.Println("Rcvd bytes: ", len) 92 | buffer := data[:len] 93 | fmt.Println(hex.Dump(buffer)) 94 | fmt.Println(hex.Dump(sctp.Pack(info))) 95 | } 96 | } 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /epoll.go: -------------------------------------------------------------------------------- 1 | package sctp_go 2 | 3 | import ( 4 | "errors" 5 | "sync" 6 | "sync/atomic" 7 | "syscall" 8 | ) 9 | 10 | const ( 11 | MaxNumberOfEvents = 64 12 | ) 13 | 14 | // Callback represents a function that handles epoll events for a file descriptor. 15 | type Callback func() 16 | 17 | // Poller manages epoll-based event polling for file descriptors with associated callbacks. 18 | type Poller struct { 19 | descriptor atomic.Int32 20 | callbacks sync.Map 21 | } 22 | 23 | var ( 24 | poller *Poller = nil 25 | ) 26 | 27 | func init() { 28 | poller = &Poller{} 29 | poller.descriptor.Store(-1) 30 | } 31 | 32 | // GetPoller returns the global singleton poller instance. 33 | func GetPoller() *Poller { 34 | return poller 35 | } 36 | 37 | // Init initializes the epoll instance by creating an epoll file descriptor. 38 | // Returns an error if already initialized. 39 | func (p *Poller) Init() error { 40 | if p.IsInitialized() { 41 | return errors.New("poller already initialized") 42 | } 43 | descriptor, err := syscall.EpollCreate1(0) 44 | if err != nil { 45 | return err 46 | } 47 | p.descriptor.Store(int32(descriptor)) 48 | return nil 49 | } 50 | 51 | // Finalize closes the epoll file descriptor if initialized. 52 | func (p *Poller) Finalize() { 53 | descriptor := p.descriptor.Load() 54 | if descriptor != -1 { 55 | syscall.Close(int(descriptor)) 56 | p.descriptor.Store(-1) 57 | } 58 | } 59 | 60 | // IsInitialized checks if the poller has been initialized with a valid epoll descriptor. 61 | func (p *Poller) IsInitialized() bool { 62 | return p.descriptor.Load() != -1 63 | } 64 | 65 | // Add registers a file descriptor with the poller and associates it with a callback function. 66 | // Returns an error if the file descriptor is already registered. 67 | func (p *Poller) Add(fd int, cb Callback) error { 68 | // Check if already registered 69 | if _, exists := p.callbacks.Load(fd); exists { 70 | return errors.New("file descriptor already registered") 71 | } 72 | 73 | descriptor := p.descriptor.Load() 74 | err := syscall.EpollCtl(int(descriptor), syscall.EPOLL_CTL_ADD, fd, 75 | &syscall.EpollEvent{ 76 | Fd: int32(fd), 77 | Events: syscall.EPOLLIN, 78 | }, 79 | ) 80 | if err != nil { 81 | return err 82 | } 83 | p.callbacks.Store(fd, cb) 84 | return nil 85 | } 86 | 87 | // Del removes a file descriptor from the poller and deletes its associated callback. 88 | // Returns an error if the file descriptor is not registered. 89 | func (p *Poller) Del(fd int) error { 90 | // Check if registered 91 | if _, exists := p.callbacks.Load(fd); !exists { 92 | return errors.New("file descriptor not registered") 93 | } 94 | 95 | p.callbacks.Delete(fd) 96 | descriptor := p.descriptor.Load() 97 | return syscall.EpollCtl(int(descriptor), syscall.EPOLL_CTL_DEL, fd, nil) 98 | } 99 | 100 | // Loop runs the event loop, waiting for epoll events and executing associated callbacks. 101 | // The loop continues until an error occurs or the poller is not initialized. 102 | func (p *Poller) Loop() { 103 | if !p.IsInitialized() { 104 | return 105 | } 106 | 107 | events := make([]syscall.EpollEvent, MaxNumberOfEvents) 108 | descriptor := p.descriptor.Load() 109 | 110 | for { 111 | n, err := syscall.EpollWait(int(descriptor), events, 100) 112 | if err != nil { 113 | if err == syscall.EINTR { 114 | continue 115 | } 116 | // break on any other error 117 | break 118 | } 119 | for i := 0; i < n; i++ { 120 | fd := events[i].Fd 121 | if callback, ok := p.callbacks.Load(int(fd)); ok { 122 | if handle, ok := callback.(Callback); ok { 123 | handle() 124 | } 125 | } 126 | } 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # sctp-go 2 | 3 | [![Go Version](https://img.shields.io/badge/go-%3E%3D1.17-blue.svg)](https://golang.org/) 4 | [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) 5 | 6 | A Go library for implementing the Stream Control Transmission Protocol (SCTP) in Go applications. SCTP is a transport-layer protocol that provides reliable, message-oriented data transfer with features like multi-streaming, multi-homing, and congestion control. 7 | 8 | ## Features 9 | 10 | - Full SCTP protocol implementation 11 | - Support for both IPv4 and IPv6 12 | - Multi-streaming and multi-homing capabilities 13 | - Connection-oriented and message-oriented communication 14 | - Integration with Go's net package interfaces 15 | - Comprehensive test suite 16 | 17 | ## Installation 18 | 19 | ```bash 20 | go get github.com/thebagchi/sctp-go 21 | ``` 22 | 23 | ## Usage 24 | 25 | ### Basic Client 26 | 27 | ```go 28 | package main 29 | 30 | import ( 31 | "fmt" 32 | "os" 33 | 34 | sctp "github.com/thebagchi/sctp-go" 35 | ) 36 | 37 | func main() { 38 | local, err := sctp.MakeSCTPAddr("sctp4", "127.0.0.1:54321") 39 | if err != nil { 40 | fmt.Println("Error:", err) 41 | os.Exit(1) 42 | } 43 | 44 | remote, err := sctp.MakeSCTPAddr("sctp4", "127.0.0.1:12345") 45 | if err != nil { 46 | fmt.Println("Error:", err) 47 | os.Exit(1) 48 | } 49 | 50 | conn, err := sctp.DialSCTP( 51 | "sctp4", 52 | local, 53 | remote, 54 | &sctp.SCTPInitMsg{ 55 | NumOutStreams: 0xFFFF, 56 | MaxInStreams: 0, 57 | MaxAttempts: 0, 58 | MaxInitTimeout: 0, 59 | }, 60 | ) 61 | if err != nil { 62 | fmt.Println("Error:", err) 63 | os.Exit(1) 64 | } 65 | defer conn.Close() 66 | 67 | // Use the connection... 68 | } 69 | ``` 70 | 71 | ### Basic Server 72 | 73 | ```go 74 | package main 75 | 76 | import ( 77 | "fmt" 78 | "os" 79 | "syscall" 80 | 81 | sctp "github.com/thebagchi/sctp-go" 82 | ) 83 | 84 | func main() { 85 | addr, err := sctp.MakeSCTPAddr("sctp4", "127.0.0.1:12345") 86 | if err != nil { 87 | fmt.Println("Error:", err) 88 | os.Exit(1) 89 | } 90 | 91 | server, err := sctp.ListenSCTP("sctp4", syscall.SOCK_STREAM, addr) 92 | if err != nil { 93 | fmt.Println("Error:", err) 94 | os.Exit(1) 95 | } 96 | defer server.Close() 97 | 98 | for { 99 | conn, err := server.Accept() 100 | if err != nil { 101 | fmt.Println("Error:", err) 102 | continue 103 | } 104 | 105 | go handleConnection(conn.(*sctp.SCTPConn)) 106 | } 107 | } 108 | 109 | func handleConnection(conn *sctp.SCTPConn) { 110 | defer conn.Close() 111 | // Handle the connection... 112 | } 113 | ``` 114 | 115 | ## Examples 116 | 117 | The `example/` directory contains several example implementations: 118 | 119 | - **Simple**: Basic client-server communication (`example/simple/`) 120 | - **Packet**: Sequential packet examples (`example/packet/`) 121 | - **Epoll**: Epoll-based implementation (`example/epoll/`) 122 | 123 | To run the simple server: 124 | 125 | ```bash 126 | go run example/simple/server/main.go 127 | ``` 128 | 129 | To run the simple client: 130 | 131 | ```bash 132 | go run example/simple/client/main.go 133 | ``` 134 | 135 | ## API Overview 136 | 137 | ### Connection Management 138 | - `DialSCTP()` - Establish an SCTP connection 139 | - `ListenSCTP()` - Create an SCTP listener 140 | - `Accept()` - Accept incoming connections 141 | 142 | ### Address Handling 143 | - `MakeSCTPAddr()` - Create SCTP addresses 144 | - `ResolveSCTPAddr()` - Resolve hostnames to SCTP addresses 145 | 146 | ### Data Transfer 147 | - `SendMsg()` - Send messages with stream information 148 | - `RecvMsg()` - Receive messages with stream information 149 | 150 | ### Connection Information 151 | - `GetInitMsg()` - Get initialization message 152 | - `GetPrimaryPeerAddr()` - Get primary peer address 153 | - `RemoteAddr()` / `LocalAddr()` - Get connection addresses 154 | 155 | ## Testing 156 | 157 | Run the test suite: 158 | 159 | ```bash 160 | go test 161 | ``` 162 | 163 | Run with race detection: 164 | 165 | ```bash 166 | go test -race 167 | ``` 168 | 169 | ## Requirements 170 | 171 | - Go 1.17 or later 172 | - Linux kernel with SCTP support (most modern distributions) 173 | 174 | ## License 175 | 176 | This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. 177 | 178 | ## Contributing 179 | 180 | Contributions are welcome! Please feel free to submit a Pull Request. 181 | -------------------------------------------------------------------------------- /codegen/types_sctp.go: -------------------------------------------------------------------------------- 1 | // +build ignore 2 | 3 | package sctp_go 4 | 5 | //#include 6 | //#include 7 | //#include 8 | //#include 9 | //#include 10 | //typedef struct iovec IoVector; 11 | //typedef struct msghdr MsgHeader; 12 | //typedef struct cmsghdr CMsgHeader; 13 | //typedef struct in_addr InAddr; 14 | //typedef struct in6_addr In6Addr; 15 | //typedef struct sockaddr_in6 SockAddrIn6; 16 | //typedef struct sockaddr_in SockAddrIn; 17 | //typedef struct sockaddr SockAddr; 18 | //typedef struct sockaddr_storage SockAddrStorage; 19 | //typedef struct sctp_sndrcvinfo SCTPSndRcvInfo; 20 | //typedef struct sctp_initmsg SCTPInitMsg; 21 | //typedef struct sctp_sndinfo SCTPSndInfo; 22 | //typedef struct sctp_rcvinfo SCTPRcvInfo; 23 | //typedef struct sctp_nxtinfo SCTPNxtInfo; 24 | //typedef struct sctp_prinfo SCTPPrInfo; 25 | //typedef struct sctp_authinfo SCTPAuthInfo; 26 | //typedef struct sctp_assoc_change SCTPAssocChange; 27 | //typedef struct sctp_paddr_change SCTPPAddrChange; 28 | //typedef struct sctp_remote_error SCTPRemoteError; 29 | //typedef struct sctp_send_failed SCTPSendFailed; 30 | //typedef struct sctp_shutdown_event SCTPShutdownEvent; 31 | //typedef struct sctp_adaptation_event SCTPAdaptationEvent; 32 | //typedef struct sctp_pdapi_event SCTPPDApiEvent; 33 | //typedef struct sctp_authkey_event SCTPAuthKeyEvent; 34 | //typedef struct sctp_sender_dry_event SCTPSenderDryEvent; 35 | //typedef struct sctp_stream_reset_event SCTPStreamResetEvent; 36 | //typedef struct sctp_assoc_reset_event SCTPAssocResetEvent; 37 | //typedef struct sctp_stream_change_event SCTPStreamChangeEvent; 38 | //typedef struct sctp_event_subscribe SCTPEventSubscribe; 39 | //typedef union sctp_notification SCTPNotification; 40 | //typedef sctp_cmsg_data_t SCTPCmsgData; 41 | //typedef struct sn_header { 42 | // __u16 sn_type; 43 | // __u16 sn_flags; 44 | // __u32 sn_length; 45 | //} SCTPNotificationHeader; 46 | //typedef struct sctp_rtoinfo SCTPRTOInfo; 47 | //typedef struct sctp_assocparams SCTPAssocParams; 48 | //typedef struct sctp_setpeerprim SCTPSetPeerPrimary; 49 | //typedef struct sctp_prim SCTPPrimaryAddr; 50 | //typedef struct sctp_setadaptation SCTPSetAdaptation; 51 | //typedef struct sctp_paddrparams SCTPPeerAddrParams; 52 | //typedef struct sctp_authchunk SCTPAuthChunk; 53 | //typedef struct sctp_hmacalgo SCTPHmacAlgo; 54 | //typedef struct sctp_authkey SCTPAuthKey; 55 | //typedef struct sctp_authkeyid SCTPAuthKeyId; 56 | //typedef struct sctp_sack_info SCTPSackInfo; 57 | //typedef struct sctp_assoc_value SCTPAssocValue; 58 | //typedef struct sctp_stream_value SCTPStreamValue; 59 | //typedef struct sctp_paddrinfo SCTPPeerAddrInfo; 60 | //typedef struct sctp_status SCTPStatus; 61 | //typedef struct sctp_authchunks SCTPAuthChunks; 62 | //typedef struct sctp_assoc_ids SCTPAssocIds; 63 | //typedef struct sctp_getaddrs_old SCTPGetAddrsOld; 64 | //typedef struct sctp_getaddrs SCTPGetAddrs; 65 | //typedef struct sctp_assoc_stats SCTPAssocStats; 66 | //typedef sctp_peeloff_arg_t SCTPPeelOffArg; 67 | //typedef sctp_peeloff_flags_arg_t SCTPPeelOffFlagsArg; 68 | //typedef struct sctp_paddrthlds SCTPPeerAddrThresholds; 69 | //typedef struct sctp_prstatus SCTPPRStatus; 70 | //typedef struct sctp_default_prinfo SCTPDefaultPRInfo; 71 | //typedef struct sctp_info SCTPInfo; 72 | //typedef struct sctp_reset_streams SCTPResetStreams; 73 | //typedef struct sctp_add_streams SCTPAddStreams; 74 | //typedef struct sctp_event SCTPEvent; 75 | import "C" 76 | 77 | type IoVector C.IoVector 78 | type MsgHeader C.MsgHeader 79 | type CMsgHeader C.CMsgHeader 80 | type InAddr C.InAddr 81 | type In6Addr C.In6Addr 82 | type SockAddrIn6 C.SockAddrIn6 83 | type SockAddrIn C.SockAddrIn 84 | type SockAddr C.SockAddr 85 | type SockAddrStorage C.SockAddrStorage 86 | type SCTPAssocId C.sctp_assoc_t 87 | type SCTPInitMsg C.SCTPInitMsg 88 | type SCTPSndRcvInfo C.SCTPSndRcvInfo 89 | type SCTPSndInfo C.SCTPSndInfo 90 | type SCTPRcvInfo C.SCTPRcvInfo 91 | type SCTPNxtInfo C.SCTPNxtInfo 92 | type SCTPPrInfo C.SCTPPrInfo 93 | type SCTPAuthInfo C.SCTPAuthInfo 94 | type SCTPCmsgData C.SCTPCmsgData 95 | type SCTPAssocChange C.SCTPAssocChange 96 | type SCTPPAddrChange C.SCTPPAddrChange 97 | type SCTPRemoteError C.SCTPRemoteError 98 | type SCTPSendFailed C.SCTPSendFailed 99 | type SCTPShutdownEvent C.SCTPShutdownEvent 100 | type SCTPAdaptationEvent C.SCTPAdaptationEvent 101 | type SCTPPDApiEvent C.SCTPPDApiEvent 102 | type SCTPAuthKeyEvent C.SCTPAuthKeyEvent 103 | type SCTPSenderDryEvent C.SCTPSenderDryEvent 104 | type SCTPStreamResetEvent C.SCTPStreamResetEvent 105 | type SCTPAssocResetEvent C.SCTPAssocResetEvent 106 | type SCTPStreamChangeEvent C.SCTPStreamChangeEvent 107 | type SCTPEventSubscribe C.SCTPEventSubscribe 108 | type SCTPNotification C.SCTPNotification 109 | type SCTPNotificationHeader C.SCTPNotificationHeader 110 | type SCTPRTOInfo C.SCTPRTOInfo 111 | type SCTPAssocParams C.SCTPAssocParams 112 | type SCTPSetPeerPrimary C.SCTPSetPeerPrimary 113 | type SCTPPrimaryAddr C.SCTPPrimaryAddr 114 | type SCTPSetAdaptation C.SCTPSetAdaptation 115 | type SCTPPeerAddrParams C.SCTPPeerAddrParams 116 | type SCTPAuthChunk C.SCTPAuthChunk 117 | type SCTPHmacAlgo C.SCTPHmacAlgo 118 | type SCTPAuthKey C.SCTPAuthKey 119 | type SCTPAuthKeyId C.SCTPAuthKeyId 120 | type SCTPSackInfo C.SCTPSackInfo 121 | type SCTPAssocValue C.SCTPAssocValue 122 | type SCTPStreamValue C.SCTPStreamValue 123 | type SCTPPeerAddrInfo C.SCTPPeerAddrInfo 124 | type SCTPStatus C.SCTPStatus 125 | type SCTPAuthChunks C.SCTPAuthChunks 126 | type SCTPAssocIds C.SCTPAssocIds 127 | type SCTPGetAddrsOld C.SCTPGetAddrsOld 128 | type SCTPGetAddrs C.SCTPGetAddrs 129 | type SCTPAssocStats C.SCTPAssocStats 130 | type SCTPPeelOffArg C.SCTPPeelOffArg 131 | type SCTPPeelOffFlagsArg C.SCTPPeelOffFlagsArg 132 | type SCTPPeerAddrThresholds C.SCTPPeerAddrThresholds 133 | type SCTPPRStatus C.SCTPPRStatus 134 | type SCTPDefaultPRInfo C.SCTPDefaultPRInfo 135 | type SCTPInfo C.SCTPInfo 136 | type SCTPResetStreams C.SCTPResetStreams 137 | type SCTPAddStreams C.SCTPAddStreams 138 | type SCTPEvent C.SCTPEvent -------------------------------------------------------------------------------- /sctp_addr.go: -------------------------------------------------------------------------------- 1 | package sctp_go 2 | 3 | import ( 4 | "bytes" 5 | "encoding/binary" 6 | "net" 7 | "strconv" 8 | "strings" 9 | "syscall" 10 | "unsafe" 11 | ) 12 | 13 | type SCTPAddr struct { 14 | addresses []net.IP 15 | port int 16 | } 17 | 18 | // Address returns the address part of the SCTPAddr without the port. 19 | // Multiple addresses are separated by '/'. 20 | func (addr *SCTPAddr) Address() string { 21 | if len(addr.addresses) == 0 { 22 | return "" 23 | } 24 | var b strings.Builder 25 | b.Grow(64) 26 | for n, address := range addr.addresses { 27 | if n > 0 { 28 | b.WriteByte('/') 29 | } 30 | if ip4 := address.To4(); ip4 != nil { 31 | b.WriteString(ip4.String()) 32 | continue 33 | } 34 | if ip6 := address.To16(); ip6 != nil { 35 | b.WriteByte('[') 36 | b.WriteString(address.String()) 37 | b.WriteByte(']') 38 | } 39 | } 40 | return b.String() 41 | } 42 | 43 | // Port returns the port number of the SCTPAddr. 44 | func (addr *SCTPAddr) Port() int { 45 | return addr.port 46 | } 47 | 48 | // IsV6Only reports whether the SCTPAddr contains only IPv6 addresses. 49 | func (addr *SCTPAddr) IsV6Only() bool { 50 | for _, addr := range addr.addresses { 51 | if addr.To16() == nil { 52 | return false 53 | } 54 | } 55 | return true 56 | } 57 | 58 | // IsV4Only reports whether the SCTPAddr contains only IPv4 addresses. 59 | func (addr *SCTPAddr) IsV4Only() bool { 60 | for _, addr := range addr.addresses { 61 | if addr.To4() == nil { 62 | return false 63 | } 64 | } 65 | return true 66 | } 67 | 68 | // String returns the string representation of the SCTPAddr in the format "address:port". 69 | // Multiple addresses are separated by '/', and IPv6 addresses are enclosed in brackets. 70 | func (addr *SCTPAddr) String() string { 71 | var b strings.Builder 72 | b.Grow(128) 73 | for n, address := range addr.addresses { 74 | if n > 0 { 75 | b.WriteByte('/') 76 | } 77 | if ip4 := address.To4(); ip4 != nil { 78 | b.WriteString(ip4.String()) 79 | } 80 | if ip6 := address.To16(); ip6 != nil { 81 | b.WriteByte('[') 82 | b.WriteString(address.String()) 83 | b.WriteByte(']') 84 | } 85 | } 86 | b.WriteByte(':') 87 | b.WriteString(strconv.Itoa(addr.port)) 88 | return b.String() 89 | } 90 | 91 | // Network returns the network type, which is always "sctp". 92 | func (addr *SCTPAddr) Network() string { 93 | return "sctp" 94 | } 95 | 96 | // Addr returns the SCTPAddr itself, implementing the net.Addr interface. 97 | func (addr *SCTPAddr) Addr() net.Addr { 98 | if addr == nil { 99 | return nil 100 | } 101 | return addr 102 | } 103 | 104 | // MakeSockaddr converts an SCTPAddr to a byte slice containing socket address structures 105 | // suitable for use with SCTP system calls. It handles both IPv4 and IPv6 addresses. 106 | func MakeSockaddr(addr *SCTPAddr) []byte { 107 | if len(addr.addresses) == 0 { 108 | return nil 109 | } 110 | // Pre-calculate buffer capacity and cache port conversion 111 | port := htons(uint16(addr.port)) 112 | capacity := 0 113 | for _, address := range addr.addresses { 114 | if address.To4() != nil { 115 | capacity += SockAddrInSize 116 | } else { 117 | capacity += SockAddrIn6Size 118 | } 119 | } 120 | var buffer bytes.Buffer 121 | buffer.Grow(capacity) 122 | for _, address := range addr.addresses { 123 | if ip4 := address.To4(); ip4 != nil { 124 | /* 125 | sa := &syscall.RawSockaddrInet4{ 126 | Family: syscall.AF_INET, 127 | Port: port, 128 | } 129 | copy(sa.Addr[:], ip4) 130 | buffer = append(buffer, Pack(sa)...) 131 | */ 132 | // IPv4: Family(2) + Port(2) + Addr(4) + Zero(8) = 16 bytes 133 | binary.Write(&buffer, endian, uint16(syscall.AF_INET)) 134 | binary.Write(&buffer, endian, port) 135 | buffer.Write(ip4) 136 | binary.Write(&buffer, endian, uint64(0)) 137 | continue 138 | } 139 | if ip6 := address.To16(); ip6 != nil { 140 | /* 141 | sa := syscall.RawSockaddrInet6{ 142 | Family: syscall.AF_INET6, 143 | Port: port, 144 | } 145 | copy(sa.Addr[:], ip6) 146 | buffer = append(buffer, Pack(sa)...) 147 | */ 148 | // IPv6: Family(2) + Port(2) + FlowInfo(4) + Addr(16) + ScopeId(4) = 28 bytes 149 | binary.Write(&buffer, endian, uint16(syscall.AF_INET6)) 150 | binary.Write(&buffer, endian, port) 151 | binary.Write(&buffer, endian, uint32(0)) // FlowInfo 152 | buffer.Write(ip6) 153 | binary.Write(&buffer, endian, uint32(0)) // ScopeId 154 | } 155 | } 156 | return buffer.Bytes() 157 | } 158 | 159 | // FromSockAddrStorage converts a socket address storage structure to an SCTPAddr. 160 | // It supports both IPv4 (AF_INET) and IPv6 (AF_INET6) address families. 161 | func FromSockAddrStorage(addr *SockAddrStorage) *SCTPAddr { 162 | if addr != nil { 163 | switch addr.Family { 164 | case syscall.AF_INET: 165 | sa := (*SockAddrIn)(unsafe.Pointer(addr)) 166 | return &SCTPAddr{ 167 | port: int(ntohs(sa.Port)), 168 | addresses: []net.IP{ 169 | sa.Addr.Addr[:], 170 | }, 171 | } 172 | case syscall.AF_INET6: 173 | sa := (*SockAddrIn6)(unsafe.Pointer(addr)) 174 | return &SCTPAddr{ 175 | port: int(ntohs(sa.Port)), 176 | addresses: []net.IP{ 177 | sa.Addr.Addr[:], 178 | }, 179 | } 180 | } 181 | } 182 | return nil 183 | } 184 | 185 | // FromSCTPGetAddrs converts a SCTPGetAddrs structure to an SCTPAddr. 186 | // It handles both IPv4 and IPv6 addresses, extracting the port from the first address. 187 | func FromSCTPGetAddrs(addr *SCTPGetAddrs) *SCTPAddr { 188 | if addr != nil && addr.Num > 0 { 189 | address := &SCTPAddr{ 190 | addresses: make([]net.IP, addr.Num), 191 | } 192 | ptr := unsafe.Add(unsafe.Pointer(addr), SCTPGetAddrsSize) 193 | for i := uint32(0); i < addr.Num; i++ { 194 | sockaddr := (*SockAddr)(unsafe.Pointer(ptr)) 195 | switch sockaddr.Family { 196 | case syscall.AF_INET: 197 | sa := (*SockAddrIn)(unsafe.Pointer(ptr)) 198 | if i == 0 { 199 | address.port = int(ntohs(sa.Port)) 200 | } 201 | address.addresses[i] = sa.Addr.Addr[:] 202 | ptr = unsafe.Add(ptr, SockAddrInSize) 203 | case syscall.AF_INET6: 204 | sa := (*SockAddrIn6)(unsafe.Pointer(ptr)) 205 | if i == 0 { 206 | address.port = int(ntohs(sa.Port)) 207 | } 208 | address.addresses[i] = sa.Addr.Addr[:] 209 | ptr = unsafe.Add(ptr, SockAddrIn6Size) 210 | default: 211 | return nil 212 | } 213 | } 214 | return address 215 | } 216 | return nil 217 | } 218 | 219 | // MakeSCTPAddr parses a network address string and creates an SCTPAddr. 220 | // It supports "sctp", "sctp4", and "sctp6" networks, parsing comma-separated IP addresses. 221 | func MakeSCTPAddr(network, addr string) (*SCTPAddr, error) { 222 | // Normalize network 223 | switch network { 224 | case "", "sctp": 225 | network = "sctp" 226 | case "sctp4": 227 | network = "sctp4" 228 | case "sctp6": 229 | network = "sctp6" 230 | default: 231 | return nil, net.UnknownNetworkError(network) 232 | } 233 | 234 | // Find port separator 235 | index := strings.LastIndex(addr, ":") 236 | if index <= 0 || index == len(addr)-1 { 237 | return nil, &net.AddrError{ 238 | Err: "missing port in address", 239 | Addr: addr, 240 | } 241 | } 242 | 243 | // Parse port 244 | port, err := net.LookupPort(network, addr[index+1:]) 245 | if err != nil { 246 | return nil, &net.AddrError{ 247 | Err: "missing port in address: " + err.Error(), 248 | Addr: addr, 249 | } 250 | } 251 | 252 | // Split addresses 253 | addrs := strings.Split(addr[:index], "/") 254 | addresses := make([]net.IP, 0, len(addrs)) 255 | 256 | for _, addrPart := range addrs { 257 | if len(addrPart) == 0 { 258 | // Empty address part 259 | switch network { 260 | case "sctp4": 261 | addresses = append(addresses, net.IPv4zero) 262 | case "sctp", "sctp6": 263 | addresses = append(addresses, net.IPv6zero) 264 | } 265 | } else { 266 | // Parse IP address 267 | ip := net.ParseIP(addrPart) 268 | if ip == nil { 269 | continue // Skip invalid addresses 270 | } 271 | 272 | // Validate based on network type 273 | switch network { 274 | case "sctp4": 275 | if ip.To4() != nil { 276 | addresses = append(addresses, ip) 277 | } 278 | case "sctp6": 279 | if ip.To16() != nil { 280 | addresses = append(addresses, ip) 281 | } 282 | case "sctp": 283 | // Accept both IPv4 and IPv6 284 | addresses = append(addresses, ip) 285 | } 286 | } 287 | } 288 | 289 | if len(addresses) == 0 { 290 | return nil, net.InvalidAddrError(addr) 291 | } 292 | 293 | return &SCTPAddr{ 294 | addresses: addresses, 295 | port: port, 296 | }, nil 297 | } 298 | -------------------------------------------------------------------------------- /sctp_listener.go: -------------------------------------------------------------------------------- 1 | package sctp_go 2 | 3 | import ( 4 | "bytes" 5 | "encoding/binary" 6 | "errors" 7 | "net" 8 | "syscall" 9 | "unsafe" 10 | ) 11 | 12 | // SCTPListener represents an SCTP listener socket. 13 | type SCTPListener struct { 14 | sock int 15 | } 16 | 17 | // FD returns the file descriptor of the listener socket. 18 | func (listener *SCTPListener) FD() int { 19 | return listener.sock 20 | } 21 | 22 | // Addr returns the local network address. 23 | func (listener *SCTPListener) Addr() net.Addr { 24 | if listener.sock <= 0 { 25 | return nil 26 | } 27 | var ( 28 | data [4096]byte 29 | addrs = (*SCTPGetAddrs)(unsafe.Pointer(&data[0])) 30 | length = len(data) 31 | ) 32 | addrs.AssocId = 0 33 | _, _, err := syscall.Syscall6( 34 | syscall.SYS_GETSOCKOPT, 35 | uintptr(listener.sock), 36 | syscall.IPPROTO_SCTP, 37 | SCTP_GET_LOCAL_ADDRS, 38 | uintptr(unsafe.Pointer(addrs)), 39 | uintptr(unsafe.Pointer(&length)), 40 | 0, 41 | ) 42 | if err == 0 { 43 | return FromSCTPGetAddrs(addrs) 44 | } 45 | return nil 46 | } 47 | 48 | // RemoteAddr returns the remote network address for the specified association. 49 | func (listener *SCTPListener) RemoteAddr(assoc int) net.Addr { 50 | if listener.sock <= 0 { 51 | return nil 52 | } 53 | var ( 54 | data [4096]byte 55 | addrs = (*SCTPGetAddrs)(unsafe.Pointer(&data[0])) 56 | length = len(data) 57 | ) 58 | addrs.AssocId = int32(assoc) 59 | _, _, err := syscall.Syscall6( 60 | syscall.SYS_GETSOCKOPT, 61 | uintptr(listener.sock), 62 | syscall.IPPROTO_SCTP, 63 | SCTP_GET_PEER_ADDRS, 64 | uintptr(unsafe.Pointer(addrs)), 65 | uintptr(unsafe.Pointer(&length)), 66 | 0, 67 | ) 68 | if err == 0 { 69 | return FromSCTPGetAddrs(addrs) 70 | } 71 | return nil 72 | } 73 | 74 | // Connect connects to the remote SCTP address. 75 | func (listener *SCTPListener) Connect(remote *SCTPAddr) (int, error) { 76 | if listener.sock <= 0 { 77 | return 0, errors.New("invalid listener") 78 | } 79 | return SCTPConnect(listener.sock, remote) 80 | } 81 | 82 | // Abort aborts the SCTP association specified by assoc. 83 | func (listener *SCTPListener) Abort(assoc int) error { 84 | if listener.sock <= 0 { 85 | return errors.New("invalid listener") 86 | } 87 | var msg = SCTPSndRcvInfo{ 88 | Flags: SCTP_ABORT, 89 | AssocId: int32(assoc), 90 | } 91 | _, err := listener.SendMsg(nil, &msg) 92 | return err 93 | } 94 | 95 | // Disconnect disconnects the SCTP association specified by assoc. 96 | func (listener *SCTPListener) Disconnect(assoc int) error { 97 | if listener.sock <= 0 { 98 | return errors.New("invalid listener") 99 | } 100 | var msg = SCTPSndRcvInfo{ 101 | Stream: 0, 102 | Ppid: 0, 103 | Flags: SCTP_EOF, 104 | AssocId: int32(assoc), 105 | } 106 | _, err := listener.SendMsg(nil, &msg) 107 | return err 108 | } 109 | 110 | // PeelOff peels off the SCTP association specified by assoc. 111 | func (listener *SCTPListener) PeelOff(assoc int) (*SCTPConn, error) { 112 | if listener.sock <= 0 { 113 | return nil, errors.New("invalid listener") 114 | } 115 | return SCTPPeelOff(listener.sock, assoc) 116 | } 117 | 118 | // PeelOffFlags peels off the SCTP association specified by assoc with flags. 119 | func (listener *SCTPListener) PeelOffFlags(assoc, flag int) (*SCTPConn, error) { 120 | if listener.sock <= 0 { 121 | return nil, errors.New("invalid listener") 122 | } 123 | return SCTPPeelOffFlag(listener.sock, assoc, flag) 124 | } 125 | 126 | // AcceptSCTP accepts an incoming SCTP connection. 127 | func (listener *SCTPListener) AcceptSCTP() (*SCTPConn, error) { 128 | if listener.sock <= 0 { 129 | return nil, errors.New("invalid listener") 130 | } 131 | sock, _, err := syscall.Accept4(listener.sock, 0) 132 | if err != nil { 133 | return nil, err 134 | } 135 | return NewSCTPConn(sock), nil 136 | } 137 | 138 | // Accept accepts a generic network connection. 139 | func (listener *SCTPListener) Accept() (net.Conn, error) { 140 | return listener.AcceptSCTP() 141 | } 142 | 143 | // Close closes the listener. 144 | func (listener *SCTPListener) Close() error { 145 | if listener.sock <= 0 { 146 | return errors.New("invalid listener") 147 | } 148 | // Shutdown doesn't work on RAW Sockets, SCTP Socket is essentially a RAW Socket. 149 | _ = syscall.Shutdown(listener.sock, syscall.SHUT_RDWR) 150 | return syscall.Close(listener.sock) 151 | } 152 | 153 | // SetEventSubscribe sets the SCTP event subscription. 154 | func (listener *SCTPListener) SetEventSubscribe(events *SCTPEventSubscribe) error { 155 | if listener.sock <= 0 { 156 | return errors.New("invalid listener") 157 | } 158 | if events == nil { 159 | return errors.New("events cannot be nil") 160 | } 161 | _, _, err := syscall.Syscall6( 162 | syscall.SYS_SETSOCKOPT, 163 | uintptr(listener.sock), 164 | SOL_SCTP, 165 | SCTP_EVENTS, 166 | uintptr(unsafe.Pointer(events)), 167 | unsafe.Sizeof(*events), 168 | 0, 169 | ) 170 | if err != 0 { 171 | return err 172 | } 173 | return nil 174 | } 175 | 176 | // GetEventSubscribe gets the SCTP event subscription. 177 | func (listener *SCTPListener) GetEventSubscribe() (*SCTPEventSubscribe, error) { 178 | if listener.sock <= 0 { 179 | return nil, errors.New("invalid listener") 180 | } 181 | var ( 182 | events = &SCTPEventSubscribe{} 183 | length = unsafe.Sizeof(*events) 184 | ) 185 | _, _, err := syscall.Syscall6( 186 | syscall.SYS_GETSOCKOPT, 187 | uintptr(listener.sock), 188 | SOL_SCTP, 189 | SCTP_EVENTS, 190 | uintptr(unsafe.Pointer(events)), 191 | uintptr(unsafe.Pointer(&length)), 192 | 0, 193 | ) 194 | if err != 0 { 195 | return nil, err 196 | } 197 | return events, nil 198 | } 199 | 200 | // RecvMsg receives a message from the SCTP socket. 201 | func (listener *SCTPListener) RecvMsg(b []byte, info *SCTPSndRcvInfo, flags *int) (n int, err error) { 202 | if listener.sock <= 0 { 203 | return 0, errors.New("invalid listener") 204 | } 205 | var ( 206 | oob = make([]byte, syscall.CmsgSpace(SCTPSndRcvInfoSize)) 207 | flag = 0 208 | ) 209 | if flags != nil { 210 | flag = *flags 211 | } 212 | n, noob, flag, _, err := syscall.Recvmsg(listener.sock, b, oob[:], flag) 213 | if err != nil { 214 | return n, err 215 | } 216 | *flags = flag 217 | if noob > 0 { 218 | ParseSndRcvInfo(info, oob[:noob]) 219 | } 220 | return n, nil 221 | } 222 | 223 | // SendMsg sends a message on the SCTP socket. 224 | func (listener *SCTPListener) SendMsg(b []byte, info *SCTPSndRcvInfo) (int, error) { 225 | if listener.sock <= 0 { 226 | return 0, errors.New("invalid listener") 227 | } 228 | var buffer bytes.Buffer 229 | if info != nil { 230 | size := int(unsafe.Sizeof(syscall.Cmsghdr{})) + int(unsafe.Sizeof(*info)) 231 | buffer.Grow(size) 232 | hdr := syscall.Cmsghdr{ 233 | Level: syscall.IPPROTO_SCTP, 234 | Type: SCTP_SNDRCV, 235 | Len: uint64(syscall.CmsgSpace(SCTPSndRcvInfoSize)), 236 | } 237 | binary.Write(&buffer, endian, hdr) 238 | binary.Write(&buffer, endian, *info) 239 | } 240 | return SCTPSendMsg(listener.sock, b, buffer.Bytes(), 0) 241 | } 242 | 243 | // SetInitMsg sets the SCTP initialization message. 244 | func (listener *SCTPListener) SetInitMsg(init *SCTPInitMsg) error { 245 | if listener.sock <= 0 { 246 | return errors.New("invalid listener") 247 | } 248 | if init == nil { 249 | return errors.New("init cannot be nil") 250 | } 251 | _, _, err := syscall.Syscall6( 252 | syscall.SYS_SETSOCKOPT, 253 | uintptr(listener.sock), 254 | SOL_SCTP, 255 | SCTP_INITMSG, 256 | uintptr(unsafe.Pointer(init)), 257 | unsafe.Sizeof(*init), 258 | 0, 259 | ) 260 | if err != 0 { 261 | return err 262 | } 263 | return nil 264 | } 265 | 266 | // SetNonblock sets the listener socket to non-blocking mode. 267 | func (listener *SCTPListener) SetNonblock() error { 268 | if listener.sock <= 0 { 269 | return errors.New("invalid listener") 270 | } 271 | return syscall.SetNonblock(listener.sock, true) 272 | } 273 | 274 | // ListenSCTP creates an SCTP listener on the specified network and address. 275 | func ListenSCTP(network string, sockettype int, local *SCTPAddr, init *SCTPInitMsg) (*SCTPListener, error) { 276 | if local == nil { 277 | return nil, errors.New("local address cannot be nil") 278 | } 279 | if init == nil { 280 | return nil, errors.New("init message cannot be nil") 281 | } 282 | switch network { 283 | case "sctp", "sctp4", "sctp6": 284 | default: 285 | return nil, &net.OpError{ 286 | Op: "listen", 287 | Net: network, 288 | Source: local.Addr(), 289 | Err: net.UnknownNetworkError(network), 290 | } 291 | } 292 | var ( 293 | sock int 294 | err error 295 | listener *SCTPListener 296 | ) 297 | family := DetectAddrFamily(network) 298 | // syscall.SOCK_SEQPACKET vs syscall.SOCK_STREAM 299 | sock, err = SCTPSocket(family, sockettype) 300 | if err != nil { 301 | return nil, err 302 | } 303 | defer func() { 304 | if err != nil && sock > 0 { 305 | _ = syscall.Close(sock) 306 | } 307 | }() 308 | err = syscall.SetsockoptInt(sock, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1) 309 | if err != nil { 310 | return nil, err 311 | } 312 | err = syscall.SetsockoptInt(sock, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1) 313 | if err != nil { 314 | return nil, err 315 | } 316 | _, _, errno := syscall.Syscall6( 317 | syscall.SYS_SETSOCKOPT, 318 | uintptr(sock), 319 | SOL_SCTP, 320 | SCTP_INITMSG, 321 | uintptr(unsafe.Pointer(init)), 322 | unsafe.Sizeof(*init), 323 | 0, 324 | ) 325 | if errno != 0 { 326 | err = errno 327 | return nil, err 328 | } 329 | err = SCTPBind(sock, local, SCTP_BINDX_ADD_ADDR) 330 | if err != nil { 331 | return nil, err 332 | } 333 | err = syscall.Listen(sock, syscall.SOMAXCONN) 334 | if err != nil { 335 | return nil, err 336 | } 337 | listener = &SCTPListener{ 338 | sock: sock, 339 | } 340 | return listener, nil 341 | } 342 | -------------------------------------------------------------------------------- /sctp_constants.go: -------------------------------------------------------------------------------- 1 | // Code generated by cmd/cgo -godefs; DO NOT EDIT. 2 | // cgo -godefs -srcdir . constants_sctp.go 3 | 4 | package sctp_go 5 | 6 | const ( 7 | SOL_SCTP = 0x84 8 | IPPROTO_SCTP = 0x84 9 | IoVectorSize = 0x10 10 | MsgHeaderSize = 0x38 11 | CMsgHeaderSize = 0x10 12 | InAddrSize = 0x4 13 | In6AddrSize = 0x10 14 | SockAddrInSize = 0x10 15 | SockAddrIn6Size = 0x1c 16 | SockAddrSize = 0x10 17 | SockAddrStorageSize = 0x80 18 | SCTPSndRcvInfoSize = 0x20 19 | SCTPInitMsgSize = 0x8 20 | SCTPSndInfoSize = 0x10 21 | SCTPRcvInfoSize = 0x1c 22 | SCTPNxtInfoSize = 0x10 23 | SCTPPrInfoSize = 0x8 24 | SCTPAuthInfoSize = 0x2 25 | SCTPAssocChangeSize = 0x14 26 | SCTPPAddrChangeSize = 0x94 27 | SCTPRemoteErrorSize = 0x10 28 | SCTPSendFailedSize = 0x30 29 | SCTPShutdownEventSize = 0xc 30 | SCTPAdaptationEventSize = 0x10 31 | SCTPPDApiEventSize = 0x18 32 | SCTPAuthKeyEventSize = 0x14 33 | SCTPSenderDryEventSize = 0xc 34 | SCTPStreamResetEventSize = 0xc 35 | SCTPAssocResetEventSize = 0x14 36 | SCTPStreamChangeEventSize = 0x10 37 | SCTPEventSubscribeSize = 0xd 38 | SCTPNotificationSize = 0x94 39 | SCTPCmsgDataSize = 0x20 40 | SCTPNotificationHeaderSize = 0x8 41 | SCTPRTOInfoSize = 0x10 42 | SCTPAssocParamsSize = 0x14 43 | SCTPSetPeerPrimarySize = 0x84 44 | SCTPPrimaryAddrSize = 0x84 45 | SCTPSetAdaptationSize = 0x4 46 | SCTPPeerAddrParamsSize = 0x9c 47 | SCTPAuthChunkSize = 0x1 48 | SCTPHmacAlgoSize = 0x4 49 | SCTPAuthKeySize = 0x8 50 | SCTPAuthKeyIdSize = 0x8 51 | SCTPSackInfoSize = 0xc 52 | SCTPAssocValueSize = 0x8 53 | SCTPStreamValueSize = 0x8 54 | SCTPPeerAddrInfoSize = 0x98 55 | SCTPStatusSize = 0xb0 56 | SCTPAuthChunksSize = 0x8 57 | SCTPAssocIdsSize = 0x4 58 | SCTPGetAddrsOldSize = 0x10 59 | SCTPGetAddrsSize = 0x8 60 | SCTPAssocStatsSize = 0x100 61 | SCTPPeelOffArgSize = 0x8 62 | SCTPPeelOffFlagsArgSize = 0xc 63 | SCTPPeerAddrThresholdsSize = 0x90 64 | SCTPPRStatusSize = 0x18 65 | SCTPDefaultPRInfoSize = 0xc 66 | SCTPInfoSize = 0x170 67 | SCTPResetStreamsSize = 0x8 68 | SCTPAddStreamsSize = 0x8 69 | SCTPEventSize = 0x8 70 | SCTP_FUTURE_ASSOC = 0x0 71 | SCTP_CURRENT_ASSOC = 0x1 72 | SCTP_ALL_ASSOC = 0x2 73 | SCTP_RTOINFO = 0x0 74 | SCTP_ASSOCINFO = 0x1 75 | SCTP_INITMSG = 0x2 76 | SCTP_NODELAY = 0x3 77 | SCTP_AUTOCLOSE = 0x4 78 | SCTP_SET_PEER_PRIMARY_ADDR = 0x5 79 | SCTP_PRIMARY_ADDR = 0x6 80 | SCTP_ADAPTATION_LAYER = 0x7 81 | SCTP_DISABLE_FRAGMENTS = 0x8 82 | SCTP_PEER_ADDR_PARAMS = 0x9 83 | SCTP_DEFAULT_SEND_PARAM = 0xa 84 | SCTP_EVENTS = 0xb 85 | SCTP_I_WANT_MAPPED_V4_ADDR = 0xc 86 | SCTP_MAXSEG = 0xd 87 | SCTP_STATUS = 0xe 88 | SCTP_GET_PEER_ADDR_INFO = 0xf 89 | SCTP_DELAYED_ACK_TIME = 0x10 90 | SCTP_DELAYED_ACK = 0x10 91 | SCTP_DELAYED_SACK = 0x10 92 | SCTP_CONTEXT = 0x11 93 | SCTP_FRAGMENT_INTERLEAVE = 0x12 94 | SCTP_PARTIAL_DELIVERY_POINT = 0x13 95 | SCTP_MAX_BURST = 0x14 96 | SCTP_AUTH_CHUNK = 0x15 97 | SCTP_HMAC_IDENT = 0x16 98 | SCTP_AUTH_KEY = 0x17 99 | SCTP_AUTH_ACTIVE_KEY = 0x18 100 | SCTP_AUTH_DELETE_KEY = 0x19 101 | SCTP_PEER_AUTH_CHUNKS = 0x1a 102 | SCTP_LOCAL_AUTH_CHUNKS = 0x1b 103 | SCTP_GET_ASSOC_NUMBER = 0x1c 104 | SCTP_GET_ASSOC_ID_LIST = 0x1d 105 | SCTP_AUTO_ASCONF = 0x1e 106 | SCTP_PEER_ADDR_THLDS = 0x1f 107 | SCTP_RECVRCVINFO = 0x20 108 | SCTP_RECVNXTINFO = 0x21 109 | SCTP_DEFAULT_SNDINFO = 0x22 110 | SCTP_AUTH_DEACTIVATE_KEY = 0x23 111 | SCTP_REUSE_PORT = 0x24 112 | SCTP_SOCKOPT_BINDX_ADD = 0x64 113 | SCTP_SOCKOPT_BINDX_REM = 0x65 114 | SCTP_SOCKOPT_PEELOFF = 0x66 115 | SCTP_SOCKOPT_CONNECTX_OLD = 0x6b 116 | SCTP_GET_PEER_ADDRS = 0x6c 117 | SCTP_GET_LOCAL_ADDRS = 0x6d 118 | SCTP_SOCKOPT_CONNECTX = 0x6e 119 | SCTP_SOCKOPT_CONNECTX3 = 0x6f 120 | SCTP_GET_ASSOC_STATS = 0x70 121 | SCTP_PR_SUPPORTED = 0x71 122 | SCTP_DEFAULT_PRINFO = 0x72 123 | SCTP_PR_ASSOC_STATUS = 0x73 124 | SCTP_PR_STREAM_STATUS = 0x74 125 | SCTP_RECONFIG_SUPPORTED = 0x75 126 | SCTP_ENABLE_STREAM_RESET = 0x76 127 | SCTP_RESET_STREAMS = 0x77 128 | SCTP_RESET_ASSOC = 0x78 129 | SCTP_ADD_STREAMS = 0x79 130 | SCTP_SOCKOPT_PEELOFF_FLAGS = 0x7a 131 | SCTP_STREAM_SCHEDULER = 0x7b 132 | SCTP_STREAM_SCHEDULER_VALUE = 0x7c 133 | SCTP_INTERLEAVING_SUPPORTED = 0x7d 134 | SCTP_SENDMSG_CONNECT = 0x7e 135 | SCTP_EVENT = 0x7f 136 | SCTP_ASCONF_SUPPORTED = 0x80 137 | SCTP_AUTH_SUPPORTED = 0x81 138 | SCTP_ECN_SUPPORTED = 0x82 139 | SCTP_PR_SCTP_NONE = 0x0 140 | SCTP_PR_SCTP_TTL = 0x10 141 | SCTP_PR_SCTP_RTX = 0x20 142 | SCTP_PR_SCTP_PRIO = 0x30 143 | SCTP_PR_SCTP_MAX = 0x30 144 | SCTP_PR_SCTP_MASK = 0x30 145 | SCTP_ENABLE_RESET_STREAM_REQ = 0x1 146 | SCTP_ENABLE_RESET_ASSOC_REQ = 0x2 147 | SCTP_ENABLE_CHANGE_ASSOC_REQ = 0x4 148 | SCTP_ENABLE_STRRESET_MASK = 0x7 149 | SCTP_STREAM_RESET_INCOMING = 0x1 150 | SCTP_STREAM_RESET_OUTGOING = 0x2 151 | SCTP_MSG_NOTIFICATION = 0x8000 152 | SCTP_UNORDERED = 0x1 153 | SCTP_ADDR_OVER = 0x2 154 | SCTP_ABORT = 0x4 155 | SCTP_SACK_IMMEDIATELY = 0x8 156 | SCTP_SENDALL = 0x40 157 | SCTP_PR_SCTP_ALL = 0x80 158 | SCTP_NOTIFICATION = 0x8000 159 | SCTP_EOF = 0x200 160 | SCTP_INIT = 0x0 161 | SCTP_SNDRCV = 0x1 162 | SCTP_SNDINFO = 0x2 163 | SCTP_RCVINFO = 0x3 164 | SCTP_NXTINFO = 0x4 165 | SCTP_PRINFO = 0x5 166 | SCTP_AUTHINFO = 0x6 167 | SCTP_DSTADDRV4 = 0x7 168 | SCTP_DSTADDRV6 = 0x8 169 | SCTP_COMM_UP = 0x0 170 | SCTP_COMM_LOST = 0x1 171 | SCTP_RESTART = 0x2 172 | SCTP_SHUTDOWN_COMP = 0x3 173 | SCTP_CANT_STR_ASSOC = 0x4 174 | SCTP_ADDR_AVAILABLE = 0x0 175 | SCTP_ADDR_UNREACHABLE = 0x1 176 | SCTP_ADDR_REMOVED = 0x2 177 | SCTP_ADDR_ADDED = 0x3 178 | SCTP_ADDR_MADE_PRIM = 0x4 179 | SCTP_ADDR_CONFIRMED = 0x5 180 | SCTP_DATA_UNSENT = 0x0 181 | SCTP_DATA_SENT = 0x1 182 | SCTP_PARTIAL_DELIVERY_ABORTED = 0x0 183 | SCTP_AUTH_NEW_KEY = 0x0 184 | SCTP_AUTH_FREE_KEY = 0x1 185 | SCTP_AUTH_NO_AUTH = 0x2 186 | SCTP_STREAM_RESET_INCOMING_SSN = 0x1 187 | SCTP_STREAM_RESET_OUTGOING_SSN = 0x2 188 | SCTP_STREAM_RESET_DENIED = 0x4 189 | SCTP_STREAM_RESET_FAILED = 0x8 190 | SCTP_ASSOC_RESET_DENIED = 0x4 191 | SCTP_ASSOC_RESET_FAILED = 0x8 192 | SCTP_ASSOC_CHANGE_DENIED = 0x4 193 | SCTP_ASSOC_CHANGE_FAILED = 0x8 194 | SCTP_STREAM_CHANGE_DENIED = 0x4 195 | SCTP_STREAM_CHANGE_FAILED = 0x8 196 | SCTP_SN_TYPE_BASE = 0x8000 197 | SCTP_DATA_IO_EVENT = 0x8000 198 | SCTP_ASSOC_CHANGE = 0x8001 199 | SCTP_PEER_ADDR_CHANGE = 0x8002 200 | SCTP_SEND_FAILED = 0x8003 201 | SCTP_REMOTE_ERROR = 0x8004 202 | SCTP_SHUTDOWN_EVENT = 0x8005 203 | SCTP_PARTIAL_DELIVERY_EVENT = 0x8006 204 | SCTP_ADAPTATION_INDICATION = 0x8007 205 | SCTP_AUTHENTICATION_EVENT = 0x8008 206 | SCTP_SENDER_DRY_EVENT = 0x8009 207 | SCTP_STREAM_RESET_EVENT = 0x800a 208 | SCTP_ASSOC_RESET_EVENT = 0x800b 209 | SCTP_STREAM_CHANGE_EVENT = 0x800c 210 | SCTP_SN_TYPE_MAX = 0x800c 211 | SCTP_FAILED_THRESHOLD = 0x0 212 | SCTP_RECEIVED_SACK = 0x1 213 | SCTP_HEARTBEAT_SUCCESS = 0x2 214 | SCTP_RESPONSE_TO_USER_REQ = 0x3 215 | SCTP_INTERNAL_ERROR = 0x4 216 | SCTP_SHUTDOWN_GUARD_EXPIRES = 0x5 217 | SCTP_PEER_FAULTY = 0x6 218 | SPP_HB_ENABLE = 0x1 219 | SPP_HB_DISABLE = 0x2 220 | SPP_HB = 0x3 221 | SPP_HB_DEMAND = 0x4 222 | SPP_PMTUD_ENABLE = 0x8 223 | SPP_PMTUD_DISABLE = 0x10 224 | SPP_PMTUD = 0x18 225 | SPP_SACKDELAY_ENABLE = 0x20 226 | SPP_SACKDELAY_DISABLE = 0x40 227 | SPP_SACKDELAY = 0x60 228 | SPP_HB_TIME_IS_ZERO = 0x80 229 | SPP_IPV6_FLOWLABEL = 0x100 230 | SPP_DSCP = 0x200 231 | SCTP_AUTH_HMAC_ID_SHA1 = 0x1 232 | SCTP_AUTH_HMAC_ID_SHA256 = 0x3 233 | SCTP_INACTIVE = 0x0 234 | SCTP_PF = 0x1 235 | SCTP_ACTIVE = 0x2 236 | SCTP_UNCONFIRMED = 0x3 237 | SCTP_UNKNOWN = 0xffff 238 | SCTP_EMPTY = 0x0 239 | SCTP_CLOSED = 0x1 240 | SCTP_COOKIE_WAIT = 0x2 241 | SCTP_COOKIE_ECHOED = 0x3 242 | SCTP_ESTABLISHED = 0x4 243 | SCTP_SHUTDOWN_PENDING = 0x5 244 | SCTP_SHUTDOWN_SENT = 0x6 245 | SCTP_SHUTDOWN_RECEIVED = 0x7 246 | SCTP_SHUTDOWN_ACK_SENT = 0x8 247 | SCTP_BINDX_ADD_ADDR = 0x1 248 | SCTP_BINDX_REM_ADDR = 0x2 249 | SCTP_SS_FCFS = 0x0 250 | SCTP_SS_DEFAULT = 0x0 251 | SCTP_SS_PRIO = 0x1 252 | SCTP_SS_RR = 0x2 253 | SCTP_SS_MAX = 0x2 254 | ) 255 | -------------------------------------------------------------------------------- /sctp_conn.go: -------------------------------------------------------------------------------- 1 | package sctp_go 2 | 3 | import ( 4 | "net" 5 | "sync/atomic" 6 | "syscall" 7 | "time" 8 | "unsafe" 9 | ) 10 | 11 | // SCTPConn represents an SCTP connection. 12 | type SCTPConn struct { 13 | sock int64 14 | assoc int 15 | } 16 | 17 | // NewSCTPConn creates a new SCTPConn from a socket file descriptor. 18 | func NewSCTPConn(sock int) *SCTPConn { 19 | return &SCTPConn{ 20 | sock: int64(sock), 21 | } 22 | } 23 | 24 | // FD returns the socket file descriptor. 25 | func (conn *SCTPConn) FD() int64 { 26 | return conn.sock 27 | } 28 | 29 | // AssocId returns the association ID. 30 | func (conn *SCTPConn) AssocId() int { 31 | return conn.assoc 32 | } 33 | 34 | // GetPrimaryPeerAddr returns the primary peer address for the association. 35 | func (conn *SCTPConn) GetPrimaryPeerAddr() (*SCTPAddr, error) { 36 | param := SCTPPrimaryAddr{ 37 | AssocId: int32(conn.assoc), 38 | } 39 | length := unsafe.Sizeof(param) 40 | _, _, err := syscall.Syscall6( 41 | syscall.SYS_GETSOCKOPT, 42 | uintptr(conn.sock), 43 | syscall.IPPROTO_SCTP, 44 | SCTP_PRIMARY_ADDR, 45 | uintptr(unsafe.Pointer(¶m)), 46 | uintptr(unsafe.Pointer(&length)), 47 | 0, 48 | ) 49 | if err != 0 { 50 | return nil, err 51 | } 52 | addr := FromSockAddrStorage((*SockAddrStorage)(unsafe.Pointer(¶m.Addr))) 53 | return addr, nil 54 | } 55 | 56 | // Read reads data from the connection, skipping notifications. 57 | func (conn *SCTPConn) Read(b []byte) (n int, err error) { 58 | if !conn.ok() { 59 | return 0, syscall.EINVAL 60 | } 61 | var ( 62 | flags = 0 63 | info = &SCTPSndRcvInfo{} 64 | ) 65 | for { 66 | n, err = conn.RecvMsg(b, info, &flags) 67 | if flags&SCTP_MSG_NOTIFICATION == 0 { 68 | return n, err 69 | } 70 | } 71 | } 72 | 73 | // RecvMsg receives a message from the connection. 74 | func (conn *SCTPConn) RecvMsg(b []byte, info *SCTPSndRcvInfo, flags *int) (n int, err error) { 75 | if !conn.ok() { 76 | return 0, syscall.EINVAL 77 | } 78 | oob := make([]byte, syscall.CmsgSpace(SCTPSndRcvInfoSize)) 79 | n, noob, flag, _, err := syscall.Recvmsg(int(conn.sock), b, oob, 0) 80 | if err != nil { 81 | return n, err 82 | } 83 | *flags = flag 84 | if noob > 0 { 85 | ParseSndRcvInfo(info, oob[:noob]) 86 | } 87 | return n, nil 88 | } 89 | 90 | // Write writes data to the connection. 91 | func (conn *SCTPConn) Write(b []byte) (n int, err error) { 92 | return conn.SendMsg(b, nil) 93 | } 94 | 95 | // SendMsg sends a message on the connection. 96 | func (conn *SCTPConn) SendMsg(b []byte, info *SCTPSndRcvInfo) (int, error) { 97 | if !conn.ok() { 98 | return 0, syscall.EINVAL 99 | } 100 | var buffer []byte 101 | if info != nil { 102 | hdr := &syscall.Cmsghdr{ 103 | Level: syscall.IPPROTO_SCTP, 104 | Type: SCTP_SNDRCV, 105 | Len: uint64(syscall.CmsgSpace(SCTPSndRcvInfoSize)), 106 | } 107 | buffer = append(Pack(hdr), Pack(info)...) 108 | } 109 | // return syscall.SendmsgN(int(conn.sock), b, buffer, nil, 0) 110 | return SCTPSendMsg(int(conn.sock), b, buffer, 0) 111 | } 112 | 113 | // Abort aborts the SCTP association. 114 | func (conn *SCTPConn) Abort() error { 115 | sock := atomic.SwapInt64(&conn.sock, -1) 116 | if sock > 0 { 117 | linger := syscall.Linger{ 118 | Onoff: 1, 119 | Linger: 0, 120 | } 121 | _, _, _ = syscall.Syscall6( 122 | syscall.SYS_SETSOCKOPT, 123 | uintptr(sock), 124 | syscall.SOL_SOCKET, 125 | syscall.SO_LINGER, 126 | uintptr(unsafe.Pointer(&linger)), 127 | unsafe.Sizeof(linger), 128 | 0, 129 | ) 130 | return syscall.Close(int(sock)) 131 | } 132 | return syscall.EBADFD 133 | } 134 | 135 | // Close closes the SCTP connection. 136 | func (conn *SCTPConn) Close() error { 137 | if !conn.ok() { 138 | return syscall.EINVAL 139 | } 140 | msg := &SCTPSndRcvInfo{ 141 | Flags: SCTP_EOF, 142 | } 143 | _, _ = conn.SendMsg(nil, msg) 144 | sock := atomic.SwapInt64(&conn.sock, -1) 145 | if sock > 0 { 146 | _ = syscall.Shutdown(int(sock), syscall.SHUT_RDWR) 147 | return syscall.Close(int(sock)) 148 | } 149 | return syscall.EBADFD 150 | } 151 | 152 | // LocalAddr returns the local network address. 153 | func (conn *SCTPConn) LocalAddr() net.Addr { 154 | if !conn.ok() { 155 | return nil 156 | } 157 | var ( 158 | data [4096]byte 159 | addrs = (*SCTPGetAddrs)(unsafe.Pointer(&data[0])) 160 | length = len(data) 161 | ) 162 | addrs.AssocId = 0 163 | _, _, err := syscall.Syscall6( 164 | syscall.SYS_GETSOCKOPT, 165 | uintptr(conn.sock), 166 | syscall.IPPROTO_SCTP, 167 | SCTP_GET_LOCAL_ADDRS, 168 | uintptr(unsafe.Pointer(addrs)), 169 | uintptr(unsafe.Pointer(&length)), 170 | 0, 171 | ) 172 | if err == 0 { 173 | return FromSCTPGetAddrs(addrs) 174 | } 175 | return nil 176 | } 177 | 178 | // RemoteAddr returns the remote network address. 179 | func (conn *SCTPConn) RemoteAddr() net.Addr { 180 | if !conn.ok() { 181 | return nil 182 | } 183 | var ( 184 | data [4096]byte 185 | addrs = (*SCTPGetAddrs)(unsafe.Pointer(&data[0])) 186 | length = len(data) 187 | ) 188 | addrs.AssocId = 0 189 | _, _, err := syscall.Syscall6( 190 | syscall.SYS_GETSOCKOPT, 191 | uintptr(conn.sock), 192 | syscall.IPPROTO_SCTP, 193 | SCTP_GET_PEER_ADDRS, 194 | uintptr(unsafe.Pointer(addrs)), 195 | uintptr(unsafe.Pointer(&length)), 196 | 0, 197 | ) 198 | if err == 0 { 199 | return FromSCTPGetAddrs(addrs) 200 | } 201 | return nil 202 | } 203 | 204 | // SetDeadline sets the read and write deadlines. Not supported for SCTP. 205 | func (conn *SCTPConn) SetDeadline(_ time.Time) error { 206 | return syscall.ENOPROTOOPT 207 | } 208 | 209 | // SetReadDeadline sets the read deadline. Not supported for SCTP. 210 | func (conn *SCTPConn) SetReadDeadline(_ time.Time) error { 211 | return syscall.ENOPROTOOPT 212 | } 213 | 214 | // SetWriteDeadline sets the write deadline. Not supported for SCTP. 215 | func (conn *SCTPConn) SetWriteDeadline(_ time.Time) error { 216 | return syscall.ENOPROTOOPT 217 | } 218 | 219 | // SetWriteBufferSize sets the size of the send buffer. 220 | func (conn *SCTPConn) SetWriteBufferSize(bytes int) error { 221 | return syscall.SetsockoptInt(int(conn.sock), syscall.SOL_SOCKET, syscall.SO_SNDBUF, bytes) 222 | } 223 | 224 | // GetWriteBufferSize gets the size of the send buffer. 225 | func (conn *SCTPConn) GetWriteBufferSize() (int, error) { 226 | return syscall.GetsockoptInt(int(conn.sock), syscall.SOL_SOCKET, syscall.SO_SNDBUF) 227 | } 228 | 229 | // SetReadBufferSize sets the size of the receive buffer. 230 | func (conn *SCTPConn) SetReadBufferSize(bytes int) error { 231 | return syscall.SetsockoptInt(int(conn.sock), syscall.SOL_SOCKET, syscall.SO_RCVBUF, bytes) 232 | } 233 | 234 | // GetReadBufferSize gets the size of the receive buffer. 235 | func (conn *SCTPConn) GetReadBufferSize() (int, error) { 236 | return syscall.GetsockoptInt(int(conn.sock), syscall.SOL_SOCKET, syscall.SO_RCVBUF) 237 | } 238 | 239 | // SetEventSubscribe sets the SCTP event subscriptions. 240 | func (conn *SCTPConn) SetEventSubscribe(events *SCTPEventSubscribe) error { 241 | _, _, err := syscall.Syscall6( 242 | syscall.SYS_SETSOCKOPT, 243 | uintptr(conn.sock), 244 | SOL_SCTP, 245 | SCTP_EVENTS, 246 | uintptr(unsafe.Pointer(events)), 247 | unsafe.Sizeof(*events), 248 | 0, 249 | ) 250 | if err != 0 { 251 | return err 252 | } 253 | return nil 254 | } 255 | 256 | // GetEventSubscribe gets the current SCTP event subscriptions. 257 | func (conn *SCTPConn) GetEventSubscribe() (*SCTPEventSubscribe, error) { 258 | if !conn.ok() { 259 | return nil, syscall.EINVAL 260 | } 261 | var ( 262 | events SCTPEventSubscribe 263 | length = unsafe.Sizeof(events) 264 | ) 265 | _, _, err := syscall.Syscall6( 266 | syscall.SYS_GETSOCKOPT, 267 | uintptr(conn.sock), 268 | SOL_SCTP, 269 | SCTP_EVENTS, 270 | uintptr(unsafe.Pointer(&events)), 271 | uintptr(unsafe.Pointer(&length)), 272 | 0, 273 | ) 274 | if err != 0 { 275 | return nil, err 276 | } 277 | return &events, nil 278 | } 279 | 280 | // SetInitMsg sets the SCTP initialization message parameters. 281 | func (conn *SCTPConn) SetInitMsg(init *SCTPInitMsg) error { 282 | if !conn.ok() { 283 | return syscall.EINVAL 284 | } 285 | _, _, err := syscall.Syscall6( 286 | syscall.SYS_SETSOCKOPT, 287 | uintptr(conn.sock), 288 | SOL_SCTP, 289 | SCTP_INITMSG, 290 | uintptr(unsafe.Pointer(init)), 291 | unsafe.Sizeof(*init), 292 | 0, 293 | ) 294 | if err != 0 { 295 | return err 296 | } 297 | return nil 298 | } 299 | 300 | // GetInitMsg gets the current SCTP initialization message parameters. 301 | func (conn *SCTPConn) GetInitMsg() (*SCTPInitMsg, error) { 302 | if !conn.ok() { 303 | return nil, syscall.EINVAL 304 | } 305 | var ( 306 | init SCTPInitMsg 307 | length = unsafe.Sizeof(init) 308 | ) 309 | _, _, err := syscall.Syscall6( 310 | syscall.SYS_GETSOCKOPT, 311 | uintptr(conn.sock), 312 | SOL_SCTP, 313 | SCTP_INITMSG, 314 | uintptr(unsafe.Pointer(&init)), 315 | uintptr(unsafe.Pointer(&length)), 316 | 0, 317 | ) 318 | if err != 0 { 319 | return nil, err 320 | } 321 | return &init, nil 322 | } 323 | 324 | // SetDefaultSendParam sets the default send parameters for the association. 325 | func (conn *SCTPConn) SetDefaultSendParam(param *SCTPSndRcvInfo) error { 326 | if !conn.ok() { 327 | return syscall.EINVAL 328 | } 329 | _, _, err := syscall.Syscall6( 330 | syscall.SYS_SETSOCKOPT, 331 | uintptr(conn.sock), 332 | SOL_SCTP, 333 | SCTP_DEFAULT_SEND_PARAM, 334 | uintptr(unsafe.Pointer(param)), 335 | unsafe.Sizeof(*param), 336 | 0, 337 | ) 338 | if err != 0 { 339 | return err 340 | } 341 | return nil 342 | } 343 | 344 | // GetDefaultSendParam gets the default send parameters for the association. 345 | func (conn *SCTPConn) GetDefaultSendParam() (*SCTPSndRcvInfo, error) { 346 | if !conn.ok() { 347 | return nil, syscall.EINVAL 348 | } 349 | var ( 350 | param SCTPSndRcvInfo 351 | length = unsafe.Sizeof(param) 352 | ) 353 | _, _, err := syscall.Syscall6( 354 | syscall.SYS_GETSOCKOPT, 355 | uintptr(conn.sock), 356 | SOL_SCTP, 357 | SCTP_DEFAULT_SEND_PARAM, 358 | uintptr(unsafe.Pointer(¶m)), 359 | uintptr(unsafe.Pointer(&length)), 360 | 0, 361 | ) 362 | if err != 0 { 363 | return nil, err 364 | } 365 | return ¶m, nil 366 | } 367 | 368 | func (conn *SCTPConn) ok() bool { 369 | if nil != conn && conn.sock > 0 { 370 | return true 371 | } 372 | return false 373 | } 374 | 375 | // DialSCTP dials an SCTP connection to the remote address. 376 | func DialSCTP(network string, local, remote *SCTPAddr, init *SCTPInitMsg) (*SCTPConn, error) { 377 | switch network { 378 | case "sctp", "sctp4", "sctp6": 379 | default: 380 | return nil, &net.OpError{ 381 | Op: "dial", 382 | Net: network, 383 | Source: local.Addr(), 384 | Addr: remote.Addr(), 385 | Err: net.UnknownNetworkError(network), 386 | } 387 | } 388 | if remote == nil { 389 | return nil, &net.OpError{ 390 | Op: "dial", 391 | Net: network, 392 | Source: local.Addr(), 393 | Addr: remote.Addr(), 394 | Err: net.InvalidAddrError("invalid remote addr"), 395 | } 396 | } 397 | // syscall.SOCK_SEQPACKET vs syscall.SOCK_STREAM 398 | sock, err := SCTPSocket(AddrFamily(network), syscall.SOCK_STREAM) 399 | if err != nil { 400 | return nil, err 401 | } 402 | conn := &SCTPConn{ 403 | sock: int64(sock), 404 | } 405 | defer func() { 406 | if err != nil && conn != nil { 407 | _ = conn.Close() 408 | } 409 | }() 410 | if err = syscall.SetsockoptInt(sock, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1); err != nil { 411 | return nil, err 412 | } 413 | if err = conn.SetInitMsg(init); err != nil { 414 | return nil, err 415 | } 416 | if local != nil { 417 | if err = SCTPBind(sock, local, SCTP_BINDX_ADD_ADDR); err != nil { 418 | return nil, err 419 | } 420 | } 421 | conn.assoc, err = SCTPConnect(sock, remote) 422 | if err != nil { 423 | return nil, err 424 | } 425 | return conn, nil 426 | } 427 | -------------------------------------------------------------------------------- /test_test.go: -------------------------------------------------------------------------------- 1 | package sctp_go 2 | 3 | import ( 4 | "encoding/hex" 5 | "fmt" 6 | "syscall" 7 | "testing" 8 | "unsafe" 9 | ) 10 | 11 | func TestSizes(t *testing.T) { 12 | { 13 | temp := &IoVector{} 14 | if unsafe.Sizeof(*temp) != IoVectorSize { 15 | fmt.Println(unsafe.Sizeof(*temp)) 16 | fmt.Println(IoVectorSize) 17 | t.Error("IoVector sizes don't match") 18 | } else { 19 | fmt.Println("IoVectorSize: ", IoVectorSize) 20 | } 21 | } 22 | { 23 | temp := &MsgHeader{} 24 | if unsafe.Sizeof(*temp) != MsgHeaderSize { 25 | fmt.Println(unsafe.Sizeof(*temp)) 26 | fmt.Println(MsgHeaderSize) 27 | t.Error("MsgHeader sizes don't match") 28 | } else { 29 | fmt.Println("MsgHeaderSize: ", MsgHeaderSize) 30 | } 31 | } 32 | { 33 | temp := &CMsgHeader{} 34 | if unsafe.Sizeof(*temp) != CMsgHeaderSize { 35 | fmt.Println(unsafe.Sizeof(*temp)) 36 | fmt.Println(CMsgHeaderSize) 37 | t.Error("CMsgHeader sizes don't match") 38 | } else { 39 | fmt.Println("CMsgHeaderSize: ", CMsgHeaderSize) 40 | } 41 | } 42 | { 43 | temp := &SCTPSndRcvInfo{} 44 | if unsafe.Sizeof(*temp) != SCTPSndRcvInfoSize { 45 | fmt.Println(unsafe.Sizeof(*temp)) 46 | fmt.Println(SCTPSndRcvInfoSize) 47 | t.Error("SCTPSndRcvInfo sizes don't match") 48 | } else { 49 | fmt.Println("SCTPSndRcvInfoSize: ", SCTPSndRcvInfoSize) 50 | } 51 | } 52 | { 53 | temp := &SCTPInitMsg{} 54 | if unsafe.Sizeof(*temp) != SCTPInitMsgSize { 55 | fmt.Println(unsafe.Sizeof(*temp)) 56 | fmt.Println(SCTPInitMsgSize) 57 | t.Error("SCTPInitMsg sizes don't match") 58 | } else { 59 | fmt.Println("SCTPInitMsgSize: ", SCTPInitMsgSize) 60 | } 61 | } 62 | { 63 | temp := &SCTPGetAddrsOld{} 64 | if unsafe.Sizeof(*temp) != SCTPGetAddrsOldSize { 65 | fmt.Println(unsafe.Sizeof(*temp)) 66 | fmt.Println(SCTPGetAddrsOldSize) 67 | t.Error("SCTPGetAddrsOld sizes don't match") 68 | } else { 69 | fmt.Println("SCTPGetAddrsOldSize: ", SCTPGetAddrsOldSize) 70 | } 71 | } 72 | { 73 | temp := &SCTPEventSubscribe{} 74 | if unsafe.Sizeof(*temp) != SCTPEventSubscribeSize { 75 | fmt.Println(unsafe.Sizeof(*temp)) 76 | fmt.Println(SCTPEventSubscribeSize) 77 | t.Error("SCTPEventSubscribe sizes don't match") 78 | } else { 79 | fmt.Println("SCTPEventSubscribeSize: ", SCTPEventSubscribeSize) 80 | } 81 | } 82 | { 83 | temp := &SockAddrStorage{} 84 | if unsafe.Sizeof(*temp) != SockAddrStorageSize { 85 | fmt.Println(unsafe.Sizeof(*temp)) 86 | fmt.Println(SockAddrStorageSize) 87 | t.Error("SockAddrStorage sizes don't match") 88 | } else { 89 | fmt.Println("SockAddrStorageSize: ", SockAddrStorageSize) 90 | } 91 | } 92 | { 93 | temp := &SockAddrIn{} 94 | if unsafe.Sizeof(*temp) != SockAddrInSize { 95 | fmt.Println(unsafe.Sizeof(*temp)) 96 | fmt.Println(SockAddrInSize) 97 | t.Error("SockAddrIn sizes don't match") 98 | } else { 99 | fmt.Println("SockAddrInSize: ", SockAddrInSize) 100 | } 101 | } 102 | { 103 | temp := &SockAddrIn6{} 104 | if unsafe.Sizeof(*temp) != SockAddrIn6Size { 105 | fmt.Println(unsafe.Sizeof(*temp)) 106 | fmt.Println(SockAddrIn6Size) 107 | t.Error("SockAddrIn6 sizes don't match") 108 | } else { 109 | fmt.Println("SockAddrIn6Size: ", SockAddrIn6Size) 110 | } 111 | } 112 | { 113 | temp := &InAddr{} 114 | if unsafe.Sizeof(*temp) != InAddrSize { 115 | fmt.Println(unsafe.Sizeof(*temp)) 116 | fmt.Println(InAddrSize) 117 | t.Error("InAddr sizes don't match") 118 | } else { 119 | fmt.Println("InAddrSize: ", InAddrSize) 120 | } 121 | } 122 | { 123 | temp := &In6Addr{} 124 | if unsafe.Sizeof(*temp) != In6AddrSize { 125 | fmt.Println(unsafe.Sizeof(*temp)) 126 | fmt.Println(In6AddrSize) 127 | t.Error("In6AddrSize sizes don't match") 128 | } else { 129 | fmt.Println("In6AddrSize: ", In6AddrSize) 130 | } 131 | } 132 | { 133 | temp := &SCTPSetPeerPrimary{} 134 | if unsafe.Sizeof(*temp) != SCTPSetPeerPrimarySize { 135 | fmt.Println(unsafe.Sizeof(*temp)) 136 | fmt.Println(SCTPSetPeerPrimarySize) 137 | t.Error("SCTPSetPeerPrimary sizes don't match") 138 | } else { 139 | fmt.Println("SCTPSetPeerPrimarySize: ", SCTPSetPeerPrimarySize) 140 | } 141 | } 142 | { 143 | temp := &SCTPPrimaryAddr{} 144 | if unsafe.Sizeof(*temp) != SCTPPrimaryAddrSize { 145 | fmt.Println(unsafe.Sizeof(*temp)) 146 | fmt.Println(SCTPPrimaryAddrSize) 147 | t.Error("SCTPPrimaryAddr sizes don't match") 148 | } else { 149 | fmt.Println("SCTPPrimaryAddrSize: ", SCTPPrimaryAddrSize) 150 | } 151 | } 152 | { 153 | temp := &SCTPPeelOffArg{} 154 | if unsafe.Sizeof(*temp) != SCTPPeelOffArgSize { 155 | fmt.Println(unsafe.Sizeof(*temp)) 156 | fmt.Println(SCTPPeelOffArgSize) 157 | t.Error("SCTPPeelOffArg sizes don't match") 158 | } else { 159 | fmt.Println("SCTPPeelOffArgSize: ", SCTPPeelOffArgSize) 160 | } 161 | } 162 | { 163 | temp := &SCTPPeelOffFlagsArg{} 164 | if unsafe.Sizeof(*temp) != SCTPPeelOffFlagsArgSize { 165 | fmt.Println(unsafe.Sizeof(*temp)) 166 | fmt.Println(SCTPPeelOffFlagsArgSize) 167 | t.Error("SCTPPeelOffFlagsArg sizes don't match") 168 | } else { 169 | fmt.Println("SCTPPeelOffFlagsArgSize: ", SCTPPeelOffFlagsArgSize) 170 | } 171 | } 172 | { 173 | temp := &SCTPAssocChange{} 174 | if unsafe.Sizeof(*temp) != SCTPAssocChangeSize { 175 | fmt.Println(unsafe.Sizeof(*temp)) 176 | fmt.Println(SCTPAssocChangeSize) 177 | t.Error("SCTPAssocChange sizes don't match") 178 | } else { 179 | fmt.Println("SCTPAssocChangeSize: ", SCTPAssocChangeSize) 180 | } 181 | } 182 | { 183 | temp := &SCTPPAddrChange{} 184 | if unsafe.Sizeof(*temp) != SCTPPAddrChangeSize { 185 | fmt.Println(unsafe.Sizeof(*temp)) 186 | fmt.Println(SCTPPAddrChangeSize) 187 | t.Error("SCTPPAddrChange sizes don't match") 188 | } else { 189 | fmt.Println("SCTPPAddrChangeSize: ", SCTPPAddrChangeSize) 190 | } 191 | } 192 | { 193 | temp := &SCTPRemoteError{} 194 | if unsafe.Sizeof(*temp) != SCTPRemoteErrorSize { 195 | fmt.Println(unsafe.Sizeof(*temp)) 196 | fmt.Println(SCTPRemoteErrorSize) 197 | t.Error("SCTPRemoteError sizes don't match") 198 | } else { 199 | fmt.Println("SCTPRemoteErrorSize: ", SCTPRemoteErrorSize) 200 | } 201 | } 202 | { 203 | temp := &SCTPSendFailed{} 204 | if unsafe.Sizeof(*temp) != SCTPSendFailedSize { 205 | fmt.Println(unsafe.Sizeof(*temp)) 206 | fmt.Println(SCTPSendFailedSize) 207 | t.Error("SCTPSendFailed sizes don't match") 208 | } else { 209 | fmt.Println("SCTPSendFailedSize: ", SCTPSendFailedSize) 210 | } 211 | } 212 | { 213 | temp := &SCTPShutdownEvent{} 214 | if unsafe.Sizeof(*temp) != SCTPShutdownEventSize { 215 | fmt.Println(unsafe.Sizeof(*temp)) 216 | fmt.Println(SCTPShutdownEventSize) 217 | t.Error("SCTPShutdownEvent sizes don't match") 218 | } else { 219 | fmt.Println("SCTPShutdownEventSize: ", SCTPShutdownEventSize) 220 | } 221 | } 222 | { 223 | temp := &SCTPAdaptationEvent{} 224 | if unsafe.Sizeof(*temp) != SCTPAdaptationEventSize { 225 | fmt.Println(unsafe.Sizeof(*temp)) 226 | fmt.Println(SCTPAdaptationEventSize) 227 | t.Error("SCTPAdaptationEvent sizes don't match") 228 | } else { 229 | fmt.Println("SCTPAdaptationEventSize: ", SCTPAdaptationEventSize) 230 | } 231 | } 232 | { 233 | temp := &SCTPPDApiEvent{} 234 | if unsafe.Sizeof(*temp) != SCTPPDApiEventSize { 235 | fmt.Println(unsafe.Sizeof(*temp)) 236 | fmt.Println(SCTPPDApiEventSize) 237 | t.Error("SCTPPDApiEvent sizes don't match") 238 | } else { 239 | fmt.Println("SCTPPDApiEventSize: ", SCTPPDApiEventSize) 240 | } 241 | } 242 | { 243 | temp := &SCTPAuthKeyEvent{} 244 | if unsafe.Sizeof(*temp) != SCTPAuthKeyEventSize { 245 | fmt.Println(unsafe.Sizeof(*temp)) 246 | fmt.Println(SCTPAuthKeyEventSize) 247 | t.Error("SCTPAuthKeyEvent sizes don't match") 248 | } else { 249 | fmt.Println("SCTPAuthKeyEventSize: ", SCTPAuthKeyEventSize) 250 | } 251 | } 252 | { 253 | temp := &SCTPSenderDryEvent{} 254 | if unsafe.Sizeof(*temp) != SCTPSenderDryEventSize { 255 | fmt.Println(unsafe.Sizeof(*temp)) 256 | fmt.Println(SCTPSenderDryEventSize) 257 | t.Error("SCTPSenderDryEvent sizes don't match") 258 | } else { 259 | fmt.Println("SCTPSenderDryEventSize: ", SCTPSenderDryEventSize) 260 | } 261 | } 262 | { 263 | temp := &SCTPStreamResetEvent{} 264 | if unsafe.Sizeof(*temp) != SCTPStreamResetEventSize { 265 | fmt.Println(unsafe.Sizeof(*temp)) 266 | fmt.Println(SCTPStreamResetEventSize) 267 | t.Error("SCTPStreamResetEvent sizes don't match") 268 | } else { 269 | fmt.Println("SCTPStreamResetEventSize: ", SCTPStreamResetEventSize) 270 | } 271 | } 272 | { 273 | temp := &SCTPAssocResetEvent{} 274 | if unsafe.Sizeof(*temp) != SCTPAssocResetEventSize { 275 | fmt.Println(unsafe.Sizeof(*temp)) 276 | fmt.Println(SCTPAssocResetEventSize) 277 | t.Error("SCTPAssocResetEvent sizes don't match") 278 | } else { 279 | fmt.Println("SCTPAssocResetEventSize: ", SCTPAssocResetEventSize) 280 | } 281 | } 282 | { 283 | temp := &SCTPAssocResetEvent{} 284 | if unsafe.Sizeof(*temp) != SCTPAssocResetEventSize { 285 | fmt.Println(unsafe.Sizeof(*temp)) 286 | fmt.Println(SCTPAssocResetEventSize) 287 | t.Error("SCTPAssocResetEvent sizes don't match") 288 | } else { 289 | fmt.Println("SCTPAssocResetEventSize: ", SCTPAssocResetEventSize) 290 | } 291 | } 292 | { 293 | temp := &SCTPStreamChangeEvent{} 294 | if unsafe.Sizeof(*temp) != SCTPStreamChangeEventSize { 295 | fmt.Println(unsafe.Sizeof(*temp)) 296 | fmt.Println(SCTPStreamChangeEventSize) 297 | t.Error("SCTPStreamChangeEvent sizes don't match") 298 | } else { 299 | fmt.Println("SCTPStreamChangeEventSize: ", SCTPStreamChangeEventSize) 300 | } 301 | } 302 | { 303 | temp := &SCTPRTOInfo{} 304 | if unsafe.Sizeof(*temp) != SCTPRTOInfoSize { 305 | fmt.Println(unsafe.Sizeof(*temp)) 306 | fmt.Println(SCTPRTOInfoSize) 307 | t.Error("SCTPRTOInfo sizes don't match") 308 | } else { 309 | fmt.Println("SCTPRTOInfoSize: ", SCTPRTOInfoSize) 310 | } 311 | } 312 | { 313 | temp := &SCTPResetStreams{} 314 | if unsafe.Sizeof(*temp) != SCTPResetStreamsSize { 315 | fmt.Println(unsafe.Sizeof(*temp)) 316 | fmt.Println(SCTPResetStreamsSize) 317 | t.Error("SCTPResetStreams sizes don't match") 318 | } else { 319 | fmt.Println("SCTPResetStreamsSize: ", SCTPResetStreamsSize) 320 | } 321 | } 322 | { 323 | temp := &SCTPAddStreams{} 324 | if unsafe.Sizeof(*temp) != SCTPAddStreamsSize { 325 | fmt.Println(unsafe.Sizeof(*temp)) 326 | fmt.Println(SCTPAddStreamsSize) 327 | t.Error("SCTPAddStreams sizes don't match") 328 | } else { 329 | fmt.Println("SCTPAddStreamsSize: ", SCTPAddStreamsSize) 330 | } 331 | } 332 | { 333 | temp := &SCTPAssocParams{} 334 | if unsafe.Sizeof(*temp) != SCTPAssocParamsSize { 335 | fmt.Println(unsafe.Sizeof(*temp)) 336 | fmt.Println(SCTPAssocParamsSize) 337 | t.Error("SCTPAssocParams sizes don't match") 338 | } else { 339 | fmt.Println("SCTPAssocParamsSize: ", SCTPAssocParamsSize) 340 | } 341 | } 342 | { 343 | temp := &SCTPSetAdaptation{} 344 | if unsafe.Sizeof(*temp) != SCTPSetAdaptationSize { 345 | fmt.Println(unsafe.Sizeof(*temp)) 346 | fmt.Println(SCTPSetAdaptationSize) 347 | t.Error("SCTPSetAdaptation sizes don't match") 348 | } else { 349 | fmt.Println("SCTPSetAdaptationSize: ", SCTPSetAdaptationSize) 350 | } 351 | } 352 | { 353 | temp := &SCTPPeerAddrParams{} 354 | if unsafe.Sizeof(*temp) != SCTPPeerAddrParamsSize { 355 | fmt.Println(unsafe.Sizeof(*temp)) 356 | fmt.Println(SCTPPeerAddrParamsSize) 357 | { 358 | if len(Pack(temp)) != SCTPPeerAddrParamsSize { 359 | t.Error("SCTPPeerAddrParams sizes don't match") 360 | } else { 361 | fmt.Println("SCTPPeerAddrParams sizes don't match") 362 | } 363 | } 364 | } else { 365 | fmt.Println("SCTPPeerAddrParamsSize: ", SCTPPeerAddrParamsSize) 366 | } 367 | } 368 | { 369 | temp := &SCTPPeerAddrInfo{} 370 | if unsafe.Sizeof(*temp) != SCTPPeerAddrInfoSize { 371 | fmt.Println(unsafe.Sizeof(*temp)) 372 | fmt.Println(SCTPPeerAddrInfoSize) 373 | t.Error("SCTPPeerAddrInfo sizes don't match") 374 | } else { 375 | fmt.Println("SCTPPeerAddrInfoSize: ", SCTPPeerAddrInfoSize) 376 | } 377 | } 378 | { 379 | temp := &SCTPAssocValue{} 380 | if unsafe.Sizeof(*temp) != SCTPAssocValueSize { 381 | fmt.Println(unsafe.Sizeof(*temp)) 382 | fmt.Println(SCTPAssocValueSize) 383 | t.Error("SCTPAssocValue sizes don't match") 384 | } else { 385 | fmt.Println("SCTPAssocValueSize: ", SCTPAssocValueSize) 386 | } 387 | } 388 | { 389 | temp := &SCTPSackInfo{} 390 | if unsafe.Sizeof(*temp) != SCTPSackInfoSize { 391 | fmt.Println(unsafe.Sizeof(*temp)) 392 | fmt.Println(SCTPSackInfoSize) 393 | t.Error("SCTPSackInfo sizes don't match") 394 | } else { 395 | fmt.Println("SCTPSackInfoSize: ", SCTPSackInfoSize) 396 | } 397 | } 398 | { 399 | temp := &SCTPStreamValue{} 400 | if unsafe.Sizeof(*temp) != SCTPStreamValueSize { 401 | fmt.Println(unsafe.Sizeof(*temp)) 402 | fmt.Println(SCTPStreamValueSize) 403 | t.Error("SCTPStreamValue sizes don't match") 404 | } else { 405 | fmt.Println("SCTPStreamValueSize: ", SCTPStreamValueSize) 406 | } 407 | } 408 | { 409 | temp := &SCTPStatus{} 410 | if unsafe.Sizeof(*temp) != SCTPStatusSize { 411 | fmt.Println(unsafe.Sizeof(*temp)) 412 | fmt.Println(SCTPStatusSize) 413 | t.Error("SCTPStatus sizes don't match") 414 | } else { 415 | fmt.Println("SCTPStatusSize: ", SCTPStatusSize) 416 | } 417 | } 418 | { 419 | temp := &SCTPAuthKeyId{} 420 | if unsafe.Sizeof(*temp) != SCTPAuthKeyIdSize { 421 | fmt.Println(unsafe.Sizeof(*temp)) 422 | fmt.Println(SCTPAuthKeyIdSize) 423 | t.Error("SCTPAuthKeyId sizes don't match") 424 | } else { 425 | fmt.Println("SCTPAuthKeyIdSize: ", SCTPAuthKeyIdSize) 426 | } 427 | } 428 | { 429 | temp := &SCTPAssocStats{} 430 | if unsafe.Sizeof(*temp) != SCTPAssocStatsSize { 431 | fmt.Println(unsafe.Sizeof(*temp)) 432 | fmt.Println(SCTPAssocStatsSize) 433 | t.Error("SCTPAssocStats sizes don't match") 434 | } else { 435 | fmt.Println("SCTPAssocStatsSize: ", SCTPAssocStatsSize) 436 | } 437 | } 438 | { 439 | temp := &SCTPPeerAddrThresholds{} 440 | if unsafe.Sizeof(*temp) != SCTPPeerAddrThresholdsSize { 441 | fmt.Println(unsafe.Sizeof(*temp)) 442 | fmt.Println(SCTPPeerAddrThresholdsSize) 443 | t.Error("SCTPPeerAddrThresholds sizes don't match") 444 | } else { 445 | fmt.Println("SCTPPeerAddrThresholdsSize: ", SCTPPeerAddrThresholdsSize) 446 | } 447 | } 448 | { 449 | temp := &SCTPPRStatus{} 450 | if unsafe.Sizeof(*temp) != SCTPPRStatusSize { 451 | fmt.Println(unsafe.Sizeof(*temp)) 452 | fmt.Println(SCTPPRStatusSize) 453 | t.Error("SCTPPRStatus sizes don't match") 454 | } else { 455 | fmt.Println("SCTPPRStatusSize: ", SCTPPRStatusSize) 456 | } 457 | } 458 | { 459 | temp := &SCTPDefaultPRInfo{} 460 | if unsafe.Sizeof(*temp) != SCTPDefaultPRInfoSize { 461 | fmt.Println(unsafe.Sizeof(*temp)) 462 | fmt.Println(SCTPDefaultPRInfoSize) 463 | t.Error("SCTPDefaultPRInfo sizes don't match") 464 | } else { 465 | fmt.Println("SCTPDefaultPRInfoSize: ", SCTPDefaultPRInfoSize) 466 | } 467 | } 468 | { 469 | temp := &SCTPEvent{} 470 | if unsafe.Sizeof(*temp) != SCTPEventSize { 471 | fmt.Println(unsafe.Sizeof(*temp)) 472 | fmt.Println(SCTPEventSize) 473 | t.Error("SCTPEvent sizes don't match") 474 | } else { 475 | fmt.Println("SCTPEventSize: ", SCTPEventSize) 476 | } 477 | } 478 | { 479 | temp := &SCTPInfo{} 480 | if unsafe.Sizeof(*temp) != SCTPInfoSize { 481 | fmt.Println(unsafe.Sizeof(*temp)) 482 | fmt.Println(SCTPInfoSize) 483 | t.Error("SCTPInfo sizes don't match") 484 | } else { 485 | fmt.Println("SCTPInfoSize: ", SCTPInfoSize) 486 | } 487 | } 488 | { 489 | fmt.Println("CMSG_SPACE(sizeof(SCTPSndRcvInfo)): ", syscall.CmsgSpace(SCTPSndRcvInfoSize)) 490 | } 491 | } 492 | 493 | func TestPacking(t *testing.T) { 494 | var buffer []byte 495 | { 496 | hdr := &syscall.Cmsghdr{ 497 | Level: syscall.IPPROTO_SCTP, 498 | Type: SCTP_SNDRCV, 499 | } 500 | hdr.SetLen(syscall.CmsgSpace(SCTPSndRcvInfoSize)) 501 | info := &SCTPSndRcvInfo{ 502 | AssocId: 100, 503 | } 504 | buffer = append(buffer, Pack(hdr)...) 505 | buffer = append(buffer, Pack(info)...) 506 | fmt.Println(len(Pack(hdr))) 507 | fmt.Println(len(Pack(info))) 508 | } 509 | fmt.Printf("%s", hex.Dump(buffer)) 510 | fmt.Println(len(buffer)) 511 | fmt.Println(CMsgHeaderSize) 512 | if len(buffer) != (CMsgHeaderSize + SCTPSndRcvInfoSize) { 513 | t.Error("Expected sizes don't match") 514 | } 515 | } 516 | 517 | func TestMakeSockaddr(t *testing.T) { 518 | addr, err := MakeSCTPAddr("sctp4", "127.0.0.1:12345") 519 | if nil != err { 520 | fmt.Println("Error: ", err) 521 | t.FailNow() 522 | } 523 | { 524 | buffer := MakeSockaddr(addr) 525 | fmt.Println(hex.Dump(buffer)) 526 | fmt.Println(len(buffer)) 527 | } 528 | } 529 | -------------------------------------------------------------------------------- /sctp.go: -------------------------------------------------------------------------------- 1 | package sctp_go 2 | 3 | import ( 4 | "bytes" 5 | "encoding/binary" 6 | "encoding/gob" 7 | "fmt" 8 | "strings" 9 | "syscall" 10 | "unsafe" 11 | ) 12 | 13 | var ( 14 | endian binary.ByteOrder = binary.LittleEndian 15 | ) 16 | 17 | func init() { 18 | endian = Endianness() 19 | } 20 | 21 | func htons(port uint16) uint16 { 22 | if endian == binary.LittleEndian { 23 | return (port << 8 & 0xff00) | (port >> 8 & 0xff) 24 | } 25 | return port 26 | } 27 | 28 | func ntohs(port uint16) uint16 { 29 | if endian == binary.LittleEndian { 30 | return (port << 8 & 0xff00) | (port >> 8 & 0xff) 31 | } 32 | return port 33 | } 34 | 35 | // Endianness returns the byte order (big-endian or little-endian) of the system. 36 | func Endianness() binary.ByteOrder { 37 | i := uint16(1) 38 | if *(*byte)(unsafe.Pointer(&i)) == 0 { 39 | return binary.BigEndian 40 | } 41 | return binary.LittleEndian 42 | } 43 | 44 | // DetectAddrFamily detects the address family (AF_INET or AF_INET6) from the network string. 45 | func DetectAddrFamily(network string) int { 46 | if strings.HasSuffix(network, "4") { 47 | return syscall.AF_INET 48 | } 49 | return syscall.AF_INET6 50 | } 51 | 52 | // Pack serializes the given value into a byte slice using the system's endianness. 53 | func Pack(v interface{}) []byte { 54 | var buf bytes.Buffer 55 | if err := binary.Write(&buf, endian, v); err != nil { 56 | return nil 57 | } 58 | return buf.Bytes() 59 | } 60 | 61 | // SCTPSocket creates a new SCTP socket with the specified address family and type. 62 | func SCTPSocket(family, flag int) (int, error) { 63 | if family == syscall.AF_INET { 64 | return syscall.Socket(syscall.AF_INET, flag, syscall.IPPROTO_SCTP) 65 | } 66 | return syscall.Socket(syscall.AF_INET6, flag, syscall.IPPROTO_SCTP) 67 | } 68 | 69 | // SCTPBind binds the SCTP socket to the specified address with the given flags. 70 | func SCTPBind(sock int, addr *SCTPAddr, flags int) error { 71 | var option uintptr 72 | switch flags { 73 | case SCTP_BINDX_ADD_ADDR: 74 | option = SCTP_SOCKOPT_BINDX_ADD 75 | case SCTP_BINDX_REM_ADDR: 76 | option = SCTP_SOCKOPT_BINDX_REM 77 | default: 78 | return syscall.EINVAL 79 | } 80 | 81 | buffer := MakeSockaddr(addr) 82 | if len(buffer) == 0 { 83 | return syscall.EINVAL 84 | } 85 | _, _, errno := syscall.Syscall6( 86 | syscall.SYS_SETSOCKOPT, 87 | uintptr(sock), 88 | SOL_SCTP, 89 | option, 90 | uintptr(unsafe.Pointer(&buffer[0])), 91 | uintptr(len(buffer)), 92 | 0, 93 | ) 94 | if errno != 0 { 95 | return errno 96 | } 97 | return nil 98 | } 99 | 100 | // SCTPConnect connects the SCTP socket to the specified address and returns the association ID. 101 | func SCTPConnect(sock int, addr *SCTPAddr) (int, error) { 102 | buffer := MakeSockaddr(addr) 103 | if len(buffer) == 0 { 104 | return 0, syscall.EINVAL 105 | } 106 | addrs := &SCTPGetAddrsOld{ 107 | AssocId: 0, 108 | Num: int32(len(buffer)), 109 | Addrs: uintptr(unsafe.Pointer(&buffer[0])), 110 | } 111 | length := unsafe.Sizeof(*addr) 112 | _, _, errno := syscall.Syscall6( 113 | syscall.SYS_GETSOCKOPT, 114 | uintptr(sock), 115 | syscall.IPPROTO_SCTP, 116 | SCTP_SOCKOPT_CONNECTX3, 117 | uintptr(unsafe.Pointer(addrs)), 118 | uintptr(unsafe.Pointer(&length)), 119 | 0, 120 | ) 121 | if errno == 0 || errno == syscall.EINPROGRESS { 122 | return int(addrs.AssocId), nil 123 | } 124 | if errno != syscall.ENOPROTOOPT { 125 | return 0, errno 126 | } 127 | // Fallback to CONNECTX 128 | assoc, _, errno := syscall.Syscall6( 129 | syscall.SYS_SETSOCKOPT, 130 | uintptr(sock), 131 | syscall.IPPROTO_SCTP, 132 | SCTP_SOCKOPT_CONNECTX, 133 | uintptr(unsafe.Pointer(&buffer[0])), 134 | uintptr(len(buffer)), 135 | 0, 136 | ) 137 | if errno != 0 { 138 | return 0, errno 139 | } 140 | return int(assoc), nil 141 | } 142 | 143 | // SCTPPeelOffFlag peels off an association from the SCTP socket with the specified flags and returns a new SCTPConn. 144 | func SCTPPeelOffFlag(sock, assoc, flags int) (*SCTPConn, error) { 145 | if flags == 0 { 146 | return SCTPPeelOff(sock, assoc) 147 | } 148 | var params = SCTPPeelOffFlagsArg{ 149 | Arg: SCTPPeelOffArg{ 150 | AssocId: int32(assoc), 151 | Sd: 0, 152 | }, 153 | Flags: uint32(flags), 154 | } 155 | length := unsafe.Sizeof(params) 156 | _, _, errno := syscall.Syscall6( 157 | syscall.SYS_GETSOCKOPT, 158 | uintptr(sock), 159 | syscall.IPPROTO_SCTP, 160 | SCTP_SOCKOPT_PEELOFF_FLAGS, 161 | uintptr(unsafe.Pointer(¶ms)), 162 | uintptr(unsafe.Pointer(&length)), 163 | 0, 164 | ) 165 | if errno != 0 { 166 | return nil, errno 167 | } 168 | return NewSCTPConn(int(params.Arg.Sd)), nil 169 | } 170 | 171 | // SCTPPeelOff peels off an association from the SCTP socket and returns a new SCTPConn. 172 | func SCTPPeelOff(sock, assoc int) (*SCTPConn, error) { 173 | var params = SCTPPeelOffArg{ 174 | AssocId: int32(assoc), 175 | Sd: 0, 176 | } 177 | length := unsafe.Sizeof(params) 178 | _, _, errno := syscall.Syscall6( 179 | syscall.SYS_GETSOCKOPT, 180 | uintptr(sock), 181 | syscall.IPPROTO_SCTP, 182 | SCTP_SOCKOPT_PEELOFF, 183 | uintptr(unsafe.Pointer(¶ms)), 184 | uintptr(unsafe.Pointer(&length)), 185 | 0, 186 | ) 187 | if errno != 0 { 188 | return nil, errno 189 | } 190 | return NewSCTPConn(int(params.Sd)), nil 191 | } 192 | 193 | // AddrFamily returns the address family (AF_INET or AF_INET6) based on the network string. 194 | func AddrFamily(network string) int { 195 | if strings.HasSuffix(network, "4") { 196 | return syscall.AF_INET 197 | } 198 | return syscall.AF_INET6 199 | } 200 | 201 | // Clone performs a deep copy of the 'from' interface to the 'to' interface using gob encoding. 202 | func Clone(from, to interface{}) error { 203 | var ( 204 | buffer = new(bytes.Buffer) 205 | encoder = gob.NewEncoder(buffer) 206 | decoder = gob.NewDecoder(buffer) 207 | ) 208 | if err := encoder.Encode(from); err != nil { 209 | return err 210 | } 211 | return decoder.Decode(to) 212 | } 213 | 214 | // ParseSndRcvInfo parses the socket control message data and populates the SCTPSndRcvInfo struct. 215 | func ParseSndRcvInfo(info *SCTPSndRcvInfo, data []byte) { 216 | if info == nil || len(data) == 0 { 217 | return 218 | } 219 | messages, err := syscall.ParseSocketControlMessage(data) 220 | if err != nil { 221 | return 222 | } 223 | for _, message := range messages { 224 | if message.Header.Level == IPPROTO_SCTP && message.Header.Type == SCTP_SNDRCV { 225 | temp := (*SCTPSndRcvInfo)(unsafe.Pointer(&message.Data[0])) 226 | *info = *temp 227 | break 228 | } 229 | } 230 | } 231 | 232 | // ParseDataIOEvent parses the notification data into a SCTPNotificationHeader. 233 | func ParseDataIOEvent(data []byte) (Notification, error) { 234 | if len(data) < SCTPNotificationHeaderSize { 235 | return nil, fmt.Errorf("invalid data len, too small") 236 | } 237 | temp := (*SCTPNotificationHeader)(unsafe.Pointer(&data[0])) 238 | return &SCTPNotificationHeader{ 239 | Type: temp.Type, 240 | Flags: temp.Flags, 241 | Length: temp.Length, 242 | }, nil 243 | } 244 | 245 | // ParseAssocChangeEvent parses the notification data into a SCTPAssocChange. 246 | func ParseAssocChangeEvent(data []byte) (Notification, error) { 247 | if len(data) < int(unsafe.Sizeof(SCTPAssocChange{})) { 248 | return nil, fmt.Errorf("invalid data len, too small") 249 | } 250 | temp := (*SCTPAssocChange)(unsafe.Pointer(&data[0])) 251 | return &SCTPAssocChange{ 252 | Type: temp.Type, 253 | Flags: temp.Flags, 254 | Length: temp.Length, 255 | State: temp.State, 256 | Error: temp.Error, 257 | OutboundStreams: temp.OutboundStreams, 258 | InboundStreams: temp.InboundStreams, 259 | AssocId: temp.AssocId, 260 | }, nil 261 | } 262 | 263 | // ParsePeerAddrChangeEvent parses the notification data into a SCTPPAddrChange. 264 | func ParsePeerAddrChangeEvent(data []byte) (Notification, error) { 265 | if len(data) < int(unsafe.Sizeof(SCTPPAddrChange{})) { 266 | return nil, fmt.Errorf("invalid data len, too small") 267 | } 268 | var ( 269 | temp = (*SCTPPAddrChange)(unsafe.Pointer(&data[0])) 270 | addr [128]byte 271 | ) 272 | copy(addr[:], temp.Addr[:]) 273 | return &SCTPPAddrChange{ 274 | Type: temp.Type, 275 | Flags: temp.Flags, 276 | Length: temp.Length, 277 | Addr: addr, 278 | State: temp.State, 279 | Error: temp.Error, 280 | AssocId: temp.AssocId, 281 | }, nil 282 | } 283 | 284 | // ParseSendFailedEvent parses the notification data into a SCTPSendFailed. 285 | func ParseSendFailedEvent(data []byte) (Notification, error) { 286 | if len(data) < int(unsafe.Sizeof(SCTPSendFailed{})) { 287 | return nil, fmt.Errorf("invalid data len, too small") 288 | } 289 | temp := (*SCTPSendFailed)(unsafe.Pointer(&data[0])) 290 | return &SCTPSendFailed{ 291 | Type: temp.Type, 292 | Flags: temp.Flags, 293 | Length: temp.Length, 294 | Error: temp.Error, 295 | Info: temp.Info, 296 | AssocId: temp.AssocId, 297 | }, nil 298 | } 299 | 300 | // ParseRemoteErrorEvent parses the notification data into a SCTPRemoteError. 301 | func ParseRemoteErrorEvent(data []byte) (Notification, error) { 302 | if len(data) < int(unsafe.Sizeof(SCTPRemoteError{})) { 303 | return nil, fmt.Errorf("invalid data len, too small") 304 | } 305 | temp := (*SCTPRemoteError)(unsafe.Pointer(&data[0])) 306 | return &SCTPRemoteError{ 307 | Type: temp.Type, 308 | Flags: temp.Flags, 309 | Length: temp.Length, 310 | Error: temp.Error, 311 | AssocId: temp.AssocId, 312 | }, nil 313 | } 314 | 315 | // ParseShutdownEvent parses the notification data into a SCTPShutdownEvent. 316 | func ParseShutdownEvent(data []byte) (Notification, error) { 317 | if len(data) < int(unsafe.Sizeof(SCTPShutdownEvent{})) { 318 | return nil, fmt.Errorf("invalid data len, too small") 319 | } 320 | temp := (*SCTPShutdownEvent)(unsafe.Pointer(&data[0])) 321 | return &SCTPShutdownEvent{ 322 | Type: temp.Type, 323 | Flags: temp.Flags, 324 | Length: temp.Length, 325 | AssocId: temp.AssocId, 326 | }, nil 327 | } 328 | 329 | // ParsePartialDeliveryEvent parses the notification data into a SCTPPDApiEvent. 330 | func ParsePartialDeliveryEvent(data []byte) (Notification, error) { 331 | if len(data) < int(unsafe.Sizeof(SCTPPDApiEvent{})) { 332 | return nil, fmt.Errorf("invalid data len, too small") 333 | } 334 | temp := (*SCTPPDApiEvent)(unsafe.Pointer(&data[0])) 335 | return &SCTPPDApiEvent{ 336 | Type: temp.Type, 337 | Flags: temp.Flags, 338 | Length: temp.Length, 339 | Indication: temp.Indication, 340 | AssocId: temp.AssocId, 341 | Stream: temp.Stream, 342 | Sequence: temp.Sequence, 343 | }, nil 344 | } 345 | 346 | // ParseAdaptationIndicationEvent parses the notification data into a SCTPAdaptationEvent. 347 | func ParseAdaptationIndicationEvent(data []byte) (Notification, error) { 348 | if len(data) < int(unsafe.Sizeof(SCTPAdaptationEvent{})) { 349 | return nil, fmt.Errorf("invalid data len, too small") 350 | } 351 | temp := (*SCTPAdaptationEvent)(unsafe.Pointer(&data[0])) 352 | return &SCTPAdaptationEvent{ 353 | Type: temp.Type, 354 | Flags: temp.Flags, 355 | Length: temp.Length, 356 | AdaptationInd: temp.AdaptationInd, 357 | AssocId: temp.AssocId, 358 | }, nil 359 | } 360 | 361 | // ParseAuthenticationEvent parses the notification data into a SCTPAuthKeyEvent. 362 | func ParseAuthenticationEvent(data []byte) (Notification, error) { 363 | if len(data) < int(unsafe.Sizeof(SCTPAuthKeyEvent{})) { 364 | return nil, fmt.Errorf("invalid data len, too small") 365 | } 366 | temp := (*SCTPAuthKeyEvent)(unsafe.Pointer(&data[0])) 367 | return &SCTPAuthKeyEvent{ 368 | Type: temp.Type, 369 | Flags: temp.Flags, 370 | Length: temp.Length, 371 | KeyNumber: temp.KeyNumber, 372 | AltKeyNumber: temp.AltKeyNumber, 373 | Indication: temp.Indication, 374 | AssocId: temp.AssocId, 375 | }, nil 376 | } 377 | 378 | // ParseSenderDryEvent parses the notification data into a SCTPSenderDryEvent. 379 | func ParseSenderDryEvent(data []byte) (Notification, error) { 380 | if len(data) < int(unsafe.Sizeof(SCTPSenderDryEvent{})) { 381 | return nil, fmt.Errorf("invalid data len, too small") 382 | } 383 | temp := (*SCTPSenderDryEvent)(unsafe.Pointer(&data[0])) 384 | return &SCTPSenderDryEvent{ 385 | Type: temp.Type, 386 | Flags: temp.Flags, 387 | Length: temp.Length, 388 | AssocId: temp.AssocId, 389 | }, nil 390 | } 391 | 392 | // ParseStreamResetEvent parses the notification data into a SCTPStreamResetEvent. 393 | func ParseStreamResetEvent(data []byte) (Notification, error) { 394 | if len(data) < int(unsafe.Sizeof(SCTPStreamResetEvent{})) { 395 | return nil, fmt.Errorf("invalid data len, too small") 396 | } 397 | temp := (*SCTPStreamResetEvent)(unsafe.Pointer(&data[0])) 398 | return &SCTPStreamResetEvent{ 399 | Type: temp.Type, 400 | Flags: temp.Flags, 401 | Length: temp.Length, 402 | AssocId: temp.AssocId, 403 | }, nil 404 | } 405 | 406 | // ParseAssocResetEvent parses the notification data into a SCTPAssocResetEvent. 407 | func ParseAssocResetEvent(data []byte) (Notification, error) { 408 | if len(data) < int(unsafe.Sizeof(SCTPAssocResetEvent{})) { 409 | return nil, fmt.Errorf("invalid data len, too small") 410 | } 411 | temp := (*SCTPAssocResetEvent)(unsafe.Pointer(&data[0])) 412 | return &SCTPAssocResetEvent{ 413 | Type: temp.Type, 414 | Flags: temp.Flags, 415 | Length: temp.Length, 416 | AssocId: temp.AssocId, 417 | LocalTsn: temp.LocalTsn, 418 | RemoteTsn: temp.RemoteTsn, 419 | }, nil 420 | } 421 | 422 | // ParseStreamChangeEvent parses the notification data into a SCTPStreamChangeEvent. 423 | func ParseStreamChangeEvent(data []byte) (Notification, error) { 424 | if len(data) < int(unsafe.Sizeof(SCTPStreamChangeEvent{})) { 425 | return nil, fmt.Errorf("invalid data len, too small") 426 | } 427 | temp := (*SCTPStreamChangeEvent)(unsafe.Pointer(&data[0])) 428 | return &SCTPStreamChangeEvent{ 429 | Type: temp.Type, 430 | Flags: temp.Flags, 431 | Length: temp.Length, 432 | AssocId: temp.AssocId, 433 | InStreams: temp.InStreams, 434 | OutStreams: temp.OutStreams, 435 | }, nil 436 | } 437 | 438 | // NotificationName returns the string name of the given SCTP notification type. 439 | func NotificationName(notification uint16) string { 440 | names := map[uint16]string{ 441 | SCTP_DATA_IO_EVENT: "SCTP_DATA_IO_EVENT", 442 | SCTP_ASSOC_CHANGE: "SCTP_ASSOC_CHANGE", 443 | SCTP_PEER_ADDR_CHANGE: "SCTP_PEER_ADDR_CHANGE", 444 | SCTP_SEND_FAILED: "SCTP_SEND_FAILED", 445 | SCTP_REMOTE_ERROR: "SCTP_REMOTE_ERROR", 446 | SCTP_SHUTDOWN_EVENT: "SCTP_SHUTDOWN_EVENT", 447 | SCTP_PARTIAL_DELIVERY_EVENT: "SCTP_PARTIAL_DELIVERY_EVENT", 448 | SCTP_ADAPTATION_INDICATION: "SCTP_ADAPTATION_INDICATION", 449 | SCTP_AUTHENTICATION_EVENT: "SCTP_AUTHENTICATION_EVENT", 450 | SCTP_SENDER_DRY_EVENT: "SCTP_SENDER_DRY_EVENT", 451 | SCTP_STREAM_RESET_EVENT: "SCTP_STREAM_RESET_EVENT", 452 | SCTP_ASSOC_RESET_EVENT: "SCTP_ASSOC_RESET_EVENT", 453 | SCTP_STREAM_CHANGE_EVENT: "SCTP_STREAM_CHANGE_EVENT", 454 | } 455 | return names[notification] 456 | } 457 | 458 | // ParseNotification parses the SCTP notification data based on its type and returns the appropriate Notification. 459 | func ParseNotification(data []byte) (Notification, error) { 460 | if len(data) < SCTPNotificationHeaderSize { 461 | return nil, fmt.Errorf("invalid data len, too small") 462 | } 463 | if len(data) > SCTPNotificationSize { 464 | return nil, fmt.Errorf("invalid data len, too large") 465 | } 466 | temp := (*SCTPNotificationHeader)(unsafe.Pointer(&data[0])) 467 | parsers := map[uint16]func([]byte) (Notification, error){ 468 | SCTP_DATA_IO_EVENT: ParseDataIOEvent, 469 | SCTP_ASSOC_CHANGE: ParseAssocChangeEvent, 470 | SCTP_PEER_ADDR_CHANGE: ParsePeerAddrChangeEvent, 471 | SCTP_SEND_FAILED: ParseSendFailedEvent, 472 | SCTP_REMOTE_ERROR: ParseRemoteErrorEvent, 473 | SCTP_SHUTDOWN_EVENT: ParseShutdownEvent, 474 | SCTP_PARTIAL_DELIVERY_EVENT: ParsePartialDeliveryEvent, 475 | SCTP_ADAPTATION_INDICATION: ParseAdaptationIndicationEvent, 476 | SCTP_AUTHENTICATION_EVENT: ParseAuthenticationEvent, 477 | SCTP_SENDER_DRY_EVENT: ParseSenderDryEvent, 478 | SCTP_STREAM_RESET_EVENT: ParseStreamResetEvent, 479 | SCTP_ASSOC_RESET_EVENT: ParseAssocResetEvent, 480 | SCTP_STREAM_CHANGE_EVENT: ParseStreamChangeEvent, 481 | } 482 | if parser, ok := parsers[temp.Type]; ok { 483 | return parser(data) 484 | } 485 | return nil, fmt.Errorf("invalid notification type") 486 | } 487 | 488 | // SCTPSendMsg sends a message with optional control data over the SCTP socket. 489 | func SCTPSendMsg(sock int, buffer, control []byte, flags int) (int, error) { 490 | var ( 491 | msg syscall.Msghdr 492 | iov syscall.Iovec 493 | ) 494 | msg.Name = nil 495 | msg.Namelen = uint32(0) 496 | if len(buffer) > 0 { 497 | iov.Base = &buffer[0] 498 | iov.SetLen(len(buffer)) 499 | } 500 | if len(control) > 0 { 501 | msg.Control = &control[0] 502 | msg.SetControllen(len(control)) 503 | } 504 | msg.Iov = &iov 505 | msg.Iovlen = 1 506 | length, _, errno := syscall.Syscall( 507 | syscall.SYS_SENDMSG, 508 | uintptr(sock), 509 | uintptr(unsafe.Pointer(&msg)), 510 | uintptr(flags), 511 | ) 512 | if errno != 0 { 513 | return 0, errno 514 | } 515 | if len(control) > 0 && len(buffer) == 0 { 516 | return 0, nil 517 | } 518 | return int(length), nil 519 | } 520 | -------------------------------------------------------------------------------- /codegen/constants_sctp.go: -------------------------------------------------------------------------------- 1 | // +build ignore 2 | 3 | package sctp_go 4 | 5 | //#include 6 | //#include 7 | //#include 8 | //#include 9 | //#include 10 | //#include 11 | //typedef struct iovec IoVector; 12 | //typedef struct msghdr MsgHeader; 13 | //typedef struct cmsghdr CMsgHeader; 14 | //typedef struct in_addr InAddr; 15 | //typedef struct in6_addr In6Addr; 16 | //typedef struct sockaddr_in6 SockAddrIn6; 17 | //typedef struct sockaddr_in SockAddrIn; 18 | //typedef struct sockaddr SockAddr; 19 | //typedef struct sockaddr_storage SockAddrStorage; 20 | //typedef struct sctp_sndrcvinfo SCTPSndRcvInfo; 21 | //typedef struct sctp_initmsg SCTPInitMsg; 22 | //typedef struct sctp_sndinfo SCTPSndInfo; 23 | //typedef struct sctp_rcvinfo SCTPRcvInfo; 24 | //typedef struct sctp_nxtinfo SCTPNxtInfo; 25 | //typedef struct sctp_prinfo SCTPPrInfo; 26 | //typedef struct sctp_authinfo SCTPAuthInfo; 27 | //typedef struct sctp_assoc_change SCTPAssocChange; 28 | //typedef struct sctp_paddr_change SCTPPAddrChange; 29 | //typedef struct sctp_remote_error SCTPRemoteError; 30 | //typedef struct sctp_send_failed SCTPSendFailed; 31 | //typedef struct sctp_shutdown_event SCTPShutdownEvent; 32 | //typedef struct sctp_adaptation_event SCTPAdaptationEvent; 33 | //typedef struct sctp_pdapi_event SCTPPDApiEvent; 34 | //typedef struct sctp_authkey_event SCTPAuthKeyEvent; 35 | //typedef struct sctp_sender_dry_event SCTPSenderDryEvent; 36 | //typedef struct sctp_stream_reset_event SCTPStreamResetEvent; 37 | //typedef struct sctp_assoc_reset_event SCTPAssocResetEvent; 38 | //typedef struct sctp_stream_change_event SCTPStreamChangeEvent; 39 | //typedef struct sctp_event_subscribe SCTPEventSubscribe; 40 | //typedef union sctp_notification SCTPNotification; 41 | //typedef sctp_cmsg_data_t SCTPCmsgData; 42 | //typedef struct sn_header { 43 | // __u16 sn_type; 44 | // __u16 sn_flags; 45 | // __u32 sn_length; 46 | //} SCTPNotificationHeader; 47 | //typedef struct sctp_rtoinfo SCTPRTOInfo; 48 | //typedef struct sctp_assocparams SCTPAssocParams; 49 | //typedef struct sctp_setpeerprim SCTPSetPeerPrimary; 50 | //typedef struct sctp_prim SCTPPrimaryAddr; 51 | //typedef struct sctp_setadaptation SCTPSetAdaptation; 52 | //typedef struct sctp_paddrparams SCTPPeerAddrParams; 53 | //typedef struct sctp_authchunk SCTPAuthChunk; 54 | //typedef struct sctp_hmacalgo SCTPHmacAlgo; 55 | //typedef struct sctp_authkey SCTPAuthKey; 56 | //typedef struct sctp_authkeyid SCTPAuthKeyId; 57 | //typedef struct sctp_sack_info SCTPSackInfo; 58 | //typedef struct sctp_assoc_value SCTPAssocValue; 59 | //typedef struct sctp_stream_value SCTPStreamValue; 60 | //typedef struct sctp_paddrinfo SCTPPeerAddrInfo; 61 | //typedef struct sctp_status SCTPStatus; 62 | //typedef struct sctp_authchunks SCTPAuthChunks; 63 | //typedef struct sctp_assoc_ids SCTPAssocIds; 64 | //typedef struct sctp_getaddrs_old SCTPGetAddrsOld; 65 | //typedef struct sctp_getaddrs SCTPGetAddrs; 66 | //typedef struct sctp_assoc_stats SCTPAssocStats; 67 | //typedef sctp_peeloff_arg_t SCTPPeelOffArg; 68 | //typedef sctp_peeloff_flags_arg_t SCTPPeelOffFlagsArg; 69 | //typedef struct sctp_paddrthlds SCTPPeerAddrThresholds; 70 | //typedef struct sctp_prstatus SCTPPRStatus; 71 | //typedef struct sctp_default_prinfo SCTPDefaultPRInfo; 72 | //typedef struct sctp_info SCTPInfo; 73 | //typedef struct sctp_reset_streams SCTPResetStreams; 74 | //typedef struct sctp_add_streams SCTPAddStreams; 75 | //typedef struct sctp_event SCTPEvent; 76 | import "C" 77 | 78 | const ( 79 | SOL_SCTP = C.SOL_SCTP 80 | IPPROTO_SCTP = C.IPPROTO_SCTP 81 | IoVectorSize = C.sizeof_IoVector 82 | MsgHeaderSize = C.sizeof_MsgHeader 83 | CMsgHeaderSize = C.sizeof_CMsgHeader 84 | InAddrSize = C.sizeof_InAddr 85 | In6AddrSize = C.sizeof_In6Addr 86 | SockAddrInSize = C.sizeof_SockAddrIn 87 | SockAddrIn6Size = C.sizeof_SockAddrIn6 88 | SockAddrSize = C.sizeof_SockAddr 89 | SockAddrStorageSize = C.sizeof_SockAddrStorage 90 | SCTPSndRcvInfoSize = C.sizeof_SCTPSndRcvInfo 91 | SCTPInitMsgSize = C.sizeof_SCTPInitMsg 92 | SCTPSndInfoSize = C.sizeof_SCTPSndInfo 93 | SCTPRcvInfoSize = C.sizeof_SCTPRcvInfo 94 | SCTPNxtInfoSize = C.sizeof_SCTPNxtInfo 95 | SCTPPrInfoSize = C.sizeof_SCTPPrInfo 96 | SCTPAuthInfoSize = C.sizeof_SCTPAuthInfo 97 | SCTPAssocChangeSize = C.sizeof_SCTPAssocChange 98 | SCTPPAddrChangeSize = C.sizeof_SCTPPAddrChange 99 | SCTPRemoteErrorSize = C.sizeof_SCTPRemoteError 100 | SCTPSendFailedSize = C.sizeof_SCTPSendFailed 101 | SCTPShutdownEventSize = C.sizeof_SCTPShutdownEvent 102 | SCTPAdaptationEventSize = C.sizeof_SCTPAdaptationEvent 103 | SCTPPDApiEventSize = C.sizeof_SCTPPDApiEvent 104 | SCTPAuthKeyEventSize = C.sizeof_SCTPAuthKeyEvent 105 | SCTPSenderDryEventSize = C.sizeof_SCTPSenderDryEvent 106 | SCTPStreamResetEventSize = C.sizeof_SCTPStreamResetEvent 107 | SCTPAssocResetEventSize = C.sizeof_SCTPAssocResetEvent 108 | SCTPStreamChangeEventSize = C.sizeof_SCTPStreamChangeEvent 109 | SCTPEventSubscribeSize = C.sizeof_SCTPEventSubscribe 110 | SCTPNotificationSize = C.sizeof_SCTPNotification 111 | SCTPCmsgDataSize = C.sizeof_SCTPCmsgData 112 | SCTPNotificationHeaderSize = C.sizeof_SCTPNotificationHeader 113 | SCTPRTOInfoSize = C.sizeof_SCTPRTOInfo 114 | SCTPAssocParamsSize = C.sizeof_SCTPAssocParams 115 | SCTPSetPeerPrimarySize = C.sizeof_SCTPSetPeerPrimary 116 | SCTPPrimaryAddrSize = C.sizeof_SCTPPrimaryAddr 117 | SCTPSetAdaptationSize = C.sizeof_SCTPSetAdaptation 118 | SCTPPeerAddrParamsSize = C.sizeof_SCTPPeerAddrParams 119 | SCTPAuthChunkSize = C.sizeof_SCTPAuthChunk 120 | SCTPHmacAlgoSize = C.sizeof_SCTPHmacAlgo 121 | SCTPAuthKeySize = C.sizeof_SCTPAuthKey 122 | SCTPAuthKeyIdSize = C.sizeof_SCTPAuthKeyId 123 | SCTPSackInfoSize = C.sizeof_SCTPSackInfo 124 | SCTPAssocValueSize = C.sizeof_SCTPAssocValue 125 | SCTPStreamValueSize = C.sizeof_SCTPStreamValue 126 | SCTPPeerAddrInfoSize = C.sizeof_SCTPPeerAddrInfo 127 | SCTPStatusSize = C.sizeof_SCTPStatus 128 | SCTPAuthChunksSize = C.sizeof_SCTPAuthChunks 129 | SCTPAssocIdsSize = C.sizeof_SCTPAssocIds 130 | SCTPGetAddrsOldSize = C.sizeof_SCTPGetAddrsOld 131 | SCTPGetAddrsSize = C.sizeof_SCTPGetAddrs 132 | SCTPAssocStatsSize = C.sizeof_SCTPAssocStats 133 | SCTPPeelOffArgSize = C.sizeof_SCTPPeelOffArg 134 | SCTPPeelOffFlagsArgSize = C.sizeof_SCTPPeelOffFlagsArg 135 | SCTPPeerAddrThresholdsSize = C.sizeof_SCTPPeerAddrThresholds 136 | SCTPPRStatusSize = C.sizeof_SCTPPRStatus 137 | SCTPDefaultPRInfoSize = C.sizeof_SCTPDefaultPRInfo 138 | SCTPInfoSize = C.sizeof_SCTPInfo 139 | SCTPResetStreamsSize = C.sizeof_SCTPResetStreams 140 | SCTPAddStreamsSize = C.sizeof_SCTPAddStreams 141 | SCTPEventSize = C.sizeof_SCTPEvent 142 | SCTP_FUTURE_ASSOC = C.SCTP_FUTURE_ASSOC 143 | SCTP_CURRENT_ASSOC = C.SCTP_CURRENT_ASSOC 144 | SCTP_ALL_ASSOC = C.SCTP_ALL_ASSOC 145 | SCTP_RTOINFO = C.SCTP_RTOINFO 146 | SCTP_ASSOCINFO = C.SCTP_ASSOCINFO 147 | SCTP_INITMSG = C.SCTP_INITMSG 148 | SCTP_NODELAY = C.SCTP_NODELAY 149 | SCTP_AUTOCLOSE = C.SCTP_AUTOCLOSE 150 | SCTP_SET_PEER_PRIMARY_ADDR = C.SCTP_SET_PEER_PRIMARY_ADDR 151 | SCTP_PRIMARY_ADDR = C.SCTP_PRIMARY_ADDR 152 | SCTP_ADAPTATION_LAYER = C.SCTP_ADAPTATION_LAYER 153 | SCTP_DISABLE_FRAGMENTS = C.SCTP_DISABLE_FRAGMENTS 154 | SCTP_PEER_ADDR_PARAMS = C.SCTP_PEER_ADDR_PARAMS 155 | SCTP_DEFAULT_SEND_PARAM = C.SCTP_DEFAULT_SEND_PARAM 156 | SCTP_EVENTS = C.SCTP_EVENTS 157 | SCTP_I_WANT_MAPPED_V4_ADDR = C.SCTP_I_WANT_MAPPED_V4_ADDR 158 | SCTP_MAXSEG = C.SCTP_MAXSEG 159 | SCTP_STATUS = C.SCTP_STATUS 160 | SCTP_GET_PEER_ADDR_INFO = C.SCTP_GET_PEER_ADDR_INFO 161 | SCTP_DELAYED_ACK_TIME = C.SCTP_DELAYED_ACK_TIME 162 | SCTP_DELAYED_ACK = C.SCTP_DELAYED_ACK 163 | SCTP_DELAYED_SACK = C.SCTP_DELAYED_SACK 164 | SCTP_CONTEXT = C.SCTP_CONTEXT 165 | SCTP_FRAGMENT_INTERLEAVE = C.SCTP_FRAGMENT_INTERLEAVE 166 | SCTP_PARTIAL_DELIVERY_POINT = C.SCTP_PARTIAL_DELIVERY_POINT 167 | SCTP_MAX_BURST = C.SCTP_MAX_BURST 168 | SCTP_AUTH_CHUNK = C.SCTP_AUTH_CHUNK 169 | SCTP_HMAC_IDENT = C.SCTP_HMAC_IDENT 170 | SCTP_AUTH_KEY = C.SCTP_AUTH_KEY 171 | SCTP_AUTH_ACTIVE_KEY = C.SCTP_AUTH_ACTIVE_KEY 172 | SCTP_AUTH_DELETE_KEY = C.SCTP_AUTH_DELETE_KEY 173 | SCTP_PEER_AUTH_CHUNKS = C.SCTP_PEER_AUTH_CHUNKS 174 | SCTP_LOCAL_AUTH_CHUNKS = C.SCTP_LOCAL_AUTH_CHUNKS 175 | SCTP_GET_ASSOC_NUMBER = C.SCTP_GET_ASSOC_NUMBER 176 | SCTP_GET_ASSOC_ID_LIST = C.SCTP_GET_ASSOC_ID_LIST 177 | SCTP_AUTO_ASCONF = C.SCTP_AUTO_ASCONF 178 | SCTP_PEER_ADDR_THLDS = C.SCTP_PEER_ADDR_THLDS 179 | SCTP_RECVRCVINFO = C.SCTP_RECVRCVINFO 180 | SCTP_RECVNXTINFO = C.SCTP_RECVNXTINFO 181 | SCTP_DEFAULT_SNDINFO = C.SCTP_DEFAULT_SNDINFO 182 | SCTP_AUTH_DEACTIVATE_KEY = C.SCTP_AUTH_DEACTIVATE_KEY 183 | SCTP_REUSE_PORT = C.SCTP_REUSE_PORT 184 | SCTP_SOCKOPT_BINDX_ADD = C.SCTP_SOCKOPT_BINDX_ADD 185 | SCTP_SOCKOPT_BINDX_REM = C.SCTP_SOCKOPT_BINDX_REM 186 | SCTP_SOCKOPT_PEELOFF = C.SCTP_SOCKOPT_PEELOFF 187 | SCTP_SOCKOPT_CONNECTX_OLD = C.SCTP_SOCKOPT_CONNECTX_OLD 188 | SCTP_GET_PEER_ADDRS = C.SCTP_GET_PEER_ADDRS 189 | SCTP_GET_LOCAL_ADDRS = C.SCTP_GET_LOCAL_ADDRS 190 | SCTP_SOCKOPT_CONNECTX = C.SCTP_SOCKOPT_CONNECTX 191 | SCTP_SOCKOPT_CONNECTX3 = C.SCTP_SOCKOPT_CONNECTX3 192 | SCTP_GET_ASSOC_STATS = C.SCTP_GET_ASSOC_STATS 193 | SCTP_PR_SUPPORTED = C.SCTP_PR_SUPPORTED 194 | SCTP_DEFAULT_PRINFO = C.SCTP_DEFAULT_PRINFO 195 | SCTP_PR_ASSOC_STATUS = C.SCTP_PR_ASSOC_STATUS 196 | SCTP_PR_STREAM_STATUS = C.SCTP_PR_STREAM_STATUS 197 | SCTP_RECONFIG_SUPPORTED = C.SCTP_RECONFIG_SUPPORTED 198 | SCTP_ENABLE_STREAM_RESET = C.SCTP_ENABLE_STREAM_RESET 199 | SCTP_RESET_STREAMS = C.SCTP_RESET_STREAMS 200 | SCTP_RESET_ASSOC = C.SCTP_RESET_ASSOC 201 | SCTP_ADD_STREAMS = C.SCTP_ADD_STREAMS 202 | SCTP_SOCKOPT_PEELOFF_FLAGS = C.SCTP_SOCKOPT_PEELOFF_FLAGS 203 | SCTP_STREAM_SCHEDULER = C.SCTP_STREAM_SCHEDULER 204 | SCTP_STREAM_SCHEDULER_VALUE = C.SCTP_STREAM_SCHEDULER_VALUE 205 | SCTP_INTERLEAVING_SUPPORTED = C.SCTP_INTERLEAVING_SUPPORTED 206 | SCTP_SENDMSG_CONNECT = C.SCTP_SENDMSG_CONNECT 207 | SCTP_EVENT = C.SCTP_EVENT 208 | SCTP_ASCONF_SUPPORTED = C.SCTP_ASCONF_SUPPORTED 209 | SCTP_AUTH_SUPPORTED = C.SCTP_AUTH_SUPPORTED 210 | SCTP_ECN_SUPPORTED = C.SCTP_ECN_SUPPORTED 211 | SCTP_PR_SCTP_NONE = C.SCTP_PR_SCTP_NONE 212 | SCTP_PR_SCTP_TTL = C.SCTP_PR_SCTP_TTL 213 | SCTP_PR_SCTP_RTX = C.SCTP_PR_SCTP_RTX 214 | SCTP_PR_SCTP_PRIO = C.SCTP_PR_SCTP_PRIO 215 | SCTP_PR_SCTP_MAX = C.SCTP_PR_SCTP_MAX 216 | SCTP_PR_SCTP_MASK = C.SCTP_PR_SCTP_MASK 217 | SCTP_ENABLE_RESET_STREAM_REQ = C.SCTP_ENABLE_RESET_STREAM_REQ 218 | SCTP_ENABLE_RESET_ASSOC_REQ = C.SCTP_ENABLE_RESET_ASSOC_REQ 219 | SCTP_ENABLE_CHANGE_ASSOC_REQ = C.SCTP_ENABLE_CHANGE_ASSOC_REQ 220 | SCTP_ENABLE_STRRESET_MASK = C.SCTP_ENABLE_STRRESET_MASK 221 | SCTP_STREAM_RESET_INCOMING = C.SCTP_STREAM_RESET_INCOMING 222 | SCTP_STREAM_RESET_OUTGOING = C.SCTP_STREAM_RESET_OUTGOING 223 | SCTP_MSG_NOTIFICATION = C.MSG_NOTIFICATION 224 | SCTP_UNORDERED = C.SCTP_UNORDERED 225 | SCTP_ADDR_OVER = C.SCTP_ADDR_OVER 226 | SCTP_ABORT = C.SCTP_ABORT 227 | SCTP_SACK_IMMEDIATELY = C.SCTP_SACK_IMMEDIATELY 228 | SCTP_SENDALL = C.SCTP_SENDALL 229 | SCTP_PR_SCTP_ALL = C.SCTP_PR_SCTP_ALL 230 | SCTP_NOTIFICATION = C.SCTP_NOTIFICATION 231 | SCTP_EOF = C.SCTP_EOF 232 | SCTP_INIT = C.SCTP_INIT 233 | SCTP_SNDRCV = C.SCTP_SNDRCV 234 | SCTP_SNDINFO = C.SCTP_SNDINFO 235 | SCTP_RCVINFO = C.SCTP_RCVINFO 236 | SCTP_NXTINFO = C.SCTP_NXTINFO 237 | SCTP_PRINFO = C.SCTP_PRINFO 238 | SCTP_AUTHINFO = C.SCTP_AUTHINFO 239 | SCTP_DSTADDRV4 = C.SCTP_DSTADDRV4 240 | SCTP_DSTADDRV6 = C.SCTP_DSTADDRV6 241 | SCTP_COMM_UP = C.SCTP_COMM_UP 242 | SCTP_COMM_LOST = C.SCTP_COMM_LOST 243 | SCTP_RESTART = C.SCTP_RESTART 244 | SCTP_SHUTDOWN_COMP = C.SCTP_SHUTDOWN_COMP 245 | SCTP_CANT_STR_ASSOC = C.SCTP_CANT_STR_ASSOC 246 | SCTP_ADDR_AVAILABLE = C.SCTP_ADDR_AVAILABLE 247 | SCTP_ADDR_UNREACHABLE = C.SCTP_ADDR_UNREACHABLE 248 | SCTP_ADDR_REMOVED = C.SCTP_ADDR_REMOVED 249 | SCTP_ADDR_ADDED = C.SCTP_ADDR_ADDED 250 | SCTP_ADDR_MADE_PRIM = C.SCTP_ADDR_MADE_PRIM 251 | SCTP_ADDR_CONFIRMED = C.SCTP_ADDR_CONFIRMED 252 | SCTP_DATA_UNSENT = C.SCTP_DATA_UNSENT 253 | SCTP_DATA_SENT = C.SCTP_DATA_SENT 254 | SCTP_PARTIAL_DELIVERY_ABORTED = C.SCTP_PARTIAL_DELIVERY_ABORTED 255 | SCTP_AUTH_NEW_KEY = C.SCTP_AUTH_NEW_KEY 256 | SCTP_AUTH_FREE_KEY = C.SCTP_AUTH_FREE_KEY 257 | SCTP_AUTH_NO_AUTH = C.SCTP_AUTH_NO_AUTH 258 | SCTP_STREAM_RESET_INCOMING_SSN = C.SCTP_STREAM_RESET_INCOMING_SSN 259 | SCTP_STREAM_RESET_OUTGOING_SSN = C.SCTP_STREAM_RESET_OUTGOING_SSN 260 | SCTP_STREAM_RESET_DENIED = C.SCTP_STREAM_RESET_DENIED 261 | SCTP_STREAM_RESET_FAILED = C.SCTP_STREAM_RESET_FAILED 262 | SCTP_ASSOC_RESET_DENIED = C.SCTP_ASSOC_RESET_DENIED 263 | SCTP_ASSOC_RESET_FAILED = C.SCTP_ASSOC_RESET_FAILED 264 | SCTP_ASSOC_CHANGE_DENIED = C.SCTP_ASSOC_CHANGE_DENIED 265 | SCTP_ASSOC_CHANGE_FAILED = C.SCTP_ASSOC_CHANGE_FAILED 266 | SCTP_STREAM_CHANGE_DENIED = C.SCTP_STREAM_CHANGE_DENIED 267 | SCTP_STREAM_CHANGE_FAILED = C.SCTP_STREAM_CHANGE_FAILED 268 | SCTP_SN_TYPE_BASE = C.SCTP_SN_TYPE_BASE 269 | SCTP_DATA_IO_EVENT = C.SCTP_DATA_IO_EVENT 270 | SCTP_ASSOC_CHANGE = C.SCTP_ASSOC_CHANGE 271 | SCTP_PEER_ADDR_CHANGE = C.SCTP_PEER_ADDR_CHANGE 272 | SCTP_SEND_FAILED = C.SCTP_SEND_FAILED 273 | SCTP_REMOTE_ERROR = C.SCTP_REMOTE_ERROR 274 | SCTP_SHUTDOWN_EVENT = C.SCTP_SHUTDOWN_EVENT 275 | SCTP_PARTIAL_DELIVERY_EVENT = C.SCTP_PARTIAL_DELIVERY_EVENT 276 | SCTP_ADAPTATION_INDICATION = C.SCTP_ADAPTATION_INDICATION 277 | SCTP_AUTHENTICATION_EVENT = C.SCTP_AUTHENTICATION_EVENT 278 | SCTP_SENDER_DRY_EVENT = C.SCTP_SENDER_DRY_EVENT 279 | SCTP_STREAM_RESET_EVENT = C.SCTP_STREAM_RESET_EVENT 280 | SCTP_ASSOC_RESET_EVENT = C.SCTP_ASSOC_RESET_EVENT 281 | SCTP_STREAM_CHANGE_EVENT = C.SCTP_STREAM_CHANGE_EVENT 282 | SCTP_SN_TYPE_MAX = C.SCTP_SN_TYPE_MAX 283 | SCTP_FAILED_THRESHOLD = C.SCTP_FAILED_THRESHOLD 284 | SCTP_RECEIVED_SACK = C.SCTP_RECEIVED_SACK 285 | SCTP_HEARTBEAT_SUCCESS = C.SCTP_HEARTBEAT_SUCCESS 286 | SCTP_RESPONSE_TO_USER_REQ = C.SCTP_RESPONSE_TO_USER_REQ 287 | SCTP_INTERNAL_ERROR = C.SCTP_INTERNAL_ERROR 288 | SCTP_SHUTDOWN_GUARD_EXPIRES = C.SCTP_SHUTDOWN_GUARD_EXPIRES 289 | SCTP_PEER_FAULTY = C.SCTP_PEER_FAULTY 290 | SPP_HB_ENABLE = C.SPP_HB_ENABLE 291 | SPP_HB_DISABLE = C.SPP_HB_DISABLE 292 | SPP_HB = C.SPP_HB 293 | SPP_HB_DEMAND = C.SPP_HB_DEMAND 294 | SPP_PMTUD_ENABLE = C.SPP_PMTUD_ENABLE 295 | SPP_PMTUD_DISABLE = C.SPP_PMTUD_DISABLE 296 | SPP_PMTUD = C.SPP_PMTUD 297 | SPP_SACKDELAY_ENABLE = C.SPP_SACKDELAY_ENABLE 298 | SPP_SACKDELAY_DISABLE = C.SPP_SACKDELAY_DISABLE 299 | SPP_SACKDELAY = C.SPP_SACKDELAY 300 | SPP_HB_TIME_IS_ZERO = C.SPP_HB_TIME_IS_ZERO 301 | SPP_IPV6_FLOWLABEL = C.SPP_IPV6_FLOWLABEL 302 | SPP_DSCP = C.SPP_DSCP 303 | SCTP_AUTH_HMAC_ID_SHA1 = C.SCTP_AUTH_HMAC_ID_SHA1 304 | SCTP_AUTH_HMAC_ID_SHA256 = C.SCTP_AUTH_HMAC_ID_SHA256 305 | SCTP_INACTIVE = C.SCTP_INACTIVE 306 | SCTP_PF = C.SCTP_PF 307 | SCTP_ACTIVE = C.SCTP_ACTIVE 308 | SCTP_UNCONFIRMED = C.SCTP_UNCONFIRMED 309 | SCTP_UNKNOWN = C.SCTP_UNKNOWN 310 | SCTP_EMPTY = C.SCTP_EMPTY 311 | SCTP_CLOSED = C.SCTP_CLOSED 312 | SCTP_COOKIE_WAIT = C.SCTP_COOKIE_WAIT 313 | SCTP_COOKIE_ECHOED = C.SCTP_COOKIE_ECHOED 314 | SCTP_ESTABLISHED = C.SCTP_ESTABLISHED 315 | SCTP_SHUTDOWN_PENDING = C.SCTP_SHUTDOWN_PENDING 316 | SCTP_SHUTDOWN_SENT = C.SCTP_SHUTDOWN_SENT 317 | SCTP_SHUTDOWN_RECEIVED = C.SCTP_SHUTDOWN_RECEIVED 318 | SCTP_SHUTDOWN_ACK_SENT = C.SCTP_SHUTDOWN_ACK_SENT 319 | SCTP_BINDX_ADD_ADDR = C.SCTP_BINDX_ADD_ADDR 320 | SCTP_BINDX_REM_ADDR = C.SCTP_BINDX_REM_ADDR 321 | SCTP_SS_FCFS = C.SCTP_SS_FCFS 322 | SCTP_SS_DEFAULT = C.SCTP_SS_DEFAULT 323 | SCTP_SS_PRIO = C.SCTP_SS_PRIO 324 | SCTP_SS_RR = C.SCTP_SS_RR 325 | SCTP_SS_MAX = C.SCTP_SS_RR 326 | ) 327 | -------------------------------------------------------------------------------- /sctp_structs.go: -------------------------------------------------------------------------------- 1 | package sctp_go 2 | 3 | import ( 4 | "bytes" 5 | "encoding/binary" 6 | "unsafe" 7 | ) 8 | 9 | // IoVector represents the C struct iovec for scatter/gather I/O operations. 10 | type IoVector struct { 11 | Base *byte 12 | Len uint64 13 | } 14 | 15 | // MsgHeader represents the C struct msghdr for socket message headers. 16 | type MsgHeader struct { 17 | Name *byte 18 | NameLen uint32 19 | Iov *IoVector 20 | IovLen uint64 21 | Control *byte 22 | ControlLen uint64 23 | Flags int32 24 | Padding [4]byte 25 | } 26 | 27 | // CMsgHeader represents the C struct cmsghdr for control message headers. 28 | type CMsgHeader struct { 29 | Len uint64 30 | Level int32 31 | Type int32 32 | } 33 | 34 | // InAddr represents the C struct in_addr for IPv4 addresses. 35 | type InAddr struct { 36 | Addr [4]byte 37 | } 38 | 39 | // In6Addr represents the C struct in6_addr for IPv6 addresses. 40 | type In6Addr struct { 41 | Addr [16]byte 42 | } 43 | 44 | // SockAddrIn6 represents the C struct sockaddr_in6 for IPv6 socket addresses. 45 | type SockAddrIn6 struct { 46 | Family uint16 47 | Port uint16 48 | FlowInfo uint32 49 | Addr In6Addr 50 | ScopeId uint32 51 | } 52 | 53 | // SockAddrIn represents the C struct sockaddr_in for IPv4 socket addresses. 54 | type SockAddrIn struct { 55 | Family uint16 56 | Port uint16 57 | Addr InAddr 58 | Zero [8]uint8 59 | } 60 | 61 | // SockAddr represents the C struct sockaddr for generic socket addresses. 62 | type SockAddr struct { 63 | Family uint16 64 | Data [14]int8 65 | } 66 | 67 | // SockAddrStorage represents the C struct sockaddr_storage for storing socket addresses. 68 | type SockAddrStorage struct { 69 | Family uint16 70 | Padding [118]int8 71 | Align uint64 72 | } 73 | 74 | // SCTPAssocId represents the C type sctp_assoc_t for SCTP association IDs. 75 | type SCTPAssocId int32 76 | 77 | // SCTPInitMsg represents the C struct sctp_initmsg for SCTP initialization parameters. 78 | type SCTPInitMsg struct { 79 | NumOutStreams uint16 80 | MaxInStreams uint16 81 | MaxAttempts uint16 82 | MaxInitTimeout uint16 83 | } 84 | 85 | // SCTPSndRcvInfo represents the C struct sctp_sndrcvinfo for SCTP send/receive information. 86 | type SCTPSndRcvInfo struct { 87 | Stream uint16 88 | Ssn uint16 89 | Flags uint16 90 | _ uint16 91 | Ppid uint32 92 | Context uint32 93 | TimeToLive uint32 94 | Tsn uint32 95 | CumTsn uint32 96 | AssocId int32 97 | } 98 | 99 | // SCTPSndInfo represents the C struct sctp_sndinfo for SCTP send information. 100 | type SCTPSndInfo struct { 101 | Sid uint16 102 | Flags uint16 103 | Ppid uint32 104 | Context uint32 105 | AssocId int32 106 | } 107 | 108 | // SCTPRcvInfo represents the C struct sctp_rcvinfo for SCTP receive information. 109 | type SCTPRcvInfo struct { 110 | Sid uint16 111 | Ssn uint16 112 | Flags uint16 113 | Ppid uint32 114 | Tsn uint32 115 | CumTsn uint32 116 | Context uint32 117 | AssocId int32 118 | } 119 | 120 | // SCTPNxtInfo represents the C struct sctp_nxtinfo for SCTP next information. 121 | type SCTPNxtInfo struct { 122 | Sid uint16 123 | Flags uint16 124 | Ppid uint32 125 | Length uint32 126 | AssocId int32 127 | } 128 | 129 | // SCTPPrInfo represents the C struct sctp_prinfo for SCTP partial reliability information. 130 | type SCTPPrInfo struct { 131 | Policy uint16 132 | Value uint32 133 | } 134 | 135 | // SCTPAuthInfo represents the C struct sctp_authinfo for SCTP authentication information. 136 | type SCTPAuthInfo struct { 137 | KeyNumber uint16 138 | } 139 | 140 | // SCTPCmsgData represents the C type sctp_cmsg_data_t for SCTP control message data. 141 | type SCTPCmsgData [32]byte 142 | 143 | // SCTPGetAddrsOld represents the C struct sctp_getaddrs_old for getting SCTP addresses (old version). 144 | type SCTPGetAddrsOld struct { 145 | AssocId int32 146 | Num int32 147 | Addrs uintptr 148 | } 149 | 150 | // SCTPGetAddrs represents the C struct sctp_getaddrs for getting SCTP addresses. 151 | type SCTPGetAddrs struct { 152 | AssocId int32 153 | Num uint32 154 | // Member Addr is removed as it is variable sized array. 155 | } 156 | 157 | // SCTPEventSubscribe represents the C struct sctp_event_subscribe for SCTP event subscription. 158 | type SCTPEventSubscribe struct { 159 | DataIoEvent uint8 160 | AssociationEvent uint8 161 | AddressEvent uint8 162 | SendFailureEvent uint8 163 | PeerErrorEvent uint8 164 | ShutdownEvent uint8 165 | PartialDeliveryEvent uint8 166 | AdaptationLayerEvent uint8 167 | AuthenticationEvent uint8 168 | SenderDryEvent uint8 169 | StreamResetEvent uint8 170 | AssocResetEvent uint8 171 | StreamChangeEvent uint8 172 | } 173 | 174 | // SCTPSetPeerPrimary represents the C struct sctp_setpeerprim for setting SCTP peer primary address. 175 | type SCTPSetPeerPrimary struct { 176 | AssocId int32 177 | Addr [128]byte 178 | // Cannot use SockAddrStorage as type for Addr. 179 | // Inner structures have alignment requirement of 8 bytes. 180 | // This structure has alignment requirement of 4 bytes. 181 | } 182 | 183 | // SCTPPrimaryAddr represents the C struct sctp_prim for SCTP primary address. 184 | type SCTPPrimaryAddr SCTPSetPeerPrimary 185 | 186 | // SCTPPeelOffArg represents the C type sctp_peeloff_arg_t for SCTP peel-off arguments. 187 | type SCTPPeelOffArg struct { 188 | AssocId int32 189 | Sd int32 190 | } 191 | 192 | // SCTPPeelOffFlagsArg represents the C type sctp_peeloff_flags_arg_t for SCTP peel-off arguments with flags. 193 | type SCTPPeelOffFlagsArg struct { 194 | Arg SCTPPeelOffArg 195 | Flags uint32 196 | } 197 | 198 | // SCTPNotification represents the C union sctp_notification for SCTP notifications. 199 | type SCTPNotification [148]byte 200 | 201 | // Notification represents the interface for SCTP notification types. 202 | type Notification interface { 203 | GetType() uint16 204 | GetFlags() uint16 205 | GetLength() uint32 206 | } 207 | 208 | // SCTPNotificationHeader represents the C struct sn_header for SCTP notification headers. 209 | type SCTPNotificationHeader struct { 210 | Type uint16 211 | Flags uint16 212 | Length uint32 213 | } 214 | 215 | // GetType returns the type field of the SCTP notification header. 216 | func (n *SCTPNotificationHeader) GetType() uint16 { 217 | return n.Type 218 | } 219 | 220 | // GetFlags returns the flags field of the SCTP notification header. 221 | func (n *SCTPNotificationHeader) GetFlags() uint16 { 222 | return n.Flags 223 | } 224 | 225 | // GetLength returns the length field of the SCTP notification header. 226 | func (n *SCTPNotificationHeader) GetLength() uint32 { 227 | return n.Length 228 | } 229 | 230 | // SCTPAssocChange represents the C struct sctp_assoc_change for SCTP association change notifications. 231 | type SCTPAssocChange struct { 232 | Type uint16 233 | Flags uint16 234 | Length uint32 235 | State uint16 236 | Error uint16 237 | OutboundStreams uint16 238 | InboundStreams uint16 239 | AssocId int32 240 | } 241 | 242 | // GetType returns the type field of the SCTP association change notification. 243 | func (n *SCTPAssocChange) GetType() uint16 { 244 | return n.Type 245 | } 246 | 247 | // GetFlags returns the flags field of the SCTP association change notification. 248 | func (n *SCTPAssocChange) GetFlags() uint16 { 249 | return n.Flags 250 | } 251 | 252 | // GetLength returns the length field of the SCTP association change notification. 253 | func (n *SCTPAssocChange) GetLength() uint32 { 254 | return n.Length 255 | } 256 | 257 | // SCTPPAddrChange represents the C struct sctp_paddr_change for SCTP peer address change notifications. 258 | type SCTPPAddrChange struct { 259 | Type uint16 260 | Flags uint16 261 | Length uint32 262 | Addr [128]byte 263 | State int32 264 | Error int32 265 | AssocId int32 266 | // Cannot use SockAddrStorage as type for Addr. 267 | // Inner structures have alignment requirement of 8 bytes. 268 | // This structure has alignment requirement of 4 bytes. 269 | } 270 | 271 | // GetType returns the type field of the SCTP peer address change notification. 272 | func (n *SCTPPAddrChange) GetType() uint16 { 273 | return n.Type 274 | } 275 | 276 | // GetFlags returns the flags field of the SCTP peer address change notification. 277 | func (n *SCTPPAddrChange) GetFlags() uint16 { 278 | return n.Flags 279 | } 280 | 281 | // GetLength returns the length field of the SCTP peer address change notification. 282 | func (n *SCTPPAddrChange) GetLength() uint32 { 283 | return n.Length 284 | } 285 | 286 | // GetAddr returns the peer address from the SCTP peer address change notification. 287 | func (n *SCTPPAddrChange) GetAddr() *SCTPAddr { 288 | return FromSockAddrStorage((*SockAddrStorage)(unsafe.Pointer(&n.Addr))) 289 | } 290 | 291 | // SCTPRemoteError represents the C struct sctp_remote_error for SCTP remote error notifications. 292 | type SCTPRemoteError struct { 293 | Type uint16 294 | Flags uint16 295 | Length uint32 296 | Error uint16 297 | AssocId int32 298 | } 299 | 300 | // GetType returns the type field of the SCTP remote error notification. 301 | func (n *SCTPRemoteError) GetType() uint16 { 302 | return n.Type 303 | } 304 | 305 | // GetFlags returns the flags field of the SCTP remote error notification. 306 | func (n *SCTPRemoteError) GetFlags() uint16 { 307 | return n.Flags 308 | } 309 | 310 | // GetLength returns the length field of the SCTP remote error notification. 311 | func (n *SCTPRemoteError) GetLength() uint32 { 312 | return n.Length 313 | } 314 | 315 | // SCTPSendFailed represents the C struct sctp_send_failed for SCTP send failure notifications. 316 | type SCTPSendFailed struct { 317 | Type uint16 318 | Flags uint16 319 | Length uint32 320 | Error uint32 321 | Info SCTPSndRcvInfo 322 | AssocId int32 323 | } 324 | 325 | // GetType returns the type field of the SCTP send failed notification. 326 | func (n *SCTPSendFailed) GetType() uint16 { 327 | return n.Type 328 | } 329 | 330 | // GetFlags returns the flags field of the SCTP send failed notification. 331 | func (n *SCTPSendFailed) GetFlags() uint16 { 332 | return n.Flags 333 | } 334 | 335 | // GetLength returns the length field of the SCTP send failed notification. 336 | func (n *SCTPSendFailed) GetLength() uint32 { 337 | return n.Length 338 | } 339 | 340 | // SCTPShutdownEvent represents the C struct sctp_shutdown_event for SCTP shutdown event notifications. 341 | type SCTPShutdownEvent struct { 342 | Type uint16 343 | Flags uint16 344 | Length uint32 345 | AssocId int32 346 | } 347 | 348 | // GetType returns the type field of the SCTP shutdown event notification. 349 | func (n *SCTPShutdownEvent) GetType() uint16 { 350 | return n.Type 351 | } 352 | 353 | // GetFlags returns the flags field of the SCTP shutdown event notification. 354 | func (n *SCTPShutdownEvent) GetFlags() uint16 { 355 | return n.Flags 356 | } 357 | 358 | // GetLength returns the length field of the SCTP shutdown event notification. 359 | func (n *SCTPShutdownEvent) GetLength() uint32 { 360 | return n.Length 361 | } 362 | 363 | // SCTPAdaptationEvent represents the C struct sctp_adaptation_event for SCTP adaptation layer event notifications. 364 | type SCTPAdaptationEvent struct { 365 | Type uint16 366 | Flags uint16 367 | Length uint32 368 | AdaptationInd uint32 369 | AssocId int32 370 | } 371 | 372 | // GetType returns the type field of the SCTP adaptation event notification. 373 | func (n *SCTPAdaptationEvent) GetType() uint16 { 374 | return n.Type 375 | } 376 | 377 | // GetFlags returns the flags field of the SCTP adaptation event notification. 378 | func (n *SCTPAdaptationEvent) GetFlags() uint16 { 379 | return n.Flags 380 | } 381 | 382 | // GetLength returns the length field of the SCTP adaptation event notification. 383 | func (n *SCTPAdaptationEvent) GetLength() uint32 { 384 | return n.Length 385 | } 386 | 387 | // SCTPPDApiEvent represents the C struct sctp_pdapi_event for SCTP partial delivery API event notifications. 388 | type SCTPPDApiEvent struct { 389 | Type uint16 390 | Flags uint16 391 | Length uint32 392 | Indication uint32 393 | AssocId int32 394 | Stream uint32 395 | Sequence uint32 396 | } 397 | 398 | // GetType returns the type field of the SCTP partial delivery API event notification. 399 | func (n *SCTPPDApiEvent) GetType() uint16 { 400 | return n.Type 401 | } 402 | 403 | // GetFlags returns the flags field of the SCTP partial delivery API event notification. 404 | func (n *SCTPPDApiEvent) GetFlags() uint16 { 405 | return n.Flags 406 | } 407 | 408 | // GetLength returns the length field of the SCTP partial delivery API event notification. 409 | func (n *SCTPPDApiEvent) GetLength() uint32 { 410 | return n.Length 411 | } 412 | 413 | // SCTPAuthKeyEvent represents the C struct sctp_authkey_event for SCTP authentication key event notifications. 414 | type SCTPAuthKeyEvent struct { 415 | Type uint16 416 | Flags uint16 417 | Length uint32 418 | KeyNumber uint16 419 | AltKeyNumber uint16 420 | Indication uint32 421 | AssocId int32 422 | } 423 | 424 | // GetType returns the type field of the SCTP authentication key event notification. 425 | func (n *SCTPAuthKeyEvent) GetType() uint16 { 426 | return n.Type 427 | } 428 | 429 | // GetFlags returns the flags field of the SCTP authentication key event notification. 430 | func (n *SCTPAuthKeyEvent) GetFlags() uint16 { 431 | return n.Flags 432 | } 433 | 434 | // GetLength returns the length field of the SCTP authentication key event notification. 435 | func (n *SCTPAuthKeyEvent) GetLength() uint32 { 436 | return n.Length 437 | } 438 | 439 | // SCTPSenderDryEvent represents the C struct sctp_sender_dry_event for SCTP sender dry event notifications. 440 | type SCTPSenderDryEvent struct { 441 | Type uint16 442 | Flags uint16 443 | Length uint32 444 | AssocId int32 445 | } 446 | 447 | // GetType returns the type field of the SCTP sender dry event notification. 448 | func (n *SCTPSenderDryEvent) GetType() uint16 { 449 | return n.Type 450 | } 451 | 452 | // GetFlags returns the flags field of the SCTP sender dry event notification. 453 | func (n *SCTPSenderDryEvent) GetFlags() uint16 { 454 | return n.Flags 455 | } 456 | 457 | // GetLength returns the length field of the SCTP sender dry event notification. 458 | func (n *SCTPSenderDryEvent) GetLength() uint32 { 459 | return n.Length 460 | } 461 | 462 | // SCTPStreamResetEvent represents the C struct sctp_stream_reset_event for SCTP stream reset event notifications. 463 | type SCTPStreamResetEvent struct { 464 | Type uint16 465 | Flags uint16 466 | Length uint32 467 | AssocId int32 468 | } 469 | 470 | // GetType returns the type field of the SCTP stream reset event notification. 471 | func (n *SCTPStreamResetEvent) GetType() uint16 { 472 | return n.Type 473 | } 474 | 475 | // GetFlags returns the flags field of the SCTP stream reset event notification. 476 | func (n *SCTPStreamResetEvent) GetFlags() uint16 { 477 | return n.Flags 478 | } 479 | 480 | // GetLength returns the length field of the SCTP stream reset event notification. 481 | func (n *SCTPStreamResetEvent) GetLength() uint32 { 482 | return n.Length 483 | } 484 | 485 | // SCTPAssocResetEvent represents the C struct sctp_assoc_reset_event for SCTP association reset event notifications. 486 | type SCTPAssocResetEvent struct { 487 | Type uint16 488 | Flags uint16 489 | Length uint32 490 | AssocId int32 491 | LocalTsn uint32 492 | RemoteTsn uint32 493 | } 494 | 495 | // GetType returns the type field of the SCTP association reset event notification. 496 | func (n *SCTPAssocResetEvent) GetType() uint16 { 497 | return n.Type 498 | } 499 | 500 | // GetFlags returns the flags field of the SCTP association reset event notification. 501 | func (n *SCTPAssocResetEvent) GetFlags() uint16 { 502 | return n.Flags 503 | } 504 | 505 | // GetLength returns the length field of the SCTP association reset event notification. 506 | func (n *SCTPAssocResetEvent) GetLength() uint32 { 507 | return n.Length 508 | } 509 | 510 | // SCTPStreamChangeEvent represents the C struct sctp_stream_change_event for SCTP stream change event notifications. 511 | type SCTPStreamChangeEvent struct { 512 | Type uint16 513 | Flags uint16 514 | Length uint32 515 | AssocId int32 516 | InStreams uint16 517 | OutStreams uint16 518 | } 519 | 520 | // GetType returns the type field of the SCTP stream change event notification. 521 | func (n *SCTPStreamChangeEvent) GetType() uint16 { 522 | return n.Type 523 | } 524 | 525 | // GetFlags returns the flags field of the SCTP stream change event notification. 526 | func (n *SCTPStreamChangeEvent) GetFlags() uint16 { 527 | return n.Flags 528 | } 529 | 530 | // GetLength returns the length field of the SCTP stream change event notification. 531 | func (n *SCTPStreamChangeEvent) GetLength() uint32 { 532 | return n.Length 533 | } 534 | 535 | // SCTPRTOInfo represents the C struct sctp_rtoinfo for SCTP retransmission timeout information. 536 | type SCTPRTOInfo struct { 537 | AssocId int32 538 | Initial uint32 539 | Max uint32 540 | Min uint32 541 | } 542 | 543 | // SCTPResetStreams represents the C struct sctp_reset_streams for SCTP reset streams parameters. 544 | type SCTPResetStreams struct { 545 | AssocId int32 546 | Flags uint16 547 | NumberStreams uint16 548 | } 549 | 550 | // SCTPAddStreams represents the C struct sctp_add_streams for SCTP add streams parameters. 551 | type SCTPAddStreams struct { 552 | AssocId int32 553 | InStreams uint16 554 | OutStreams uint16 555 | } 556 | 557 | // SCTPAssocParams represents the C struct sctp_assocparams for SCTP association parameters. 558 | type SCTPAssocParams struct { 559 | AssocId int32 560 | AssocMaxrxt uint16 561 | NumberPeerDestinations uint16 562 | PeerRwnd uint32 563 | LocalRwnd uint32 564 | CookieLife uint32 565 | } 566 | 567 | // SCTPSetAdaptation represents the C struct sctp_setadaptation for SCTP adaptation layer parameters. 568 | type SCTPSetAdaptation struct { 569 | AdaptationInd uint32 570 | } 571 | 572 | // SCTPPeerAddrParams represents the C struct sctp_paddrparams for SCTP peer address parameters. 573 | type SCTPPeerAddrParams struct { 574 | AssocId int32 575 | Addr [128]byte 576 | HbInterval uint32 577 | PathMaxRxt uint16 578 | PathMtu uint32 579 | SackDelay uint32 580 | Flags uint32 581 | Ipv6FlowLabel uint32 582 | Dscp uint8 583 | _ uint8 584 | } 585 | 586 | // Pack serializes the SCTPPeerAddrParams struct into a byte slice. 587 | func (s *SCTPPeerAddrParams) Pack() []byte { 588 | buffer := bytes.NewBuffer(make([]byte, 0, SCTPPeerAddrParamsSize)) 589 | _ = binary.Write(buffer, endian, s.AssocId) 590 | _ = binary.Write(buffer, endian, s.Addr) 591 | _ = binary.Write(buffer, endian, s.HbInterval) 592 | _ = binary.Write(buffer, endian, s.PathMaxRxt) 593 | _ = binary.Write(buffer, endian, s.PathMtu) 594 | _ = binary.Write(buffer, endian, s.SackDelay) 595 | _ = binary.Write(buffer, endian, s.Flags) 596 | _ = binary.Write(buffer, endian, s.Ipv6FlowLabel) 597 | _ = binary.Write(buffer, endian, s.Dscp) 598 | _ = binary.Write(buffer, endian, uint8(0)) 599 | return buffer.Bytes() 600 | } 601 | 602 | // Unpack deserializes a byte slice into the SCTPPeerAddrParams struct. 603 | func (s *SCTPPeerAddrParams) Unpack(data []byte) { 604 | if len(data) == SCTPPeerAddrParamsSize { 605 | buffer := bytes.NewReader(data) 606 | _ = binary.Read(buffer, endian, s.AssocId) 607 | _ = binary.Read(buffer, endian, s.Addr) 608 | _ = binary.Read(buffer, endian, s.HbInterval) 609 | _ = binary.Read(buffer, endian, s.PathMaxRxt) 610 | _ = binary.Read(buffer, endian, s.PathMtu) 611 | _ = binary.Read(buffer, endian, s.SackDelay) 612 | _ = binary.Read(buffer, endian, s.Flags) 613 | _ = binary.Read(buffer, endian, s.Ipv6FlowLabel) 614 | _ = binary.Read(buffer, endian, s.Dscp) 615 | } 616 | } 617 | 618 | // SCTPPeerAddrInfo represents the C struct sctp_paddrinfo for SCTP peer address information. 619 | type SCTPPeerAddrInfo struct { 620 | AssocId int32 621 | Addr [128]byte 622 | State int32 623 | Cwnd uint32 624 | Srtt uint32 625 | Rto uint32 626 | Mtu uint32 627 | } 628 | 629 | // SCTPAssocValue represents the C struct sctp_assoc_value for SCTP association value parameters. 630 | type SCTPAssocValue struct { 631 | Id int32 632 | Value uint32 633 | } 634 | 635 | // SCTPSackInfo represents the C struct sctp_sack_info for SCTP selective acknowledgment information. 636 | type SCTPSackInfo struct { 637 | AssocId int32 638 | Delay uint32 639 | Freq uint32 640 | } 641 | 642 | // SCTPStreamValue represents the C struct sctp_stream_value for SCTP stream value parameters. 643 | type SCTPStreamValue struct { 644 | AssocId int32 645 | StreamId uint16 646 | StreamValue uint16 647 | } 648 | 649 | // SCTPStatus represents the C struct sctp_status for SCTP association status. 650 | type SCTPStatus struct { 651 | AssocId int32 652 | State int32 653 | Rwnd uint32 654 | UnackedData uint16 655 | PendingData uint16 656 | InStreams uint16 657 | OutStreams uint16 658 | FragmentationPoint uint32 659 | Primary SCTPPeerAddrInfo 660 | } 661 | 662 | // SCTPAuthKeyId represents the C struct sctp_authkeyid for SCTP authentication key ID. 663 | type SCTPAuthKeyId struct { 664 | AssocId int32 665 | KeyNumber uint16 666 | _ uint16 667 | } 668 | 669 | // SCTPAuthKey represents the C struct sctp_authkey for SCTP authentication key. 670 | type SCTPAuthKey struct { 671 | AssocId int32 672 | KeyNumber uint16 673 | KeyLength uint16 674 | // Member Key is removed as it is variable sized array. 675 | } 676 | 677 | // SCTPAuthChunk represents the C struct sctp_authchunk for SCTP authentication chunk. 678 | type SCTPAuthChunk struct { 679 | Chunk uint8 680 | } 681 | 682 | // SCTPHmacAlgo represents the C struct sctp_hmacalgo for SCTP HMAC algorithm. 683 | type SCTPHmacAlgo struct { 684 | NumIdents uint32 685 | // Member Idents is removed as it is variable sized array. 686 | } 687 | 688 | // SCTPAuthChunks represents the C struct sctp_authchunks for SCTP authentication chunks. 689 | type SCTPAuthChunks struct { 690 | AssocId int32 691 | NumberChunks uint32 692 | // Member Chunks is removed as it is variable sized array. 693 | } 694 | 695 | // SCTPAssocIds represents the C struct sctp_assoc_ids for SCTP association IDs. 696 | type SCTPAssocIds struct { 697 | NumberIds uint32 698 | // Member Ids is removed as it is variable sized array. 699 | } 700 | 701 | // SCTPAssocStats represents the C struct sctp_assoc_stats for SCTP association statistics. 702 | type SCTPAssocStats struct { 703 | AssocId int32 704 | Addr SockAddrStorage 705 | MaxRto uint64 706 | ISacks uint64 707 | OSacks uint64 708 | OPackets uint64 709 | IPackets uint64 710 | RtxChunks uint64 711 | OutOfSeqTsns uint64 712 | IDupChunks uint64 713 | GapCnt uint64 714 | OUodChunks uint64 715 | IUodChunks uint64 716 | OodChunks uint64 717 | IodChunks uint64 718 | OCtrlChunks uint64 719 | ICtrlChunks uint64 720 | } 721 | 722 | // SCTPPeerAddrThresholds represents the C struct sctp_paddrthlds for SCTP peer address thresholds. 723 | type SCTPPeerAddrThresholds struct { 724 | AssocId int32 725 | Address SockAddrStorage 726 | PathMaxRxt uint16 727 | PathPfThreshold uint16 728 | } 729 | 730 | // SCTPPRStatus represents the C struct sctp_prstatus for SCTP partial reliability status. 731 | type SCTPPRStatus struct { 732 | AssocId int32 733 | Sid uint16 734 | Policy uint16 735 | AbandonedUnsent uint64 736 | AbandonedSent uint64 737 | } 738 | 739 | // SCTPDefaultPRInfo represents the C struct sctp_default_prinfo for SCTP default partial reliability information. 740 | type SCTPDefaultPRInfo struct { 741 | AssocId int32 742 | Value uint32 743 | Policy uint16 744 | } 745 | 746 | // SCTPEvent represents the C struct sctp_event for SCTP event parameters. 747 | type SCTPEvent struct { 748 | AssocId int32 749 | Type uint16 750 | On uint8 751 | } 752 | 753 | // SCTPInfo represents the C struct sctp_info for SCTP association information. 754 | // 755 | //lint:ignore U1000 "auto-generated" 756 | type SCTPInfo struct { 757 | Tag uint32 758 | State uint32 759 | Rwnd uint32 760 | UnackedData uint16 761 | PendingData uint16 762 | InStreams uint16 763 | OutStreams uint16 764 | FragmentationPoint uint32 765 | InQueue uint32 766 | OutQueue uint32 767 | OverallError uint32 768 | MaxBurst uint32 769 | MaxSeg uint32 770 | PeerRwnd uint32 771 | PeerTag uint32 772 | PeerCapable uint8 773 | PeerSack uint8 774 | _1 uint16 775 | ISacks uint64 776 | OSacks uint64 777 | OPackets uint64 778 | IPackets uint64 779 | RtxChunks uint64 780 | OutOfSeqTsns uint64 781 | IDupChunks uint64 782 | GapCount uint64 783 | OUodChunks uint64 784 | IUodChunks uint64 785 | OOdChunks uint64 786 | IOdChunks uint64 787 | OCtrlChunks uint64 788 | ICtrlChunks uint64 789 | PrimaryAddress SockAddrStorage 790 | PrimaryState int32 791 | PrimaryCwnd uint32 792 | PrimarySrtt uint32 793 | PrimaryRto uint32 794 | PrimaryHbInterval uint32 795 | PrimaryPathMaxRxt uint32 796 | PrimarySackDelay uint32 797 | PrimarySackFreq uint32 798 | PrimarySsThreshold uint32 799 | PrimaryPartialBytesAcked uint32 800 | PrimaryFlightSize uint32 801 | PrimaryError uint16 802 | _2 uint16 803 | SockAutoClose uint32 804 | SockAdaptationInd uint32 805 | SockPdPoint uint32 806 | SockNodelay uint8 807 | SockDisableFragments uint8 808 | SockV4Mapped uint8 809 | SockFragInterleave uint8 810 | SockType uint32 811 | _3 uint32 812 | } 813 | --------------------------------------------------------------------------------