commit 2ca7d44946664efa74301c04a675754acb673fce
parent b0ed875484aa33cc54d614c2b6bba13a449fd64b
Author: Henry Wilson <henry@henryandlizzy.uk>
Date: Tue, 3 Dec 2024 02:38:19 +0000
sctp: SCTP protocol demo
Diffstat:
M | Tupfile | | | 1 | + |
A | src/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;
+}