examples

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

sctp.cpp (4553B)


      1 #include <iostream>
      2 #include <cassert>
      3 #include <sstream>
      4 #include <string_view>
      5 #include <print>
      6 #include <experimental/iterator>
      7 
      8 #include <unistd.h>
      9 #include <sys/socket.h>
     10 #include <netinet/in.h>
     11 #include <arpa/inet.h>
     12 #include <netinet/sctp.h>
     13 #include <netdb.h>
     14 struct file_descriptor
     15 {
     16 	explicit file_descriptor(int f) noexcept
     17 	:	fd{f}
     18 	{}
     19 	~file_descriptor()
     20 	{
     21 		if (*this)
     22 			::close(fd);
     23 	}
     24 
     25 	file_descriptor(file_descriptor const&) = delete;
     26 	file_descriptor& operator =(file_descriptor const&) = delete;
     27 
     28 	operator int() noexcept { return fd; };
     29 	explicit operator bool() const noexcept { return fd >= 0; }
     30 
     31 private:
     32 	int fd;
     33 };
     34 
     35 struct sockaddr_in addr = {AF_INET, 9001, {}, {}};
     36 
     37 void server()
     38 {
     39 	file_descriptor sd{socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP)};
     40 	assert(sd);
     41 	sctp_event se = {.se_assoc_id=SCTP_ALL_ASSOC, .se_type=SCTP_SHUTDOWN_EVENT, .se_on=1};
     42 	assert(!setsockopt(sd, getprotobyname("sctp")->p_proto, SCTP_EVENT, &se, sizeof(se)));
     43 
     44 //int setsockopt(int sockfd, int level, int optname,
     45   //                    const void optval[.optlen],
     46     //                  socklen_t optlen);
     47 	assert(!bind(sd, (sockaddr*)&addr, sizeof addr));
     48 	assert(!listen(sd, 1));
     49 	std::println("listening...");
     50 
     51 	for (;;)
     52 	{
     53 		struct sockaddr from;
     54 		socklen_t fromlen;
     55 		sctp_sndrcvinfo info;
     56 		int flags = 0;
     57 		char buf[256] = {};
     58 		int len = sctp_recvmsg(sd, buf, sizeof(buf), &from, &fromlen, &info, &flags);
     59 		assert(len >= 0);
     60 
     61 		std::ostringstream f;
     62 		auto fj = std::experimental::make_ostream_joiner(f, ", ");
     63 
     64 		if ((flags & SCTP_NOTIFICATION) == SCTP_NOTIFICATION)
     65 			*fj = "NOTIFICATION";
     66 		if ((flags & SCTP_EOF) == SCTP_EOF)
     67 			*fj = "EOF";
     68 		if ((flags & SCTP_ASSOC_CHANGE) == SCTP_ASSOC_CHANGE)
     69 			*fj = "ASSOC_CHANGE";
     70 		if ((flags & SCTP_PEER_ADDR_CHANGE) == SCTP_PEER_ADDR_CHANGE)
     71 			*fj = "PEER_ADDR_CHANGE";
     72 		if ((flags & SCTP_REMOTE_ERROR) == SCTP_REMOTE_ERROR)
     73 			*fj = "REMOTE_ERROR";
     74 		if ((flags & SCTP_SEND_FAILED) == SCTP_SEND_FAILED)
     75 			*fj = "SEND_FAILED";
     76 		if ((flags & SCTP_SHUTDOWN_EVENT) == SCTP_SHUTDOWN_EVENT)
     77 			*fj = "SHUTDOWN_EVENT";
     78 		if ((flags & SCTP_ADAPTATION_INDICATION) == SCTP_ADAPTATION_INDICATION)
     79 			*fj = "ADAPTATION_INDICATION";
     80 		if ((flags & SCTP_PARTIAL_DELIVERY_EVENT) == SCTP_PARTIAL_DELIVERY_EVENT)
     81 			*fj = "PARTIAL_DELIVERY_EVENT";
     82 		if ((flags & SCTP_AUTHENTICATION_EVENT) == SCTP_AUTHENTICATION_EVENT)
     83 			*fj = "AUTHENTICATION_EVENT";
     84 		if ((flags & SCTP_SENDER_DRY_EVENT) == SCTP_SENDER_DRY_EVENT)
     85 			*fj = "AUTHENTICATION_EVENT";
     86 		if ((flags & SCTP_SEND_FAILED_EVENT) == SCTP_SEND_FAILED_EVENT)
     87 			*fj = "SEND_FAILED_EVENT";
     88 //		std::println("SEND_FAILED_EVENT = {:04x}", +SCTP_SEND_FAILED_EVENT);
     89 		std::println("flags = {:04x} {}", flags, f.str());
     90 		std::println("stream = {}", info.sinfo_stream);
     91 		if (info.sinfo_ssn)
     92 			std::println("ssn = {}", info.sinfo_ssn);
     93 		if (info.sinfo_flags)
     94 			std::println("flags = {}", info.sinfo_flags);
     95 		if (info.sinfo_ppid)
     96 			std::println("ppid = {}", info.sinfo_ppid);
     97 		if (info.sinfo_context)
     98 			std::println("ctx = {}", info.sinfo_context);
     99 		if (info.sinfo_timetolive)
    100 			std::println("ttl = {}", info.sinfo_timetolive);
    101 		if (info.sinfo_tsn)
    102 			std::println("tsn = {}", info.sinfo_tsn);
    103 		if (info.sinfo_cumtsn)
    104 			std::println("cumtsn = {}", info.sinfo_cumtsn);
    105 		if ((flags & SCTP_NOTIFICATION) != SCTP_NOTIFICATION)
    106 			std::println("msg = '{}' {}", std::string_view{buf, (unsigned)len}, flags & MSG_EOR ? "EOR" : "...");
    107 	}
    108 }
    109 
    110 void client()
    111 {
    112 	file_descriptor sd{socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP)};
    113 	assert(sd);
    114 	//assert(!connect(sd, (sockaddr*)&addr, sizeof addr));
    115 	//write(sd, "Hello!", 6);
    116 	assert(6 == sctp_sendmsg(sd, "Hello!", 6,
    117                         (struct sockaddr *)&addr, sizeof(addr),
    118                         0, 0,
    119                         0, 1000,
    120                         1337));
    121         sleep(1);
    122 	assert(4 == sctp_sendmsg(sd, "Bye.", 4,
    123                         (struct sockaddr *)&addr, sizeof(addr),
    124                         8008, 0,
    125                         0, 1000,
    126                         1337));
    127         sleep(1);
    128 	assert(0 == sctp_sendmsg(sd, nullptr, 0,
    129                         (struct sockaddr *)&addr, sizeof(addr),
    130                         0, SCTP_EOF,
    131                         0, 1000,
    132                         1337));
    133         sleep(1);
    134 }
    135 
    136 int main(int argc, char* argv[])
    137 {
    138 	assert(inet_aton("127.0.0.1", &addr.sin_addr));
    139 	if (argc == 2) switch (argv[1][0])
    140 	{
    141 	case 's':
    142 		server();
    143 		return 0;
    144 	case 'c':
    145 		client();
    146 		return 0;
    147 	}
    148 	std::println("s/c not specified");
    149 	return 1;
    150 }