examples

Toy examples in single C files.
git clone git://henryandlizzy.uk/examples
Log | Files | Refs

commit 2ca7d44946664efa74301c04a675754acb673fce
parent b0ed875484aa33cc54d614c2b6bba13a449fd64b
Author: Henry Wilson <henry@henryandlizzy.uk>
Date:   Tue,  3 Dec 2024 02:38:19 +0000

sctp: SCTP protocol demo

Diffstat:
MTupfile | 1+
Asrc/sctp.cpp | 150+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 151 insertions(+), 0 deletions(-)

diff --git a/Tupfile b/Tupfile @@ -14,6 +14,7 @@ LDLIBS_sdl = -lSDL2 LDLIBS_sdl-gl = -lSDL2 -lGL LDLIBS_pulse-async-client = -lpulse LDLIBS_pulse-simple-client = -lpulse-simple -lm +LDLIBS_sctp = -lsctp LDLIBS_sqlite-saveload = -lsqlite3 : foreach src/*.c |> cc $(CFLAGS) -o %o %f $(LDLIBS_%B) |> bin/%B diff --git a/src/sctp.cpp b/src/sctp.cpp @@ -0,0 +1,150 @@ +#include <iostream> +#include <cassert> +#include <sstream> +#include <string_view> +#include <print> +#include <experimental/iterator> + +#include <unistd.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netinet/sctp.h> +#include <netdb.h> +struct file_descriptor +{ + explicit file_descriptor(int f) noexcept + : fd{f} + {} + ~file_descriptor() + { + if (*this) + ::close(fd); + } + + file_descriptor(file_descriptor const&) = delete; + file_descriptor& operator =(file_descriptor const&) = delete; + + operator int() noexcept { return fd; }; + explicit operator bool() const noexcept { return fd >= 0; } + +private: + int fd; +}; + +struct sockaddr_in addr = {AF_INET, 9001, {}, {}}; + +void server() +{ + file_descriptor sd{socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP)}; + assert(sd); + sctp_event se = {.se_assoc_id=SCTP_ALL_ASSOC, .se_type=SCTP_SHUTDOWN_EVENT, .se_on=1}; + assert(!setsockopt(sd, getprotobyname("sctp")->p_proto, SCTP_EVENT, &se, sizeof(se))); + +//int setsockopt(int sockfd, int level, int optname, + // const void optval[.optlen], + // socklen_t optlen); + assert(!bind(sd, (sockaddr*)&addr, sizeof addr)); + assert(!listen(sd, 1)); + std::println("listening..."); + + for (;;) + { + struct sockaddr from; + socklen_t fromlen; + sctp_sndrcvinfo info; + int flags = 0; + char buf[256] = {}; + int len = sctp_recvmsg(sd, buf, sizeof(buf), &from, &fromlen, &info, &flags); + assert(len >= 0); + + std::ostringstream f; + auto fj = std::experimental::make_ostream_joiner(f, ", "); + + if ((flags & SCTP_NOTIFICATION) == SCTP_NOTIFICATION) + *fj = "NOTIFICATION"; + if ((flags & SCTP_EOF) == SCTP_EOF) + *fj = "EOF"; + if ((flags & SCTP_ASSOC_CHANGE) == SCTP_ASSOC_CHANGE) + *fj = "ASSOC_CHANGE"; + if ((flags & SCTP_PEER_ADDR_CHANGE) == SCTP_PEER_ADDR_CHANGE) + *fj = "PEER_ADDR_CHANGE"; + if ((flags & SCTP_REMOTE_ERROR) == SCTP_REMOTE_ERROR) + *fj = "REMOTE_ERROR"; + if ((flags & SCTP_SEND_FAILED) == SCTP_SEND_FAILED) + *fj = "SEND_FAILED"; + if ((flags & SCTP_SHUTDOWN_EVENT) == SCTP_SHUTDOWN_EVENT) + *fj = "SHUTDOWN_EVENT"; + if ((flags & SCTP_ADAPTATION_INDICATION) == SCTP_ADAPTATION_INDICATION) + *fj = "ADAPTATION_INDICATION"; + if ((flags & SCTP_PARTIAL_DELIVERY_EVENT) == SCTP_PARTIAL_DELIVERY_EVENT) + *fj = "PARTIAL_DELIVERY_EVENT"; + if ((flags & SCTP_AUTHENTICATION_EVENT) == SCTP_AUTHENTICATION_EVENT) + *fj = "AUTHENTICATION_EVENT"; + if ((flags & SCTP_SENDER_DRY_EVENT) == SCTP_SENDER_DRY_EVENT) + *fj = "AUTHENTICATION_EVENT"; + if ((flags & SCTP_SEND_FAILED_EVENT) == SCTP_SEND_FAILED_EVENT) + *fj = "SEND_FAILED_EVENT"; +// std::println("SEND_FAILED_EVENT = {:04x}", +SCTP_SEND_FAILED_EVENT); + std::println("flags = {:04x} {}", flags, f.str()); + std::println("stream = {}", info.sinfo_stream); + if (info.sinfo_ssn) + std::println("ssn = {}", info.sinfo_ssn); + if (info.sinfo_flags) + std::println("flags = {}", info.sinfo_flags); + if (info.sinfo_ppid) + std::println("ppid = {}", info.sinfo_ppid); + if (info.sinfo_context) + std::println("ctx = {}", info.sinfo_context); + if (info.sinfo_timetolive) + std::println("ttl = {}", info.sinfo_timetolive); + if (info.sinfo_tsn) + std::println("tsn = {}", info.sinfo_tsn); + if (info.sinfo_cumtsn) + std::println("cumtsn = {}", info.sinfo_cumtsn); + if ((flags & SCTP_NOTIFICATION) != SCTP_NOTIFICATION) + std::println("msg = '{}' {}", std::string_view{buf, (unsigned)len}, flags & MSG_EOR ? "EOR" : "..."); + } +} + +void client() +{ + file_descriptor sd{socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP)}; + assert(sd); + //assert(!connect(sd, (sockaddr*)&addr, sizeof addr)); + //write(sd, "Hello!", 6); + assert(6 == sctp_sendmsg(sd, "Hello!", 6, + (struct sockaddr *)&addr, sizeof(addr), + 0, 0, + 0, 1000, + 1337)); + sleep(1); + assert(4 == sctp_sendmsg(sd, "Bye.", 4, + (struct sockaddr *)&addr, sizeof(addr), + 8008, 0, + 0, 1000, + 1337)); + sleep(1); + assert(0 == sctp_sendmsg(sd, nullptr, 0, + (struct sockaddr *)&addr, sizeof(addr), + 0, SCTP_EOF, + 0, 1000, + 1337)); + sleep(1); +} + +int main(int argc, char* argv[]) +{ + assert(inet_aton("127.0.0.1", &addr.sin_addr)); + if (argc == 2) switch (argv[1][0]) + { + case 's': + server(); + return 0; + case 'c': + client(); + return 0; + } + std::println("s/c not specified"); + return 1; +}