Skip to content

Instantly share code, notes, and snippets.

@paigeadelethompson
Last active June 24, 2024 09:52
Show Gist options
  • Save paigeadelethompson/e916f95607fbf193ecafb08295ecab68 to your computer and use it in GitHub Desktop.
Save paigeadelethompson/e916f95607fbf193ecafb08295ecab68 to your computer and use it in GitHub Desktop.
Really simple usrsctp SCTP library example (with UDP encapsulation and without, instructions in the comments)
// cc -g3 -I /usr/local/include -l usrsctp -L /usr/local/lib -l pthread server.c -o server
// [email protected]
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include <pthread.h>
#include <unistd.h>
#include <usrsctp.h>
#define LOCAL_ADDRESS "127.0.0.1"
#define LOCAL_UDP_ENCAPS_PORT 19819
#define REMOTE_ADDRESS "127.0.0.1"
#define REMOTE_UDP_ENCAPS_PORT 19818
#define REMOTE_SCTP_PORT 19818
#define LOCAL_SCTP_PORT 19819
#define DEFAULT_TARGET stdout;
#define DEBUG 1
int done = 0;
static FILE *debug_target = NULL;
static int
receive_cb(struct socket *sock, union sctp_sockstore addr, void *data,
size_t datalen, struct sctp_rcvinfo rcv, int flags, void *ulp_info);
void
debug_printf_stack(const char *format, ...);
void
handle_notification(union sctp_notification *notif, size_t n);
static void
handle_remote_error_event(struct sctp_remote_error *sre);
static void
handle_stream_change_event(struct sctp_stream_change_event *strchg);
static void
handle_stream_change_event(struct sctp_stream_change_event *strchg);
static void
handle_stream_reset_event(struct sctp_stream_reset_event *strrst);
static void
handle_shutdown_event(struct sctp_shutdown_event *sse);
static void
handle_adaptation_indication(struct sctp_adaptation_event *sai);
void
debug_set_target(FILE *fp);
void
debug_printf(const char *format, ...);
int
main(int argc, char **argv) {
struct socket *sock;
struct sockaddr *addr, *addrs;
struct sockaddr_in addr4;
struct sockaddr_in6 addr6;
struct sctp_udpencaps encaps;
struct sctpstat stat;
struct sctp_event event;
uint16_t event_types[] = {SCTP_ASSOC_CHANGE,
SCTP_PEER_ADDR_CHANGE,
SCTP_SEND_FAILED_EVENT};
char buffer[80];
unsigned int i;
int n;
usrsctp_init(LOCAL_UDP_ENCAPS_PORT, NULL, debug_printf_stack);
if(DEBUG != 0)
usrsctp_sysctl_set_sctp_debug_on(0xFFFFFFFF);
else
usrsctp_sysctl_set_sctp_debug_on(0);
usrsctp_sysctl_set_sctp_blackhole(2);
usrsctp_sysctl_set_sctp_no_csum_on_loopback(0);
if ((sock = usrsctp_socket(AF_INET6, SOCK_STREAM, IPPROTO_SCTP, receive_cb, NULL, 0, NULL)) == NULL) {
perror("usrsctp_socket");
}
memset(&event, 0, sizeof(event));
event.se_assoc_id = SCTP_ALL_ASSOC;
event.se_on = 1;
for (i = 0; i < sizeof(event_types)/sizeof(uint16_t); i++) {
event.se_type = event_types[i];
if (usrsctp_setsockopt(sock, IPPROTO_SCTP, SCTP_EVENT, &event, sizeof(event)) < 0) {
perror("setsockopt SCTP_EVENT");
}
}
memset((void *)&addr6, 0, sizeof(struct sockaddr_in6));
addr6.sin6_len = sizeof(struct sockaddr_in6);
addr6.sin6_family = AF_INET6;
addr6.sin6_port = htons(LOCAL_SCTP_PORT);
addr6.sin6_addr = in6addr_any;
if (usrsctp_bind(sock, (struct sockaddr *)&addr6, sizeof(struct sockaddr_in6)) < 0) {
perror("bind");
}
if(LOCAL_UDP_ENCAPS_PORT > 0) {
memset(&encaps, 0, sizeof(struct sctp_udpencaps));
encaps.sue_address.ss_family = AF_INET6;
encaps.sue_port = htons(REMOTE_UDP_ENCAPS_PORT);
if (usrsctp_setsockopt(sock, IPPROTO_SCTP, SCTP_REMOTE_UDP_ENCAPS_PORT, (const void*)&encaps, (socklen_t)sizeof(struct sctp_udpencaps)) < 0) {
perror("setsockopt");
}
}
memset((void *)&addr4, 0, sizeof(struct sockaddr_in));
memset((void *)&addr6, 0, sizeof(struct sockaddr_in6));
addr4.sin_len = sizeof(struct sockaddr_in);
addr6.sin6_len = sizeof(struct sockaddr_in6);
addr4.sin_family = AF_INET;
addr6.sin6_family = AF_INET6;
addr4.sin_port = htons(REMOTE_SCTP_PORT);
addr6.sin6_port = htons(REMOTE_SCTP_PORT);
if (inet_pton(AF_INET6, REMOTE_ADDRESS, &addr6.sin6_addr) == 1) {
if (usrsctp_connect(sock, (struct sockaddr *)&addr6, sizeof(struct sockaddr_in6)) < 0) {
perror("usrsctp_connect");
}
} else if (inet_pton(AF_INET, REMOTE_ADDRESS, &addr4.sin_addr) == 1) {
if (usrsctp_connect(sock, (struct sockaddr *)&addr4, sizeof(struct sockaddr_in)) < 0) {
perror("usrsctp_connect");
}
} else {
printf("Illegal destination address.\n");
}
if ((n = usrsctp_getladdrs(sock, 0, &addrs)) < 0) {
perror("usrsctp_getladdrs");
} else {
addr = addrs;
printf("Local addresses: ");
for (i = 0; i < (unsigned int)n; i++) {
if (i > 0) {
printf("%s", ", ");
}
switch (addr->sa_family) {
case AF_INET: {
struct sockaddr_in *sin;
char buf[INET_ADDRSTRLEN];
const char *name;
sin = (struct sockaddr_in *)addr;
name = inet_ntop(AF_INET, &sin->sin_addr, buf, INET_ADDRSTRLEN);
printf("%s", name);
addr = (struct sockaddr *)((caddr_t)addr + sizeof(struct sockaddr_in));
break;
}
case AF_INET6: {
struct sockaddr_in6 *sin6;
char buf[INET6_ADDRSTRLEN];
const char *name;
sin6 = (struct sockaddr_in6 *)addr;
name = inet_ntop(AF_INET6, &sin6->sin6_addr, buf, INET6_ADDRSTRLEN);
printf("%s", name);
addr = (struct sockaddr *)((caddr_t)addr + sizeof(struct sockaddr_in6));
break;
}
default:
break;
}
addr = (struct sockaddr *)((caddr_t)addr + addr->sa_len);
}
printf(".\n");
usrsctp_freeladdrs(addrs);
}
if ((n = usrsctp_getpaddrs(sock, 0, &addrs)) < 0) {
perror("usrsctp_getpaddrs");
} else {
addr = addrs;
printf("Peer addresses: ");
for (i = 0; i < (unsigned int)n; i++) {
if (i > 0) {
printf("%s", ", ");
}
switch (addr->sa_family) {
case AF_INET: {
struct sockaddr_in *sin;
char buf[INET_ADDRSTRLEN];
const char *name;
sin = (struct sockaddr_in *)addr;
name = inet_ntop(AF_INET, &sin->sin_addr, buf, INET_ADDRSTRLEN);
printf("%s", name);
addr = (struct sockaddr *)((caddr_t)addr + sizeof(struct sockaddr_in));
break;
}
case AF_INET6: {
struct sockaddr_in6 *sin6;
char buf[INET6_ADDRSTRLEN];
const char *name;
sin6 = (struct sockaddr_in6 *)addr;
name = inet_ntop(AF_INET6, &sin6->sin6_addr, buf, INET6_ADDRSTRLEN);
printf("%s", name);
addr = (struct sockaddr *)((caddr_t)addr + sizeof(struct sockaddr_in6));
break;
}
default:
break;
}
addr = (struct sockaddr *)((caddr_t)addr + addr->sa_len);
}
printf(".\n");
usrsctp_freepaddrs(addrs);
}
while ((fgets(buffer, sizeof(buffer), stdin) != NULL) && !done) {
usrsctp_sendv(sock, buffer, strlen(buffer), NULL, 0, NULL, 0, SCTP_SENDV_NOINFO, 0);
}
if (!done) {
if (usrsctp_shutdown(sock, SHUT_WR) < 0) {
perror("usrsctp_shutdown");
}
}
while (!done) {
sleep(1);
}
usrsctp_get_stat(&stat);
printf("Number of packets (sent/received): (%u/%u).\n",
stat.sctps_outpackets, stat.sctps_inpackets);
while (usrsctp_finish() != 0) {
sleep(1);
}
return(0);
}
static int
receive_cb(struct socket *sock, union sctp_sockstore addr, void *data,
size_t datalen, struct sctp_rcvinfo rcv, int flags, void *ulp_info) {
if (data == NULL) {
done = 1;
usrsctp_close(sock);
} else {
if (flags & MSG_NOTIFICATION) {
handle_notification((union sctp_notification *)data, datalen);
} else {
if (write(fileno(stdout), data, datalen) < 0) {
perror("write");
}
}
free(data);
}
return (1);
}
void
debug_set_target(FILE *fp) {
debug_target = fp;
}
void
debug_printf_clean(const char *format, ...) {
char charbuf[1024];
va_list ap;
if (debug_target == NULL) {
debug_target = DEFAULT_TARGET;
}
va_start(ap, format);
if (vsnprintf(charbuf, 1024, format, ap) < 0) {
charbuf[0] = '\0';
}
va_end(ap);
fprintf(debug_target, "%s", charbuf);
fflush(debug_target);
}
void
debug_printf(const char *format, ...) {
va_list ap;
char charbuf[1024];
static struct timeval time_main;
struct timeval time_now;
struct timeval time_delta;
if (debug_target == NULL) {
debug_target = DEFAULT_TARGET;
}
if (time_main.tv_sec == 0 && time_main.tv_usec == 0) {
gettimeofday(&time_main, NULL);
}
gettimeofday(&time_now, NULL);
timersub(&time_now, &time_main, &time_delta);
va_start(ap, format);
if (vsnprintf(charbuf, 1024, format, ap) < 0) {
charbuf[0] = '\0';
}
va_end(ap);
fprintf(debug_target, "[P][%u.%03u] %s", (unsigned int) time_delta.tv_sec, (unsigned int) time_delta.tv_usec / 1000, charbuf);
fflush(debug_target);
}
void
debug_printf_stack(const char *format, ...) {
va_list ap;
char charbuf[1024];
static struct timeval time_main;
struct timeval time_now;
struct timeval time_delta;
if (debug_target == NULL) {
debug_target = DEFAULT_TARGET;
}
if (time_main.tv_sec == 0 && time_main.tv_usec == 0) {
gettimeofday(&time_main, NULL);
}
gettimeofday(&time_now, NULL);
timersub(&time_now, &time_main, &time_delta);
va_start(ap, format);
if (vsnprintf(charbuf, 1024, format, ap) < 0) {
charbuf[0] = '\0';
}
va_end(ap);
fprintf(debug_target, "[S][%u.%03u] %s", (unsigned int) time_delta.tv_sec, (unsigned int) time_delta.tv_usec / 1000, charbuf);
fflush(debug_target);
}
static void
handle_association_change_event(struct sctp_assoc_change *sac) {
unsigned int i, n;
if (debug_target == NULL) {
debug_target = DEFAULT_TARGET;
}
fprintf(debug_target, "Association change ");
switch (sac->sac_state) {
case SCTP_COMM_UP:
fprintf(debug_target, "SCTP_COMM_UP");
break;
case SCTP_COMM_LOST:
fprintf(debug_target, "SCTP_COMM_LOST");
break;
case SCTP_RESTART:
fprintf(debug_target, "SCTP_RESTART");
break;
case SCTP_SHUTDOWN_COMP:
fprintf(debug_target, "SCTP_SHUTDOWN_COMP");
break;
case SCTP_CANT_STR_ASSOC:
fprintf(debug_target, "SCTP_CANT_STR_ASSOC");
break;
default:
fprintf(debug_target, "UNKNOWN");
break;
}
fprintf(debug_target, ", streams (in/out) = (%u/%u)",
sac->sac_inbound_streams, sac->sac_outbound_streams);
n = sac->sac_length - sizeof(struct sctp_assoc_change);
if (((sac->sac_state == SCTP_COMM_UP) ||
(sac->sac_state == SCTP_RESTART)) && (n > 0)) {
fprintf(debug_target, ", supports");
for (i = 0; i < n; i++) {
switch (sac->sac_info[i]) {
case SCTP_ASSOC_SUPPORTS_PR:
fprintf(debug_target, " PR");
break;
case SCTP_ASSOC_SUPPORTS_AUTH:
fprintf(debug_target, " AUTH");
break;
case SCTP_ASSOC_SUPPORTS_ASCONF:
fprintf(debug_target, " ASCONF");
break;
case SCTP_ASSOC_SUPPORTS_MULTIBUF:
fprintf(debug_target, " MULTIBUF");
break;
case SCTP_ASSOC_SUPPORTS_RE_CONFIG:
fprintf(debug_target, " RE-CONFIG");
break;
case SCTP_ASSOC_SUPPORTS_INTERLEAVING:
fprintf(debug_target, " INTERLEAVING");
break;
default:
fprintf(debug_target, " UNKNOWN(0x%02x)", sac->sac_info[i]);
break;
}
}
} else if (((sac->sac_state == SCTP_COMM_LOST) ||
(sac->sac_state == SCTP_CANT_STR_ASSOC)) && (n > 0)) {
fprintf(debug_target, ", ABORT =");
for (i = 0; i < n; i++) {
fprintf(debug_target, " 0x%02x", sac->sac_info[i]);
}
}
fprintf(debug_target, ".\n");
return;
}
static void
handle_peer_address_change_event(struct sctp_paddr_change *spc) {
char addr_buf[INET6_ADDRSTRLEN];
const char *addr;
struct sockaddr_in *sin;
struct sockaddr_in6 *sin6;
struct sockaddr_conn *sconn;
if (debug_target == NULL) {
debug_target = DEFAULT_TARGET;
}
switch (spc->spc_aaddr.ss_family) {
case AF_INET:
sin = (struct sockaddr_in *)&spc->spc_aaddr;
addr = inet_ntop(AF_INET, &sin->sin_addr, addr_buf, INET_ADDRSTRLEN);
break;
case AF_INET6:
sin6 = (struct sockaddr_in6 *)&spc->spc_aaddr;
addr = inet_ntop(AF_INET6, &sin6->sin6_addr, addr_buf, INET6_ADDRSTRLEN);
break;
case AF_CONN:
sconn = (struct sockaddr_conn *)&spc->spc_aaddr;
if (snprintf(addr_buf, INET6_ADDRSTRLEN, "%p", sconn->sconn_addr) < 0) {
addr_buf[0] = '\0';
}
addr = addr_buf;
break;
default:
if (snprintf(addr_buf, INET6_ADDRSTRLEN, "Unknown family %d", spc->spc_aaddr.ss_family) < 0) {
addr_buf[0] = '\0';
}
addr = addr_buf;
break;
}
fprintf(debug_target, "Peer address %s is now ", addr);
switch (spc->spc_state) {
case SCTP_ADDR_AVAILABLE:
fprintf(debug_target, "SCTP_ADDR_AVAILABLE");
break;
case SCTP_ADDR_UNREACHABLE:
fprintf(debug_target, "SCTP_ADDR_UNREACHABLE");
break;
case SCTP_ADDR_REMOVED:
fprintf(debug_target, "SCTP_ADDR_REMOVED");
break;
case SCTP_ADDR_ADDED:
fprintf(debug_target, "SCTP_ADDR_ADDED");
break;
case SCTP_ADDR_MADE_PRIM:
fprintf(debug_target, "SCTP_ADDR_MADE_PRIM");
break;
case SCTP_ADDR_CONFIRMED:
fprintf(debug_target, "SCTP_ADDR_CONFIRMED");
break;
default:
fprintf(debug_target, "UNKNOWN");
break;
}
fprintf(debug_target, " (error = 0x%08x).\n", spc->spc_error);
return;
}
static void
handle_send_failed_event(struct sctp_send_failed_event *ssfe) {
size_t i, n;
if (debug_target == NULL) {
debug_target = DEFAULT_TARGET;
}
if (ssfe->ssfe_flags & SCTP_DATA_UNSENT) {
fprintf(debug_target, "Unsent ");
}
if (ssfe->ssfe_flags & SCTP_DATA_SENT) {
fprintf(debug_target, "Sent ");
}
if (ssfe->ssfe_flags & ~(SCTP_DATA_SENT | SCTP_DATA_UNSENT)) {
fprintf(debug_target, "(flags = %x) ", ssfe->ssfe_flags);
}
fprintf(debug_target, "message with PPID = %u, SID = %u, flags: 0x%04x due to error = 0x%08x",
(uint32_t)ntohl(ssfe->ssfe_info.snd_ppid), ssfe->ssfe_info.snd_sid,
ssfe->ssfe_info.snd_flags, ssfe->ssfe_error);
n = ssfe->ssfe_length - sizeof(struct sctp_send_failed_event);
for (i = 0; i < n; i++) {
fprintf(debug_target, " 0x%02x", ssfe->ssfe_data[i]);
}
fprintf(debug_target, ".\n");
return;
}
static void
handle_adaptation_indication(struct sctp_adaptation_event *sai) {
if (debug_target == NULL) {
debug_target = DEFAULT_TARGET;
}
fprintf(debug_target, "Adaptation indication: %x.\n", sai-> sai_adaptation_ind);
return;
}
static void
handle_shutdown_event(struct sctp_shutdown_event *sse)
{
if (debug_target == NULL) {
debug_target = DEFAULT_TARGET;
}
fprintf(debug_target, "Shutdown event.\n");
/* XXX: notify all channels. */
return;
}
static void
handle_stream_reset_event(struct sctp_stream_reset_event *strrst) {
uint32_t n, i;
if (debug_target == NULL) {
debug_target = DEFAULT_TARGET;
}
n = (strrst->strreset_length - sizeof(struct sctp_stream_reset_event)) / sizeof(uint16_t);
fprintf(debug_target, "Stream reset event: flags = %x, ", strrst->strreset_flags);
if (strrst->strreset_flags & SCTP_STREAM_RESET_INCOMING_SSN) {
if (strrst->strreset_flags & SCTP_STREAM_RESET_OUTGOING_SSN) {
fprintf(debug_target, "incoming/");
}
fprintf(debug_target, "incoming ");
}
if (strrst->strreset_flags & SCTP_STREAM_RESET_OUTGOING_SSN) {
fprintf(debug_target, "outgoing ");
}
fprintf(debug_target, "stream ids = ");
for (i = 0; i < n; i++) {
if (i > 0) {
fprintf(debug_target, ", ");
}
fprintf(debug_target, "%d", strrst->strreset_stream_list[i]);
}
fprintf(debug_target, ".\n");
return;
}
static void
handle_stream_change_event(struct sctp_stream_change_event *strchg) {
if (debug_target == NULL) {
debug_target = DEFAULT_TARGET;
}
fprintf(debug_target, "Stream change event: streams (in/out) = (%u/%u), flags = %x.\n",
strchg->strchange_instrms, strchg->strchange_outstrms, strchg->strchange_flags);
return;
}
static void
handle_remote_error_event(struct sctp_remote_error *sre) {
size_t i, n;
if (debug_target == NULL) {
debug_target = DEFAULT_TARGET;
}
n = sre->sre_length - sizeof(struct sctp_remote_error);
fprintf(debug_target, "Remote Error (error = 0x%04x): ", sre->sre_error);
for (i = 0; i < n; i++) {
fprintf(debug_target, " 0x%02x", sre-> sre_data[i]);
}
fprintf(debug_target, ".\n");
return;
}
void
handle_notification(union sctp_notification *notif, size_t n) {
if (notif->sn_header.sn_length != (uint32_t)n) {
return;
}
if (debug_target == NULL) {
debug_target = DEFAULT_TARGET;
}
fprintf(debug_target, "handle_notification : ");
switch (notif->sn_header.sn_type) {
case SCTP_ASSOC_CHANGE:
fprintf(debug_target, "SCTP_ASSOC_CHANGE\n");
handle_association_change_event(&(notif->sn_assoc_change));
break;
case SCTP_PEER_ADDR_CHANGE:
fprintf(debug_target, "SCTP_PEER_ADDR_CHANGE\n");
handle_peer_address_change_event(&(notif->sn_paddr_change));
break;
case SCTP_REMOTE_ERROR:
fprintf(debug_target, "SCTP_REMOTE_ERROR\n");
handle_remote_error_event(&(notif->sn_remote_error));
break;
case SCTP_SHUTDOWN_EVENT:
fprintf(debug_target, "SCTP_SHUTDOWN_EVENT\n");
handle_shutdown_event(&(notif->sn_shutdown_event));
break;
case SCTP_ADAPTATION_INDICATION:
fprintf(debug_target, "SCTP_ADAPTATION_INDICATION\n");
handle_adaptation_indication(&(notif->sn_adaptation_event));
break;
case SCTP_PARTIAL_DELIVERY_EVENT:
fprintf(debug_target, "SCTP_PARTIAL_DELIVERY_EVENT\n");
break;
case SCTP_AUTHENTICATION_EVENT:
fprintf(debug_target, "SCTP_AUTHENTICATION_EVENT\n");
break;
case SCTP_SENDER_DRY_EVENT:
fprintf(debug_target, "SCTP_SENDER_DRY_EVENT\n");
break;
case SCTP_NOTIFICATIONS_STOPPED_EVENT:
fprintf(debug_target, "SCTP_NOTIFICATIONS_STOPPED_EVENT\n");
break;
case SCTP_SEND_FAILED_EVENT:
fprintf(debug_target, "SCTP_SEND_FAILED_EVENT\n");
handle_send_failed_event(&(notif->sn_send_failed_event));
break;
case SCTP_STREAM_RESET_EVENT:
fprintf(debug_target, "SCTP_STREAM_RESET_EVENT\n");
handle_stream_reset_event(&(notif->sn_strreset_event));
break;
case SCTP_ASSOC_RESET_EVENT:
fprintf(debug_target, "SCTP_ASSOC_RESET_EVENT\n");
break;
case SCTP_STREAM_CHANGE_EVENT:
fprintf(debug_target, "SCTP_STREAM_CHANGE_EVENT\n");
handle_stream_change_event(&(notif->sn_strchange_event));
break;
default:
break;
}
}
// cc -g3 -I /usr/local/include -l usrsctp -L /usr/local/lib -l pthread client.c -o client
// [email protected]
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <sys/types.h>
#include <usrsctp.h>
#define DEBUG 0
#define UDP_ENCAPS_PORT 19818
#define SCTP_LISTEN_PORT 19818
#define BUFFER_SIZE 10240
#define LISTEN_ADDRESS "0.0.0.0"
#define timersub(tvp, uvp, vvp) \
do { \
(vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \
(vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \
if ((vvp)->tv_usec < 0) { \
(vvp)->tv_sec--; \
(vvp)->tv_usec += 1000000; \
} \
} while (0)
void
debug_printf_stack(const char *format, ...);
static int
receive_cb(struct socket *sock, union sctp_sockstore addr, void *data,
size_t datalen, struct sctp_rcvinfo rcv, int flags, void *ulp_info);
int
main(int argc, char **argv) {
struct socket *sock;
struct sockaddr_in addr;
struct sctp_udpencaps encaps;
struct sctp_event event;
uint16_t event_types[] = {SCTP_ASSOC_CHANGE,
SCTP_PEER_ADDR_CHANGE,
SCTP_REMOTE_ERROR,
SCTP_SHUTDOWN_EVENT,
SCTP_ADAPTATION_INDICATION,
SCTP_PARTIAL_DELIVERY_EVENT};
unsigned int i;
struct sctp_assoc_value av;
const int on = 1;
ssize_t n;
int flags;
socklen_t from_len;
char buffer[BUFFER_SIZE];
char name[INET_ADDRSTRLEN];
socklen_t infolen;
struct sctp_rcvinfo rcv_info;
unsigned int infotype;
usrsctp_init(UDP_ENCAPS_PORT, NULL, debug_printf_stack);
if(DEBUG != 0)
usrsctp_sysctl_set_sctp_debug_on(0xFFFFFFFF);
else
usrsctp_sysctl_set_sctp_debug_on(0);
usrsctp_sysctl_set_sctp_blackhole(2);
usrsctp_sysctl_set_sctp_no_csum_on_loopback(0);
if ((sock = usrsctp_socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP, receive_cb, NULL, 0, NULL)) == NULL) {
perror("usrsctp_socket");
}
memset(&av, 0, sizeof(struct sctp_assoc_value));
av.assoc_id = SCTP_ALL_ASSOC;
av.assoc_value = 47;
if (usrsctp_setsockopt(sock, IPPROTO_SCTP, SCTP_CONTEXT, (const void*)&av, (socklen_t)sizeof(struct sctp_assoc_value)) < 0) {
perror("usrsctp_setsockopt SCTP_CONTEXT");
}
if (usrsctp_setsockopt(sock, IPPROTO_SCTP, SCTP_RECVRCVINFO, &on, sizeof(int)) < 0) {
perror("usrsctp_setsockopt SCTP_RECVRCVINFO");
}
if (UDP_ENCAPS_PORT > 0) {
memset(&encaps, 0, sizeof(struct sctp_udpencaps));
encaps.sue_address.ss_family = AF_INET;
encaps.sue_port = UDP_ENCAPS_PORT;
if (usrsctp_setsockopt(sock, IPPROTO_SCTP, SCTP_REMOTE_UDP_ENCAPS_PORT,
(const void*)&encaps, (socklen_t)sizeof(struct sctp_udpencaps)) < 0) {
perror("usrsctp_setsockopt SCTP_REMOTE_UDP_ENCAPS_PORT");
}
}
memset(&event, 0, sizeof(event));
event.se_assoc_id = SCTP_FUTURE_ASSOC;
event.se_on = 1;
for (i = 0; i < (unsigned int)(sizeof(event_types)/sizeof(uint16_t)); i++) {
event.se_type = event_types[i];
if (usrsctp_setsockopt(sock, IPPROTO_SCTP, SCTP_EVENT, &event, sizeof(struct sctp_event)) < 0) {
perror("usrsctp_setsockopt SCTP_EVENT");
}
}
memset((void *)&addr, 0, sizeof(struct sockaddr_in));
addr.sin_len = sizeof(struct sockaddr_in);
addr.sin_family = AF_INET;
addr.sin_port = htons(SCTP_LISTEN_PORT);
inet_aton(LISTEN_ADDRESS, &addr.sin_addr.s_addr);
if (usrsctp_bind(sock, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) < 0) {
perror("usrsctp_bind");
}
if (usrsctp_listen(sock, 1) < 0) {
perror("usrsctp_listen");
}
while (1) {
sleep(1);
}
usrsctp_close(sock);
while (usrsctp_finish() != 0) {
sleep(1);
}
return (0);
}
static int
receive_cb(struct socket *sock, union sctp_sockstore addr, void *data,
size_t datalen, struct sctp_rcvinfo rcv, int flags, void *ulp_info) {
if(flags & MSG_NOTIFICATION)
return 0;
else
printf("[R]: %s\n", (char*)data);
return 0;
}
void
debug_printf_stack(const char *format, ...) {
va_list ap;
char charbuf[1024];
static struct timeval time_main;
struct timeval time_now;
struct timeval time_delta;
if (time_main.tv_sec == 0 && time_main.tv_usec == 0) {
gettimeofday(&time_main, NULL);
}
gettimeofday(&time_now, NULL);
timersub(&time_now, &time_main, &time_delta);
va_start(ap, format);
if (vsnprintf(charbuf, 1024, format, ap) < 0) {
charbuf[0] = '\0';
}
va_end(ap);
printf("[S][%u.%03u] %s", (unsigned int) time_delta.tv_sec, (unsigned int) time_delta.tv_usec / 1000, charbuf);
}
@paigeadelethompson
Copy link
Author

paigeadelethompson commented Jun 24, 2024

This is just meant to be a simple client/server example using the SCTP protocol with the usrsctp library. I found the programs/examples made available in the library frustratingly difficult to sift through and parse out because they don't make a hell of a lot of sense unless you know what's going on.

By default this examples use UDP encapsulation, for native SCTP, set:

server: #define UDP_ENCAPS_PORT 0
client: #define LOCAL_UDP_ENCAPS_PORT 0

and use sudo ./server as well as sudo ./client

for a confirmation, run sudo tcpdump -vvv -n -e -ttt -i lo0 sctp -X

tcpdump: listening on lo0, link-type NULL (BSD loopback), snapshot length 262144 bytes
 00:00:00.000000 AF IPv4 (2), length 172: (tos 0x0, ttl 64, id 60387, offset 0, flags [none], proto SCTP (132), length 168, bad cksum 0 (->8fec)!)
    127.0.0.1.19819 > 127.0.0.1.19818: sctp
	1) [INIT] [init tag: 46196469] [rwnd: 131072] [OS: 10] [MIS: 2048] [init TSN: 1948179020] 
	0x0000:  4500 00a8 ebe3 0000 4084 0000 7f00 0001  E.......@.......
	0x0010:  7f00 0001 4d6b 4d6a 0000 0000 ceef c27c  ....MkMj.......|
	0x0020:  0100 0088 02c0 e6f5 0002 0000 000a 0800  ................
	0x0030:  741e da4c 8000 0004 c000 0004 8008 0009  t..L............
	0x0040:  c00f c180 8200 0000 8002 0024 1093 292a  ...........$..)*
	0x0050:  ae9c 2817 d9fb 0176 cc62 73d3 0eaa ac16  ..(....v.bs.....
	0x0060:  54a9 e26f e46b a7be 2245 3632 8004 0006  T..o.k.."E62....
	0x0070:  0001 0000 8003 0006 80c1 0000 000c 0008  ................
	0x0080:  0005 0006 0005 0008 7f00 0001 0006 0014  ................
	0x0090:  0000 0000 0000 0000 0000 0000 0000 0001  ................
	0x00a0:  0005 0008 c0a8 0180                      ........
 00:00:00.000085 AF IPv4 (2), length 524: (tos 0x0, ttl 64, id 60388, offset 0, flags [none], proto SCTP (132), length 520, bad cksum 0 (->8e8b)!)
    127.0.0.1.19818 > 127.0.0.1.19819: sctp
	1) [INIT ACK] [init tag: 1832780200] [rwnd: 131072] [OS: 10] [MIS: 2048] [init TSN: 2636246802] 
	0x0000:  4500 0208 ebe4 0000 4084 0000 7f00 0001  E.......@.......
	0x0010:  7f00 0001 4d6a 4d6b 02c0 e6f5 9e69 c041  ....MjMk.....i.A
	0x0020:  0200 01e8 6d3e 01a8 0002 0000 000a 0800  ....m>..........
	0x0030:  9d21 ef12 8000 0004 c000 0004 8008 0009  .!..............
	0x0040:  c00f c180 8200 0000 8002 0024 9061 eade  ...........$.a..
	0x0050:  ad85 9f19 1547 11d2 e20b 6694 09ce 43e0  .....G....f...C.
	0x0060:  3c82 cb07 f7fd 8e6d f049 6686 8004 0006  <......m.If.....
	0x0070:  0001 0000 8003 0006 80c1 0000 0005 0008  ................
	0x0080:  7f00 0001 0005 0008 c0a8 0180 0007 017c  ...............|
	0x0090:  4b41 4d45 2d42 5344 2031 2e31 0000 0000  KAME-BSD.1.1....
	0x00a0:  36db 7866 0000 0000 3241 0300 0000 0000  6.xf....2A......
	0x00b0:  60ea 0000 0000 0000 0000 0000 f5e6 c002  `...............
	0x00c0:  6d3e 01a8 7f00 0001 0000 0000 0000 0000  m>..............
	0x00d0:  0000 0000 0500 0000 7f00 0001 0000 0000  ................
	0x00e0:  0000 0000 0000 0000 0500 0000 0000 0000  ................
	0x00f0:  4d6b 4d6a 0100 0000 0101 0100 0000 0000  MkMj............
	0x0100:  0100 0088 02c0 e6f5 0002 0000 000a 0800  ................
	0x0110:  741e da4c 8000 0004 c000 0004 8008 0009  t..L............
	0x0120:  c00f c180 8200 0000 8002 0024 1093 292a  ...........$..)*
	0x0130:  ae9c 2817 d9fb 0176 cc62 73d3 0eaa ac16  ..(....v.bs.....
	0x0140:  54a9 e26f e46b a7be 2245 3632 8004 0006  T..o.k.."E62....
	0x0150:  0001 0000 8003 0006 80c1 0000 000c 0008  ................
	0x0160:  0005 0006 0005 0008 7f00 0001 0006 0014  ................
	0x0170:  0000 0000 0000 0000 0000 0000 0000 0001  ................
	0x0180:  0005 0008 c0a8 0180 0200 01e8 6d3e 01a8  ............m>..
	0x0190:  0002 0000 000a 0800 9d21 ef12 8000 0004  .........!......
	0x01a0:  c000 0004 8008 0009 c00f c180 8200 0000  ................
	0x01b0:  8002 0024 9061 eade ad85 9f19 1547 11d2  ...$.a.......G..
	0x01c0:  e20b 6694 09ce 43e0 3c82 cb07 f7fd 8e6d  ..f...C.<......m
	0x01d0:  f049 6686 8004 0006 0001 0000 8003 0006  .If.............
	0x01e0:  80c1 0000 0005 0008 7f00 0001 0005 0008  ................
	0x01f0:  c0a8 0180 0eae b12a 5055 6698 985d ba01  .......*PUf..]..
	0x0200:  b676 0f46 8113 c0da                      .v.F....
 00:00:00.000087 AF IPv4 (2), length 416: (tos 0x0, ttl 64, id 1, offset 0, flags [none], proto SCTP (132), length 412, bad cksum 0 (->7adb)!)
    127.0.0.1.19819 > 127.0.0.1.19818: sctp
	1) [COOKIE ECHO] 
	0x0000:  4500 019c 0001 0000 4084 0000 7f00 0001  E.......@.......
	0x0010:  7f00 0001 4d6b 4d6a 6d3e 01a8 70d2 a263  ....MkMjm>..p..c
	0x0020:  0a00 017c 4b41 4d45 2d42 5344 2031 2e31  ...|KAME-BSD.1.1
	0x0030:  0000 0000 36db 7866 0000 0000 3241 0300  ....6.xf....2A..
	0x0040:  0000 0000 60ea 0000 0000 0000 0000 0000  ....`...........
	0x0050:  f5e6 c002 6d3e 01a8 7f00 0001 0000 0000  ....m>..........
	0x0060:  0000 0000 0000 0000 0500 0000 7f00 0001  ................
	0x0070:  0000 0000 0000 0000 0000 0000 0500 0000  ................
	0x0080:  0000 0000 4d6b 4d6a 0100 0000 0101 0100  ....MkMj........
	0x0090:  0000 0000 0100 0088 02c0 e6f5 0002 0000  ................
	0x00a0:  000a 0800 741e da4c 8000 0004 c000 0004  ....t..L........
	0x00b0:  8008 0009 c00f c180 8200 0000 8002 0024  ...............$
	0x00c0:  1093 292a ae9c 2817 d9fb 0176 cc62 73d3  ..)*..(....v.bs.
	0x00d0:  0eaa ac16 54a9 e26f e46b a7be 2245 3632  ....T..o.k.."E62
	0x00e0:  8004 0006 0001 0000 8003 0006 80c1 0000  ................
	0x00f0:  000c 0008 0005 0006 0005 0008 7f00 0001  ................
	0x0100:  0006 0014 0000 0000 0000 0000 0000 0000  ................
	0x0110:  0000 0001 0005 0008 c0a8 0180 0200 01e8  ................
	0x0120:  6d3e 01a8 0002 0000 000a 0800 9d21 ef12  m>...........!..
	0x0130:  8000 0004 c000 0004 8008 0009 c00f c180  ................
	0x0140:  8200 0000 8002 0024 9061 eade ad85 9f19  .......$.a......
	0x0150:  1547 11d2 e20b 6694 09ce 43e0 3c82 cb07  .G....f...C.<...
	0x0160:  f7fd 8e6d f049 6686 8004 0006 0001 0000  ...m.If.........
	0x0170:  8003 0006 80c1 0000 0005 0008 7f00 0001  ................
	0x0180:  0005 0008 c0a8 0180 0eae b12a 5055 6698  ...........*PUf.
	0x0190:  985d ba01 b676 0f46 8113 c0da            .]...v.F....

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment