From e81e7be7c0e8a75b34b2a36353b8167ec6b10e20 Mon Sep 17 00:00:00 2001 From: Ludovic Chenut Date: Tue, 8 Nov 2022 13:08:19 +0100 Subject: [PATCH] Fix some bugs & rebuild accept --- build.sh | 1 + examples/sctp_client.nim | 3 +- examples/sctp_st_client.nim | 77 ++++++++++++++++++++++++ examples/sctp_st_daytimeserver.nim | 7 +++ webrtc/sctp.nim | 95 ++++++++++++++++++++++-------- webrtc/usrsctp.nim | 15 ++++- 6 files changed, 172 insertions(+), 26 deletions(-) create mode 100644 examples/sctp_st_client.nim create mode 100644 examples/sctp_st_daytimeserver.nim diff --git a/build.sh b/build.sh index 0ce73f2..41b377f 100755 --- a/build.sh +++ b/build.sh @@ -22,6 +22,7 @@ done # and put the different flags on prelude.nim depending on the # OS we're currently on LIBCFLAGS="$(grep "^LIBCFLAGS = " "${root}/usrsctp/Makefile" | cut -d' ' -f3- | sed 's/-D/--defines=/g')" +LIBCFLAGS="${LIBCFLAGS} --defines=SCTP_DEBUG --defines=HAVE_INET_ADDR=1 --defines=INET=1" # generate nim wrapper with nimterop toast \ diff --git a/examples/sctp_client.nim b/examples/sctp_client.nim index 9f030d8..4246a6d 100644 --- a/examples/sctp_client.nim +++ b/examples/sctp_client.nim @@ -3,9 +3,10 @@ import ../webrtc/sctp proc main() {.async.} = let - sctp = Sctp.new(port = 4242) + sctp = Sctp.new(port = 4244) address = TransportAddress(initTAddress("127.0.0.1:9899")) conn = await sctp.connect(address) await conn.write("toto".toBytes) + await sleepAsync(3.seconds) waitFor(main()) diff --git a/examples/sctp_st_client.nim b/examples/sctp_st_client.nim new file mode 100644 index 0000000..97433a5 --- /dev/null +++ b/examples/sctp_st_client.nim @@ -0,0 +1,77 @@ +import bitops +import chronos, posix +import ../webrtc/usrsctp +import stew/ranges/ptr_arith + +const IPPROTO_SCTP = 132 +let ta = initTAddress("127.0.0.1:4244") +let tar = initTAddress("127.0.0.1:4242") + +proc connOutput(address: pointer, + buffer: pointer, + length: uint, + tos: uint8, + set_df: uint8): cint {.cdecl.} = + echo "====> connOutput: ", usrsctp_dumppacket(buffer, length, SCTP_DUMP_OUTBOUND) + let dg: ptr DatagramTransport = cast[ptr DatagramTransport](address) + proc testSend() {.async.} = + try: + let buf = @(buffer.makeOpenArray(byte, int(length))) + echo "START await sendTo START" + await sendTo(dg[], tar, buf, int(length)) + echo "STOP await sendTo STOP" + except CatchableError as exc: + echo "Failure: ", exc.msg + + asyncSpawn testSend() + echo "connOutput <====" + +var connected = false +proc handleUpcall(sock: ptr socket, arg: pointer, length: cint) {.cdecl.} = + let e = usrsctp_get_events(sock) + echo "handleUpcall: event = ", e + if bitor(e, SCTP_EVENT_WRITE) != 0 and not connected: + echo "connect" + connected = true + elif bitor(e, SCTP_EVENT_READ) != 0: + echo "recv" + else: + echo "/!\\ ERROR /!\\" + +proc printf(format: cstring) {.cdecl, varargs.} = echo "printf" + +proc handleEvents(dg: DatagramTransport, sock: ptr socket, sconn_addr: pointer) {.async.} = + await sleepAsync(3.seconds) + +proc main {.async, gcsafe.} = + let fut = newFuture[void]() + var p: pointer + proc clientMark(transp: DatagramTransport, raddr: TransportAddress): Future[void] {.async.} = + var msg = transp.getMessage() + echo "Client Mark: ", usrsctp_dumppacket(addr msg[0], uint(msg.len), SCTP_DUMP_INBOUND) + usrsctp_conninput(p, addr msg[0], uint(msg.len), 0) + + var dg = newDatagramTransport(clientMark, remote=tar, local=ta) + p = cast[pointer](addr dg) + usrsctp_init_nothreads(0, connOutput, printf) + discard usrsctp_sysctl_set_sctp_ecn_enable(1) + usrsctp_register_address(p) + let sock = usrsctp_socket(AF_INET, posix.SOCK_STREAM, IPPROTO_SCTP, nil, nil, 0, nil) + var on: int = 1 + doAssert 0 == usrsctp_setsockopt(sock, IPPROTO_SCTP, SCTP_RECVRCVINFO, addr on, sizeof(on).SockLen) + doAssert 0 == usrsctp_set_non_blocking(sock, 1) + doAssert 0 == usrsctp_set_upcall(sock, handleUpcall, nil) + var sconn: Sockaddr_conn + sconn.sconn_family = AF_CONN + sconn.sconn_port = htons(0) + sconn.sconn_addr = nil + doAssert 0 == usrsctp_bind(sock, cast[ptr SockAddr](addr sconn), sizeof(sconn).SockLen) + sconn.sconn_family = AF_CONN + sconn.sconn_port = htons(13) + sconn.sconn_addr = p + let connErr = usrsctp_connect(sock, cast[ptr SockAddr](addr sconn), sizeof(sconn).SockLen) + doAssert 0 == connErr or errno == EINPROGRESS, ($errno) + + await handleEvents(dg, sock, sconn.sconn_addr) + +waitFor(main()) diff --git a/examples/sctp_st_daytimeserver.nim b/examples/sctp_st_daytimeserver.nim new file mode 100644 index 0000000..36cfc1f --- /dev/null +++ b/examples/sctp_st_daytimeserver.nim @@ -0,0 +1,7 @@ +import chronos +import ../webrtc/usrsctp + +proc main() {.async.} = + discard + +waitFor(main()) diff --git a/webrtc/sctp.nim b/webrtc/sctp.nim index c4aa5f8..9dd55e7 100644 --- a/webrtc/sctp.nim +++ b/webrtc/sctp.nim @@ -11,6 +11,8 @@ import tables, bitops, posix import chronos, chronicles, stew/ranges/ptr_arith import usrsctp +export chronicles + logScope: topics = "webrtc sctp" @@ -37,7 +39,22 @@ type const IPPROTO_SCTP = 132 +template usrsctpAwait(sctp: Sctp, body: untyped) = + sctp.sentFuture = nil + body + if sctp.sentFuture != nil: + await sctp.sentFuture + proc perror(error: cstring) {.importc, cdecl, header: "".} +proc printf(format: cstring) {.cdecl, varargs.} = echo "printf" +proc packetPretty(packet: cstring): string = + let data = $packet + let ctn = data[23..^16] + result = data[1..14] + if ctn.len > 30: + result = result & ctn[0..14] & " ... " & ctn[^14..^1] + else: + result = result & ctn proc new(T: typedesc[SctpConnection], sctp: Sctp, @@ -56,17 +73,18 @@ proc write*(self: SctpConnection, buf: seq[byte]) {.async.} = proc close*(self: SctpConnection) {.async.} = discard proc handleUpcall(sock: ptr socket, data: pointer, flags: cint) {.cdecl.} = - let e = usrsctp_get_events(sock) - echo "handleUpcall: event = ", e - if bitor(e, SCTP_EVENT_WRITE) != 0: # and not connected: + let events = usrsctp_get_events(sock) + trace "Handle Upcall", events + if bitor(events, SCTP_EVENT_WRITE) != 0: # and not connected: echo "connect" #connected = true - elif bitor(e, SCTP_EVENT_READ) != 0: + elif bitor(events, SCTP_EVENT_READ) != 0: echo "recv" else: echo "/!\\ ERROR /!\\" proc handleAccept(sock: ptr socket, data: pointer, flags: cint) {.cdecl.} = + trace "Handle Accept" var sin: Sockaddr_in size: SockLen @@ -87,9 +105,11 @@ proc getOrCreateConnection(self: Sctp, address: TransportAddress): SctpConnection = if self.connections.hasKey(address): return self.connections[address] + trace "Create Connection", address let sctpSocket = usrsctp_socket(AF_CONN, posix.SOCK_STREAM, IPPROTO_SCTP, nil, nil, 0, nil) conn = SctpConnection.new(self, udp, address, sctpSocket) + sctpPtr = cast[pointer](addr self) var on: int = 1 doAssert 0 == usrsctp_setsockopt(conn.sctpSocket, IPPROTO_SCTP, @@ -101,8 +121,11 @@ proc getOrCreateConnection(self: Sctp, var sconn: Sockaddr_conn sconn.sconn_family = AF_CONN sconn.sconn_port = htons(5000) - sconn.sconn_addr = nil - doAssert 0 == conn.sctpSocket.usrsctp_connect(cast[ptr SockAddr](addr sconn), SockLen(sizeof(sconn))) + sconn.sconn_addr = sctpPtr + self.sentConnection = conn + echo "=======> Avant connect" + discard conn.sctpSocket.usrsctp_connect(cast[ptr SockAddr](addr sconn), SockLen(sizeof(sconn))) + echo "Après connect <=======" self.connections[address] = conn return conn @@ -111,59 +134,85 @@ proc sendCallback(address: pointer, length: uint, tos: uint8, set_df: uint8): cint {.cdecl.} = - trace "sendCallback", data = usrsctp_dumppacket(buffer, length, SCTP_DUMP_OUTBOUND) - let sctp: ptr Sctp = cast[ptr Sctp](address) + let data = usrsctp_dumppacket(buffer, length, SCTP_DUMP_OUTBOUND) + if data != nil: + trace "sendCallback", data = data.packetPretty(), length + usrsctp_freedumpbuffer(data) + let sctp: Sctp = (cast[ptr Sctp](address))[] proc testSend() {.async.} = try: - let buf = @(buffer.makeOpenArray(byte, int(length))) - await sendTo(sctp[].udp, sctp.sentConnection.address, buf, int(length)) + let + buf = @(buffer.makeOpenArray(byte, int(length))) + address = sctp.sentConnection.address + trace "Send To", address + await sendTo(sctp.udp, address, buf, int(length)) except CatchableError as exc: echo "Failure: ", exc.msg sctp.sentFuture = testSend() proc new*(T: typedesc[Sctp], port: uint16 = 9899, isServer: bool = false): T = + logScope: topics = "webrtc sctp" let - sctp = T(gotConnection: newAsyncEvent()) + sctp = T(gotConnection: newAsyncEvent(), isServer: isServer) sctpPtr = cast[pointer](addr sctp) - proc onReceive(udp: DatagramTransport, address: TransportAddress) {.async.} = + proc onReceive(udp: DatagramTransport, address: TransportAddress) {.async, gcsafe.} = let msg = udp.getMessage() - conn = sctp.getOrCreateConnection(udp, address) - connPtr = cast[pointer](addr conn) - usrsctp_conninput(connPtr, addr msg[0], uint(msg.len), 0) + data = usrsctp_dumppacket(addr msg[0], uint(msg.len), SCTP_DUMP_INBOUND) + if data != nil: + trace "onReceive", data = data.packetPretty(), length = msg.len() + usrsctp_freedumpbuffer(data) + + if sctp.isServer: + echo "OnReceive (server): ", sctp.connections.len + var sin: Sockaddr_in + var slen: SockLen + discard sctp.sock.usrsctp_accept(cast[ptr SockAddr](addr sin), addr slen) + perror("usrsctp_accept") + echo sin.sin_port, " ", sin.sin_addr.s_addr, " ", slen + + usrsctp_conninput(sctpPtr, addr msg[0], uint(msg.len), 0) + else: + echo "OnReceive (client): ", sctp.connections.len + let conn = sctp.getOrCreateConnection(udp, address) + sctp.sentConnection = conn + usrsctp_conninput(sctpPtr, addr msg[0], uint(msg.len), 0) let localAddr = TransportAddress(family: AddressFamily.IPv4, port: Port(port)) + trace "local address", localAddr + let udp = newDatagramTransport(onReceive, local = localAddr) - usrsctp_init_nothreads(port, sendCallback, nil) # TODO maybe put a debugger instead of nil + sctp.udp = udp + usrsctp_init_nothreads(0, sendCallback, nil) discard usrsctp_sysctl_set_sctp_ecn_enable(1) usrsctp_register_address(sctpPtr) - sctp.udp = udp if isServer: - echo errno, " <=" + doAssert 0 == usrsctp_sysctl_set_sctp_blackhole(2) + doAssert 0 == usrsctp_sysctl_set_sctp_no_csum_on_loopback(0) let sock = usrsctp_socket(AF_INET, posix.SOCK_STREAM, IPPROTO_SCTP, nil, nil, 0, nil) perror("usrsctp_socket") var on: int = 1 - echo "=> ", errno doAssert 0 == usrsctp_setsockopt(sock, IPPROTO_SCTP, SCTP_RECVRCVINFO, addr on, SockLen(sizeof(on))) doAssert 0 == usrsctp_set_non_blocking(sock, 1) - echo sock.usrsctp_set_upcall(handleAccept, sctpPtr) - echo errno + doAssert 0 == sock.usrsctp_set_upcall(handleAccept, sctpPtr) var sconn: Sockaddr_conn sconn.sconn_family = AF_CONN sconn.sconn_port = htons(5000) sconn.sconn_addr = nil - echo usrsctp_bind(sock, cast[ptr SockAddr](addr sconn), SockLen(sizeof(sconn))) - doAssert 0 < usrsctp_listen(sock, 1) + doAssert 0 == usrsctp_bind(sock, cast[ptr SockAddr](addr sconn), SockLen(sizeof(sconn))) + doAssert 0 >= usrsctp_listen(sock, 1) sctp.sock = sock return sctp proc listen*(self: Sctp, address: TransportAddress): Future[SctpConnection] {.async.} = while true: + echo "Listening" if self.connections.hasKey(address): return self.connections[address] self.gotConnection.clear() await self.gotConnection.wait() proc connect*(self: Sctp, address: TransportAddress): Future[SctpConnection] {.async.} = + trace "Connect", address let conn = self.getOrCreateConnection(self.udp, address) return conn diff --git a/webrtc/usrsctp.nim b/webrtc/usrsctp.nim index 6ebfc5a..08c1e91 100644 --- a/webrtc/usrsctp.nim +++ b/webrtc/usrsctp.nim @@ -9,9 +9,9 @@ const usrsctpInclude = root/"usrsctp"/"usrsctplib" {.passc: fmt"-I{usrsctpInclude}".} -# Generated @ 2022-10-28T14:25:24+02:00 +# Generated @ 2022-11-07T15:34:50+01:00 # Command line: -# /home/lchenut/.nimble/pkgs/nimterop-0.6.13/nimterop/toast --compile=./usrsctp/usrsctplib/netinet/sctp_input.c --compile=./usrsctp/usrsctplib/netinet/sctp_asconf.c --compile=./usrsctp/usrsctplib/netinet/sctp_pcb.c --compile=./usrsctp/usrsctplib/netinet/sctp_usrreq.c --compile=./usrsctp/usrsctplib/netinet/sctp_cc_functions.c --compile=./usrsctp/usrsctplib/netinet/sctp_auth.c --compile=./usrsctp/usrsctplib/netinet/sctp_userspace.c --compile=./usrsctp/usrsctplib/netinet/sctp_output.c --compile=./usrsctp/usrsctplib/netinet/sctp_callout.c --compile=./usrsctp/usrsctplib/netinet/sctp_crc32.c --compile=./usrsctp/usrsctplib/netinet/sctp_sysctl.c --compile=./usrsctp/usrsctplib/netinet/sctp_sha1.c --compile=./usrsctp/usrsctplib/netinet/sctp_timer.c --compile=./usrsctp/usrsctplib/netinet/sctputil.c --compile=./usrsctp/usrsctplib/netinet/sctp_bsd_addr.c --compile=./usrsctp/usrsctplib/netinet/sctp_peeloff.c --compile=./usrsctp/usrsctplib/netinet/sctp_indata.c --compile=./usrsctp/usrsctplib/netinet/sctp_ss_functions.c --compile=./usrsctp/usrsctplib/user_socket.c --compile=./usrsctp/usrsctplib/netinet6/sctp6_usrreq.c --compile=./usrsctp/usrsctplib/user_mbuf.c --compile=./usrsctp/usrsctplib/user_environment.c --compile=./usrsctp/usrsctplib/user_recv_thread.c --pnim --preprocess --noHeader --defines=SCTP_PROCESS_LEVEL_LOCKS --defines=SCTP_SIMPLE_ALLOCATOR --defines=__Userspace__ --replace=sockaddr=SockAddr --replace=SockAddr_storage=Sockaddr_storage --replace=SockAddr_in=Sockaddr_in --replace=SockAddr_conn=Sockaddr_conn --replace=socklen_t=SockLen --includeDirs=./usrsctp/usrsctplib ./usrsctp/usrsctplib/usrsctp.h +# /home/lchenut/.nimble/pkgs/nimterop-0.6.13/nimterop/toast --compile=./usrsctp/usrsctplib/netinet/sctp_input.c --compile=./usrsctp/usrsctplib/netinet/sctp_asconf.c --compile=./usrsctp/usrsctplib/netinet/sctp_pcb.c --compile=./usrsctp/usrsctplib/netinet/sctp_usrreq.c --compile=./usrsctp/usrsctplib/netinet/sctp_cc_functions.c --compile=./usrsctp/usrsctplib/netinet/sctp_auth.c --compile=./usrsctp/usrsctplib/netinet/sctp_userspace.c --compile=./usrsctp/usrsctplib/netinet/sctp_output.c --compile=./usrsctp/usrsctplib/netinet/sctp_callout.c --compile=./usrsctp/usrsctplib/netinet/sctp_crc32.c --compile=./usrsctp/usrsctplib/netinet/sctp_sysctl.c --compile=./usrsctp/usrsctplib/netinet/sctp_sha1.c --compile=./usrsctp/usrsctplib/netinet/sctp_timer.c --compile=./usrsctp/usrsctplib/netinet/sctputil.c --compile=./usrsctp/usrsctplib/netinet/sctp_bsd_addr.c --compile=./usrsctp/usrsctplib/netinet/sctp_peeloff.c --compile=./usrsctp/usrsctplib/netinet/sctp_indata.c --compile=./usrsctp/usrsctplib/netinet/sctp_ss_functions.c --compile=./usrsctp/usrsctplib/user_socket.c --compile=./usrsctp/usrsctplib/netinet6/sctp6_usrreq.c --compile=./usrsctp/usrsctplib/user_mbuf.c --compile=./usrsctp/usrsctplib/user_environment.c --compile=./usrsctp/usrsctplib/user_recv_thread.c --pnim --preprocess --noHeader --defines=SCTP_PROCESS_LEVEL_LOCKS --defines=SCTP_SIMPLE_ALLOCATOR --defines=__Userspace__ --defines=SCTP_DEBUG --defines=HAVE_INET_ADDR=1 --defines=INET=1 --replace=sockaddr=SockAddr --replace=SockAddr_storage=Sockaddr_storage --replace=SockAddr_in=Sockaddr_in --replace=SockAddr_conn=Sockaddr_conn --replace=socklen_t=SockLen --includeDirs=./usrsctp/usrsctplib ./usrsctp/usrsctplib/usrsctp.h # const 'SCTP_PACKED' has unsupported value '__attribute__((packed))' # const 'SCTP_INACTIVE' has unsupported value '0x0002 /* neither SCTP_ADDR_REACHABLE' @@ -23,6 +23,9 @@ const usrsctpInclude = root/"usrsctp"/"usrsctplib" {.passc: "-DSCTP_PROCESS_LEVEL_LOCKS".} {.passc: "-DSCTP_SIMPLE_ALLOCATOR".} {.passc: "-D__Userspace__".} +{.passc: "-DSCTP_DEBUG".} +{.passc: "-DHAVE_INET_ADDR=1".} +{.passc: "-DINET=1".} {.passc: "-I./usrsctp/usrsctplib".} {.compile: "./usrsctp/usrsctplib/netinet/sctp_input.c".} {.compile: "./usrsctp/usrsctplib/netinet/sctp_asconf.c".} @@ -269,6 +272,8 @@ const SCTP_BINDX_REM_ADDR* = 0x00008002 SCTP_DUMP_OUTBOUND* = 1 SCTP_DUMP_INBOUND* = 0 + SCTP_DEBUG_NONE* = 0x00000000 + SCTP_DEBUG_ALL* = 0xFFFFFFFF type sctp_assoc_t* = uint32 sctp_common_header* {.bycopy.} = object @@ -1291,5 +1296,11 @@ proc usrsctp_sysctl_set_sctp_buffer_splitting*(value: uint32): cint {.importc, proc usrsctp_sysctl_get_sctp_buffer_splitting*(): uint32 {.importc, cdecl.} proc usrsctp_sysctl_set_sctp_initial_cwnd*(value: uint32): cint {.importc, cdecl.} proc usrsctp_sysctl_get_sctp_initial_cwnd*(): uint32 {.importc, cdecl.} +proc usrsctp_sysctl_set_sctp_debug_on*(value: uint32): cint {.importc, cdecl.} +proc usrsctp_sysctl_get_sctp_debug_on*(): uint32 {.importc, cdecl.} + ## ``` + ## More specific values can be found in sctp_constants, but + ## are not considered to be part of the API. + ## ``` proc usrsctp_get_stat*(a1: ptr sctpstat) {.importc, cdecl.} {.pop.}