blob: 1296d0f474ec8d775062afdf8584407202374b1e [file] [log] [blame]
James Kuszmaul4cb043c2021-01-17 11:25:51 -08001/*
2 * Copyright (C) 2011-2013 Michael Tuexen
3 *
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the project nor the names of its contributors
15 * may be used to endorse or promote products derived from this software
16 * without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31#ifdef _WIN32
32#define _CRT_SECURE_NO_WARNINGS
33#endif
34#include <stdio.h>
35#include <stdlib.h>
36#include <string.h>
37#include <stdarg.h>
38#include <sys/types.h>
39#ifndef _WIN32
40#include <sys/socket.h>
41#include <netinet/in.h>
42#include <arpa/inet.h>
43#include <errno.h>
44#include <pthread.h>
45#include <unistd.h>
46#else
47#include <winsock2.h>
48#include <ws2tcpip.h>
49#endif
50#include <usrsctp.h>
51
52#define MAX_PACKET_SIZE (1<<16)
53#define LINE_LENGTH (1<<20)
54#define DISCARD_PPID 39
55
56#ifdef _WIN32
57static DWORD WINAPI
58#else
59static void *
60#endif
61handle_packets(void *arg)
62{
63#ifdef _WIN32
64 SOCKET *fdp;
65#else
66 int *fdp;
67#endif
68 char *dump_buffer;
69 struct sctp_common_header *hdr;
70 ssize_t length;
71 char buffer[MAX_PACKET_SIZE];
72 uint32_t received_crc32c, computed_crc32c;
73
74#ifdef _WIN32
75 fdp = (SOCKET *)arg;
76#else
77 fdp = (int *)arg;
78#endif
79 for (;;) {
80#if defined(__NetBSD__)
81 pthread_testcancel();
82#endif
83 length = recv(*fdp, buffer, MAX_PACKET_SIZE, 0);
84 if (length > 0) {
85 if ((dump_buffer = usrsctp_dumppacket(buffer, (size_t)length, SCTP_DUMP_INBOUND)) != NULL) {
86 //fprintf(stderr, "%s", dump_buffer);
87 usrsctp_freedumpbuffer(dump_buffer);
88 }
89 if ((size_t)length >= sizeof(struct sctp_common_header)) {
90 hdr = (struct sctp_common_header *)buffer;
91 received_crc32c = hdr->crc32c;
92 hdr->crc32c = htonl(0);
93 computed_crc32c = usrsctp_crc32c(buffer, (size_t)length);
94 hdr->crc32c = received_crc32c;
95 if (received_crc32c == computed_crc32c) {
96 usrsctp_conninput(fdp, buffer, (size_t)length, 0);
97 } else {
98 fprintf(stderr, "Wrong CRC32c: expected %08x received %08x\n",
99 ntohl(computed_crc32c), ntohl(received_crc32c));
100 }
101 } else {
102 fprintf(stderr, "Packet too short: length %zu", (size_t)length);
103 }
104 }
105 }
106#ifdef _WIN32
107 return 0;
108#else
109 return (NULL);
110#endif
111}
112
113static int
114conn_output(void *addr, void *buffer, size_t length, uint8_t tos, uint8_t set_df)
115{
116 char *dump_buffer;
117 struct sctp_common_header *hdr;
118#ifdef _WIN32
119 SOCKET *fdp;
120#else
121 int *fdp;
122#endif
123
124#ifdef _WIN32
125 fdp = (SOCKET *)addr;
126#else
127 fdp = (int *)addr;
128#endif
129 if (length >= sizeof(struct sctp_common_header)) {
130 hdr = (struct sctp_common_header *)buffer;
131 hdr->crc32c = usrsctp_crc32c(buffer, (size_t)length);
132 }
133 if ((dump_buffer = usrsctp_dumppacket(buffer, length, SCTP_DUMP_OUTBOUND)) != NULL) {
134 //fprintf(stderr, "%s", dump_buffer);
135 usrsctp_freedumpbuffer(dump_buffer);
136 }
137#ifdef _WIN32
138 if (send(*fdp, buffer, (int)length, 0) == SOCKET_ERROR) {
139 return (WSAGetLastError());
140#else
141 if (send(*fdp, buffer, length, 0) < 0) {
142 return (errno);
143#endif
144 } else {
145 return (0);
146 }
147}
148
149static int
150receive_cb(struct socket *sock, union sctp_sockstore addr, void *data,
151 size_t datalen, struct sctp_rcvinfo rcv, int flags, void *ulp_info)
152{
153 printf("Message %p received on sock = %p.\n", data, (void *)sock);
154 if (data) {
155 if ((flags & MSG_NOTIFICATION) == 0) {
156 printf("Messsage of length %d received via %p:%u on stream %d with SSN %u and TSN %u, PPID %u, context %u, flags %x.\n",
157 (int)datalen,
158 addr.sconn.sconn_addr,
159 ntohs(addr.sconn.sconn_port),
160 rcv.rcv_sid,
161 rcv.rcv_ssn,
162 rcv.rcv_tsn,
163 ntohl(rcv.rcv_ppid),
164 rcv.rcv_context,
165 flags);
166 }
167 free(data);
168 } else {
169 usrsctp_deregister_address(ulp_info);
170 usrsctp_close(sock);
171 }
172 return (1);
173}
174
175#if 0
176static void
177print_addresses(struct socket *sock)
178{
179 int i, n;
180 struct sockaddr *addrs, *addr;
181
182 n = usrsctp_getladdrs(sock, 0, &addrs);
183 addr = addrs;
184 for (i = 0; i < n; i++) {
185 switch (addr->sa_family) {
186 case AF_INET:
187 {
188 struct sockaddr_in *sin;
189 char buf[INET_ADDRSTRLEN];
190 const char *name;
191
192 sin = (struct sockaddr_in *)addr;
193 name = inet_ntop(AF_INET, &sin->sin_addr, buf, INET_ADDRSTRLEN);
194 printf("%s:%d", name, ntohs(sin->sin_port));
195 break;
196 }
197 case AF_INET6:
198 {
199 struct sockaddr_in6 *sin6;
200 char buf[INET6_ADDRSTRLEN];
201 const char *name;
202
203 sin6 = (struct sockaddr_in6 *)addr;
204 name = inet_ntop(AF_INET6, &sin6->sin6_addr, buf, INET6_ADDRSTRLEN);
205 printf("%s:%d", name, ntohs(sin6->sin6_port));
206 break;
207 }
208 case AF_CONN:
209 {
210 struct sockaddr_conn *sconn;
211
212 sconn = (struct sockaddr_conn *)addr;
213 printf("%p:%d", sconn->sconn_addr, ntohs(sconn->sconn_port));
214 break;
215 }
216 default:
217 printf("Unknown family: %d", addr->sa_family);
218 break;
219 }
220 addr = (struct sockaddr *)((caddr_t)addr + addr->sa_len);
221 if (i != n - 1) {
222 printf(",");
223 }
224 }
225 if (n > 0) {
226 usrsctp_freeladdrs(addrs);
227 }
228 printf("<->");
229 n = usrsctp_getpaddrs(sock, 0, &addrs);
230 addr = addrs;
231 for (i = 0; i < n; i++) {
232 switch (addr->sa_family) {
233 case AF_INET:
234 {
235 struct sockaddr_in *sin;
236 char buf[INET_ADDRSTRLEN];
237 const char *name;
238
239 sin = (struct sockaddr_in *)addr;
240 name = inet_ntop(AF_INET, &sin->sin_addr, buf, INET_ADDRSTRLEN);
241 printf("%s:%d", name, ntohs(sin->sin_port));
242 break;
243 }
244 case AF_INET6:
245 {
246 struct sockaddr_in6 *sin6;
247 char buf[INET6_ADDRSTRLEN];
248 const char *name;
249
250 sin6 = (struct sockaddr_in6 *)addr;
251 name = inet_ntop(AF_INET6, &sin6->sin6_addr, buf, INET6_ADDRSTRLEN);
252 printf("%s:%d", name, ntohs(sin6->sin6_port));
253 break;
254 }
255 case AF_CONN:
256 {
257 struct sockaddr_conn *sconn;
258
259 sconn = (struct sockaddr_conn *)addr;
260 printf("%p:%d", sconn->sconn_addr, ntohs(sconn->sconn_port));
261 break;
262 }
263 default:
264 printf("Unknown family: %d", addr->sa_family);
265 break;
266 }
267 addr = (struct sockaddr *)((caddr_t)addr + addr->sa_len);
268 if (i != n - 1) {
269 printf(",");
270 }
271 }
272 if (n > 0) {
273 usrsctp_freepaddrs(addrs);
274 }
275 printf("\n");
276}
277#endif
278
279void
280debug_printf(const char *format, ...)
281{
282 va_list ap;
283
284 va_start(ap, format);
285 vprintf(format, ap);
286 va_end(ap);
287}
288
289int
290main(void)
291{
292 struct sockaddr_in sin_s, sin_c;
293 struct sockaddr_conn sconn;
294#ifdef _WIN32
295 SOCKET fd_c, fd_s;
296#else
297 int fd_c, fd_s;
298#endif
299 struct socket *s_c, *s_s, *s_l;
300#ifdef _WIN32
301 HANDLE tid_c, tid_s;
302#else
303 pthread_t tid_c, tid_s;
304#endif
305 int cur_buf_size, snd_buf_size, rcv_buf_size;
306 socklen_t opt_len;
307 struct sctp_sndinfo sndinfo;
308 char *line;
309#ifdef _WIN32
310 WSADATA wsaData;
311#endif
312
313#ifdef _WIN32
314 if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0) {
315 printf("WSAStartup failed\n");
316 exit (EXIT_FAILURE);
317 }
318#endif
319 usrsctp_init(0, conn_output, debug_printf);
320 usrsctp_enable_crc32c_offload();
321 /* set up a connected UDP socket */
322#ifdef _WIN32
323 if ((fd_c = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET) {
324 printf("socket() failed with error: %d\n", WSAGetLastError());
325 exit(EXIT_FAILURE);
326 }
327 if ((fd_s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET) {
328 printf("socket() failed with error: %d\n", WSAGetLastError());
329 exit(EXIT_FAILURE);
330 }
331#else
332 if ((fd_c = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
333 perror("socket");
334 exit(EXIT_FAILURE);
335 }
336 if ((fd_s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
337 perror("socket");
338 exit(EXIT_FAILURE);
339 }
340#endif
341 memset(&sin_c, 0, sizeof(struct sockaddr_in));
342 sin_c.sin_family = AF_INET;
343#ifdef HAVE_SIN_LEN
344 sin_c.sin_len = sizeof(struct sockaddr_in);
345#endif
346 sin_c.sin_port = htons(9899);
347 sin_c.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
348 memset(&sin_s, 0, sizeof(struct sockaddr_in));
349 sin_s.sin_family = AF_INET;
350#ifdef HAVE_SIN_LEN
351 sin_s.sin_len = sizeof(struct sockaddr_in);
352#endif
353 sin_s.sin_port = htons(9901);
354 sin_s.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
355#ifdef _WIN32
356 if (bind(fd_c, (struct sockaddr *)&sin_c, sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
357 printf("bind() failed with error: %d\n", WSAGetLastError());
358 exit(EXIT_FAILURE);
359 }
360 if (bind(fd_s, (struct sockaddr *)&sin_s, sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
361 printf("bind() failed with error: %d\n", WSAGetLastError());
362 exit(EXIT_FAILURE);
363 }
364#else
365 if (bind(fd_c, (struct sockaddr *)&sin_c, sizeof(struct sockaddr_in)) < 0) {
366 perror("bind");
367 exit(EXIT_FAILURE);
368 }
369 if (bind(fd_s, (struct sockaddr *)&sin_s, sizeof(struct sockaddr_in)) < 0) {
370 perror("bind");
371 exit(EXIT_FAILURE);
372 }
373#endif
374#ifdef _WIN32
375 if (connect(fd_c, (struct sockaddr *)&sin_s, sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
376 printf("connect() failed with error: %d\n", WSAGetLastError());
377 exit(EXIT_FAILURE);
378 }
379 if (connect(fd_s, (struct sockaddr *)&sin_c, sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
380 printf("connect() failed with error: %d\n", WSAGetLastError());
381 exit(EXIT_FAILURE);
382 }
383#else
384 if (connect(fd_c, (struct sockaddr *)&sin_s, sizeof(struct sockaddr_in)) < 0) {
385 perror("connect");
386 exit(EXIT_FAILURE);
387 }
388 if (connect(fd_s, (struct sockaddr *)&sin_c, sizeof(struct sockaddr_in)) < 0) {
389 perror("connect");
390 exit(EXIT_FAILURE);
391 }
392#endif
393#ifdef _WIN32
394 tid_c = CreateThread(NULL, 0, &handle_packets, (void *)&fd_c, 0, NULL);
395 tid_s = CreateThread(NULL, 0, &handle_packets, (void *)&fd_s, 0, NULL);
396#else
397 if (pthread_create(&tid_c, NULL, &handle_packets, (void *)&fd_c)) {
398 perror("pthread_create tid_c");
399 exit(EXIT_FAILURE);
400 }
401
402 if (pthread_create(&tid_s, NULL, &handle_packets, (void *)&fd_s)) {
403 perror("pthread_create tid_s");
404 exit(EXIT_FAILURE);
405 };
406#endif
407#ifdef SCTP_DEBUG
408 usrsctp_sysctl_set_sctp_debug_on(SCTP_DEBUG_ALL);
409#endif
410 usrsctp_sysctl_set_sctp_ecn_enable(0);
411 usrsctp_register_address((void *)&fd_c);
412 usrsctp_register_address((void *)&fd_s);
413 if ((s_c = usrsctp_socket(AF_CONN, SOCK_STREAM, IPPROTO_SCTP, receive_cb, NULL, 0, &fd_c)) == NULL) {
414 perror("usrsctp_socket");
415 exit(EXIT_FAILURE);
416 }
417 opt_len = (socklen_t)sizeof(int);
418 cur_buf_size = 0;
419 if (usrsctp_getsockopt(s_c, SOL_SOCKET, SO_SNDBUF, &cur_buf_size, &opt_len) < 0) {
420 perror("usrsctp_getsockopt");
421 exit(EXIT_FAILURE);
422 }
423 printf("Change send socket buffer size from %d ", cur_buf_size);
424 snd_buf_size = 1<<20; /* 1 MB */
425 if (usrsctp_setsockopt(s_c, SOL_SOCKET, SO_SNDBUF, &snd_buf_size, sizeof(int)) < 0) {
426 perror("usrsctp_setsockopt");
427 exit(EXIT_FAILURE);
428 }
429 opt_len = (socklen_t)sizeof(int);
430 cur_buf_size = 0;
431 if (usrsctp_getsockopt(s_c, SOL_SOCKET, SO_SNDBUF, &cur_buf_size, &opt_len) < 0) {
432 perror("usrsctp_getsockopt");
433 exit(EXIT_FAILURE);
434 }
435 printf("to %d.\n", cur_buf_size);
436 if ((s_l = usrsctp_socket(AF_CONN, SOCK_STREAM, IPPROTO_SCTP, receive_cb, NULL, 0, &fd_s)) == NULL) {
437 perror("usrsctp_socket");
438 exit(EXIT_FAILURE);
439 }
440 opt_len = (socklen_t)sizeof(int);
441 cur_buf_size = 0;
442 if (usrsctp_getsockopt(s_l, SOL_SOCKET, SO_RCVBUF, &cur_buf_size, &opt_len) < 0) {
443 perror("usrsctp_getsockopt");
444 exit(EXIT_FAILURE);
445 }
446 printf("Change receive socket buffer size from %d ", cur_buf_size);
447 rcv_buf_size = 1<<16; /* 64 KB */
448 if (usrsctp_setsockopt(s_l, SOL_SOCKET, SO_RCVBUF, &rcv_buf_size, sizeof(int)) < 0) {
449 perror("usrsctp_setsockopt");
450 exit(EXIT_FAILURE);
451 }
452 opt_len = (socklen_t)sizeof(int);
453 cur_buf_size = 0;
454 if (usrsctp_getsockopt(s_l, SOL_SOCKET, SO_RCVBUF, &cur_buf_size, &opt_len) < 0) {
455 perror("usrsctp_getsockopt");
456 exit(EXIT_FAILURE);
457 }
458 printf("to %d.\n", cur_buf_size);
459 /* Bind the client side. */
460 memset(&sconn, 0, sizeof(struct sockaddr_conn));
461 sconn.sconn_family = AF_CONN;
462#ifdef HAVE_SCONN_LEN
463 sconn.sconn_len = sizeof(struct sockaddr_conn);
464#endif
465 sconn.sconn_port = htons(5001);
466 sconn.sconn_addr = &fd_c;
467 if (usrsctp_bind(s_c, (struct sockaddr *)&sconn, sizeof(struct sockaddr_conn)) < 0) {
468 perror("usrsctp_bind");
469 exit(EXIT_FAILURE);
470 }
471 /* Bind the server side. */
472 memset(&sconn, 0, sizeof(struct sockaddr_conn));
473 sconn.sconn_family = AF_CONN;
474#ifdef HAVE_SCONN_LEN
475 sconn.sconn_len = sizeof(struct sockaddr_conn);
476#endif
477 sconn.sconn_port = htons(5001);
478 sconn.sconn_addr = &fd_s;
479 if (usrsctp_bind(s_l, (struct sockaddr *)&sconn, sizeof(struct sockaddr_conn)) < 0) {
480 perror("usrsctp_bind");
481 exit(EXIT_FAILURE);
482 }
483 /* Make server side passive... */
484 if (usrsctp_listen(s_l, 1) < 0) {
485 perror("usrsctp_listen");
486 exit(EXIT_FAILURE);
487 }
488 /* Initiate the handshake */
489 memset(&sconn, 0, sizeof(struct sockaddr_conn));
490 sconn.sconn_family = AF_CONN;
491#ifdef HAVE_SCONN_LEN
492 sconn.sconn_len = sizeof(struct sockaddr_conn);
493#endif
494 sconn.sconn_port = htons(5001);
495 sconn.sconn_addr = &fd_c;
496 if (usrsctp_connect(s_c, (struct sockaddr *)&sconn, sizeof(struct sockaddr_conn)) < 0) {
497 perror("usrsctp_connect");
498 exit(EXIT_FAILURE);
499 }
500 if ((s_s = usrsctp_accept(s_l, NULL, NULL)) == NULL) {
501 perror("usrsctp_accept");
502 exit(EXIT_FAILURE);
503 }
504 usrsctp_close(s_l);
505 if ((line = malloc(LINE_LENGTH)) == NULL) {
506 exit(EXIT_FAILURE);
507 }
508 memset(line, 'A', LINE_LENGTH);
509 sndinfo.snd_sid = 1;
510 sndinfo.snd_flags = 0;
511 sndinfo.snd_ppid = htonl(DISCARD_PPID);
512 sndinfo.snd_context = 0;
513 sndinfo.snd_assoc_id = 0;
514 /* Send a 1 MB message */
515 if (usrsctp_sendv(s_c, line, LINE_LENGTH, NULL, 0, (void *)&sndinfo,
516 (socklen_t)sizeof(struct sctp_sndinfo), SCTP_SENDV_SNDINFO, 0) < 0) {
517 perror("usrsctp_sendv");
518 exit(EXIT_FAILURE);
519 }
520 free(line);
521 usrsctp_shutdown(s_c, SHUT_WR);
522
523 while (usrsctp_finish() != 0) {
524#ifdef _WIN32
525 Sleep(1000);
526#else
527 sleep(1);
528#endif
529 }
530#ifdef _WIN32
531 TerminateThread(tid_c, 0);
532 WaitForSingleObject(tid_c, INFINITE);
533 TerminateThread(tid_s, 0);
534 WaitForSingleObject(tid_s, INFINITE);
535 if (closesocket(fd_c) == SOCKET_ERROR) {
536 printf("closesocket() failed with error: %d\n", WSAGetLastError());
537 exit(EXIT_FAILURE);
538 }
539 if (closesocket(fd_s) == SOCKET_ERROR) {
540 printf("closesocket() failed with error: %d\n", WSAGetLastError());
541 exit(EXIT_FAILURE);
542 }
543 WSACleanup();
544#else
545 pthread_cancel(tid_c);
546 pthread_join(tid_c, NULL);
547 pthread_cancel(tid_s);
548 pthread_join(tid_s, NULL);
549 if (close(fd_c) < 0) {
550 perror("close");
551 exit(EXIT_FAILURE);
552 }
553 if (close(fd_s) < 0) {
554 perror("close");
555 exit(EXIT_FAILURE);
556 }
557#endif
558 return (0);
559}