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 }