Skip to content

Instantly share code, notes, and snippets.

@nomis
Last active April 21, 2024 09:13
Show Gist options
  • Save nomis/b125c3885c937917078886fd4ad0f946 to your computer and use it in GitHub Desktop.
Save nomis/b125c3885c937917078886fd4ad0f946 to your computer and use it in GitHub Desktop.
dtee, implemented using sctp
$ make LDLIBS=-lsctp sctp
g++ sctp.cpp -lsctp -o sctp
$ ./sctp
flags 32896 assoc_id 0 stream 0 port 42417 len 20
flags 32896 assoc_id 0 stream 0 port 49898 len 20
flags 128 assoc_id 132 stream 0 port 42417 len 1 data o
flags 128 assoc_id 132 stream 0 port 42417 len 2 data OO
flags 128 assoc_id 134 stream 0 port 49898 len 1 data e
flags 128 assoc_id 134 stream 0 port 49898 len 2 data EE
flags 128 assoc_id 134 stream 0 port 49898 len 1 data e
flags 128 assoc_id 134 stream 0 port 49898 len 2 data EE
flags 128 assoc_id 132 stream 0 port 42417 len 1 data o
flags 128 assoc_id 132 stream 0 port 42417 len 2 data OO
#include <errno.h>
#include <netinet/in.h>
#include <netinet/sctp.h>
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <iostream>
int main() {
int si = -1;
int so = -1;
int se = -1;
struct sockaddr_in ai{};
struct sockaddr_in ao{};
struct sockaddr_in ae{};
struct sockaddr_in am{};
socklen_t li = sizeof(ai);
socklen_t lo = sizeof(ao);
socklen_t le = sizeof(ae);
socklen_t lm;
pid_t pid = getpid();
struct sctp_event_subscribe ei{};
ai.sin_family = AF_INET;
ai.sin_addr.s_addr = htonl(0x7F000000 | (pid & 0xFFFFFF));
ao.sin_family = AF_INET;
ao.sin_addr.s_addr = htonl(0x7F000000 | (pid & 0xFFFFFF));
ae.sin_family = AF_INET;
ae.sin_addr.s_addr = htonl(0x7F000000 | (pid & 0xFFFFFF));
si = socket(PF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);
if (si == -1) {
perror("socket");
return 1;
}
so = socket(PF_INET, SOCK_STREAM, IPPROTO_SCTP);
if (so == -1) {
perror("socket");
return 1;
}
se = socket(PF_INET, SOCK_STREAM, IPPROTO_SCTP);
if (se == -1) {
perror("socket");
return 1;
}
if (bind(si, reinterpret_cast<struct sockaddr*>(&ai), sizeof(ai)) == -1) {
perror("bind");
return 1;
}
if (bind(so, reinterpret_cast<struct sockaddr*>(&ao), sizeof(ao)) == -1) {
perror("bind");
return 1;
}
if (bind(se, reinterpret_cast<struct sockaddr*>(&ae), sizeof(ae)) == -1) {
perror("bind");
return 1;
}
if (getsockname(si, reinterpret_cast<struct sockaddr*>(&ai), &li) == -1) {
perror("getsockname");
return 1;
}
if (getsockname(so, reinterpret_cast<struct sockaddr*>(&ao), &lo) == -1) {
perror("getsockname");
return 1;
}
if (getsockname(se, reinterpret_cast<struct sockaddr*>(&ae), &le) == -1) {
perror("getsockname");
return 1;
}
ei.sctp_association_event = 1;
ei.sctp_data_io_event = 1;
if (setsockopt(si, IPPROTO_SCTP, SCTP_EVENTS, &ei, sizeof(ei)) == -1) {
perror("setsockopt");
return 1;
}
if (listen(si, 2) == -1) {
perror("listen");
return 1;
}
if (connect(so, reinterpret_cast<struct sockaddr*>(&ai), lo) == -1) {
perror("connect");
return 1;
}
if (connect(se, reinterpret_cast<struct sockaddr*>(&ai), le) == -1) {
perror("connect");
return 1;
}
write(so, "o", 1);
write(so, "OO", 2);
write(so, "o", 1);
write(so, "OO", 2);
write(se, "e", 1);
write(se, "EE", 2);
write(se, "e", 1);
write(se, "EE", 2);
while (true) {
char buf[4096] = { 0 };
struct sctp_sndrcvinfo info{};
int flags;
int len;
lm = sizeof(am);
flags = 0;
len = sctp_recvmsg(si, buf, sizeof(buf), reinterpret_cast<struct sockaddr *>(&am), &lm, &info, &flags);
if (len == -1) {
perror("sctp_recvmsg");
return 1;
}
std::cout
<< "flags " << flags
<< " assoc_id " << info.sinfo_assoc_id
<< " stream " << info.sinfo_stream
<< " port " << am.sin_port
<< " len " << len;
if (!(flags & MSG_NOTIFICATION)) {
if (len > 0)
std::cout << " data ";
for (int i = 0; i < len; i++ ) {
std::cout << buf[i];
}
}
std::cout << std::endl;
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment