Skip to content

Instantly share code, notes, and snippets.

@zserge
Last active May 4, 2022 10:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save zserge/481f27e66d4384a83001cff77de18c0f to your computer and use it in GitHub Desktop.
Save zserge/481f27e66d4384a83001cff77de18c0f to your computer and use it in GitHub Desktop.
//
// This is just a collection of syscalls that are used by libsctp linux implementation.
// Although it supports message-oriented workflow, it can't be wrapped into a net.PacketConn.
//
package main
import (
"log"
"syscall"
)
var (
PortLocal = 54321
PortRemote = 12345
HostRemote = [4]byte{127, 0, 0, 1}
)
func main() {
// Create a socket, STREAM and SEQPACKET types are supported, as per sctp(7)
//fd, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_SEQPACKET, syscall.IPPROTO_SCTP)
fd, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_STREAM, syscall.IPPROTO_SCTP)
if err != nil {
log.Fatal(err)
}
// Bind
err = syscall.Bind(fd, &syscall.SockaddrInet4{Port: PortLocal})
if err != nil {
syscall.Close(fd)
log.Fatal(err)
}
// This would be a perfect solution, but it fails, if fd is a SOCK_STREAM.
// If fd is a SOCK_SEQPACKET, it crashes:
//
// panic: runtime error: invalid memory address or nil pointer dereference
// [signal 0xb code=0x1 addr=0x20 pc=0x479fbb]
//
// goroutine 1 [running]:
// panic(0x526c40, 0xc82000a150)
// /usr/local/go/src/runtime/panic.go:481 +0x3e6
// net.newFileFD(0xc820028030, 0x0, 0x0, 0x0)
// /usr/local/go/src/net/file_unix.go:57 +0x4eb
// net.filePacketConn(0xc820028030, 0x0, 0x0, 0x0, 0x0)
// /usr/local/go/src/net/file_unix.go:101 +0x54
// net.FilePacketConn(0xc820028030, 0x0, 0x0, 0x0, 0x0)
// /usr/local/go/src/net/file.go:43 +0x4d
//
// f := os.NewFile(uintptr(fd), fmt.Sprintf("socket fd %d", fd))
// conn, err = net.FilePacketConn(f)
// log.Println(conn, err)
// Sendmsg and Recvmsg work fine. But they are not goroutine-friendly.
// This means that polling on multiple fds has to be implemented manually,
// which is beyond the scope if this primitive example
p := []byte("Hello")
oob := []byte{}
raddr := &syscall.SockaddrInet4{Port: PortRemote, Addr: HostRemote}
err = syscall.Sendmsg(fd, p, oob, raddr, 0)
if err != nil {
syscall.Close(fd)
log.Fatal(err)
}
n, oobn, rflags, from, err := syscall.Recvmsg(fd, p, oob, 0)
if err != nil {
syscall.Close(fd)
log.Fatal(err)
}
log.Println(n, oobn, rflags, from, string(p[:n]), oob[:oobn])
// Close() error
err = syscall.Close(fd)
if err != nil {
log.Fatal(err)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment