1 /*
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 #include "programs_helper.h"
52
53 #define MAX_PACKET_SIZE (1<<16)
54 #define LINE_LENGTH (1<<20)
55 #define DISCARD_PPID 39
56
57 #ifdef _WIN32
58 static DWORD WINAPI
59 #else
60 static void *
61 #endif
handle_packets(void * arg)62 handle_packets(void *arg)
63 {
64 #ifdef _WIN32
65 SOCKET *fdp;
66 #else
67 int *fdp;
68 #endif
69 char *dump_buffer;
70 struct sctp_common_header *hdr;
71 ssize_t length;
72 char buffer[MAX_PACKET_SIZE];
73 uint32_t received_crc32c, computed_crc32c;
74
75 #ifdef _WIN32
76 fdp = (SOCKET *)arg;
77 #else
78 fdp = (int *)arg;
79 #endif
80 for (;;) {
81 #if defined(__NetBSD__)
82 pthread_testcancel();
83 #endif
84 length = recv(*fdp, buffer, MAX_PACKET_SIZE, 0);
85 if (length > 0) {
86 if ((dump_buffer = usrsctp_dumppacket(buffer, (size_t)length, SCTP_DUMP_INBOUND)) != NULL) {
87 /* fprintf(stderr, "%s", dump_buffer); */
88 usrsctp_freedumpbuffer(dump_buffer);
89 }
90 if ((size_t)length >= sizeof(struct sctp_common_header)) {
91 hdr = (struct sctp_common_header *)buffer;
92 received_crc32c = hdr->crc32c;
93 hdr->crc32c = htonl(0);
94 computed_crc32c = usrsctp_crc32c(buffer, (size_t)length);
95 hdr->crc32c = received_crc32c;
96 if (received_crc32c == computed_crc32c) {
97 usrsctp_conninput(fdp, buffer, (size_t)length, 0);
98 } else {
99 fprintf(stderr, "Wrong CRC32c: expected %08x received %08x\n",
100 ntohl(computed_crc32c), ntohl(received_crc32c));
101 }
102 } else {
103 fprintf(stderr, "Packet too short: length %zu", (size_t)length);
104 }
105 }
106 }
107 #ifdef _WIN32
108 return 0;
109 #else
110 return (NULL);
111 #endif
112 }
113
114 static int
conn_output(void * addr,void * buffer,size_t length,uint8_t tos,uint8_t set_df)115 conn_output(void *addr, void *buffer, size_t length, uint8_t tos, uint8_t set_df)
116 {
117 char *dump_buffer;
118 struct sctp_common_header *hdr;
119 #ifdef _WIN32
120 SOCKET *fdp;
121 #else
122 int *fdp;
123 #endif
124
125 #ifdef _WIN32
126 fdp = (SOCKET *)addr;
127 #else
128 fdp = (int *)addr;
129 #endif
130 if (length >= sizeof(struct sctp_common_header)) {
131 hdr = (struct sctp_common_header *)buffer;
132 hdr->crc32c = usrsctp_crc32c(buffer, (size_t)length);
133 }
134 if ((dump_buffer = usrsctp_dumppacket(buffer, length, SCTP_DUMP_OUTBOUND)) != NULL) {
135 /* fprintf(stderr, "%s", dump_buffer); */
136 usrsctp_freedumpbuffer(dump_buffer);
137 }
138 #ifdef _WIN32
139 if (send(*fdp, buffer, (int)length, 0) == SOCKET_ERROR) {
140 return (WSAGetLastError());
141 #else
142 if (send(*fdp, buffer, length, 0) < 0) {
143 return (errno);
144 #endif
145 } else {
146 return (0);
147 }
148 }
149
150 static int
151 receive_cb(struct socket *sock, union sctp_sockstore addr, void *data,
152 size_t datalen, struct sctp_rcvinfo rcv, int flags, void *ulp_info)
153 {
154 printf("Message %p received on sock = %p.\n", data, (void *)sock);
155 if (data) {
156 if ((flags & MSG_NOTIFICATION) == 0) {
157 printf("Message of length %d received via %p:%u on stream %u with SSN %u and TSN %u, PPID %u, context %u, flags %x.\n",
158 (int)datalen,
159 addr.sconn.sconn_addr,
160 ntohs(addr.sconn.sconn_port),
161 rcv.rcv_sid,
162 rcv.rcv_ssn,
163 rcv.rcv_tsn,
164 ntohl(rcv.rcv_ppid),
165 rcv.rcv_context,
166 flags);
167 }
168 free(data);
169 } else {
170 usrsctp_deregister_address(ulp_info);
171 usrsctp_close(sock);
172 }
173 return (1);
174 }
175
176 #if 0
177 static void
178 print_addresses(struct socket *sock)
179 {
180 int i, n;
181 struct sockaddr *addrs, *addr;
182
183 n = usrsctp_getladdrs(sock, 0, &addrs);
184 addr = addrs;
185 for (i = 0; i < n; i++) {
186 switch (addr->sa_family) {
187 case AF_INET:
188 {
189 struct sockaddr_in *sin;
190 char buf[INET_ADDRSTRLEN];
191 const char *name;
192
193 sin = (struct sockaddr_in *)addr;
194 name = inet_ntop(AF_INET, &sin->sin_addr, buf, INET_ADDRSTRLEN);
195 printf("%s:%d", name, ntohs(sin->sin_port));
196 break;
197 }
198 case AF_INET6:
199 {
200 struct sockaddr_in6 *sin6;
201 char buf[INET6_ADDRSTRLEN];
202 const char *name;
203
204 sin6 = (struct sockaddr_in6 *)addr;
205 name = inet_ntop(AF_INET6, &sin6->sin6_addr, buf, INET6_ADDRSTRLEN);
206 printf("%s:%d", name, ntohs(sin6->sin6_port));
207 break;
208 }
209 case AF_CONN:
210 {
211 struct sockaddr_conn *sconn;
212
213 sconn = (struct sockaddr_conn *)addr;
214 printf("%p:%d", sconn->sconn_addr, ntohs(sconn->sconn_port));
215 break;
216 }
217 default:
218 printf("Unknown family: %d", addr->sa_family);
219 break;
220 }
221 addr = (struct sockaddr *)((caddr_t)addr + addr->sa_len);
222 if (i != n - 1) {
223 printf(",");
224 }
225 }
226 if (n > 0) {
227 usrsctp_freeladdrs(addrs);
228 }
229 printf("<->");
230 n = usrsctp_getpaddrs(sock, 0, &addrs);
231 addr = addrs;
232 for (i = 0; i < n; i++) {
233 switch (addr->sa_family) {
234 case AF_INET:
235 {
236 struct sockaddr_in *sin;
237 char buf[INET_ADDRSTRLEN];
238 const char *name;
239
240 sin = (struct sockaddr_in *)addr;
241 name = inet_ntop(AF_INET, &sin->sin_addr, buf, INET_ADDRSTRLEN);
242 printf("%s:%d", name, ntohs(sin->sin_port));
243 break;
244 }
245 case AF_INET6:
246 {
247 struct sockaddr_in6 *sin6;
248 char buf[INET6_ADDRSTRLEN];
249 const char *name;
250
251 sin6 = (struct sockaddr_in6 *)addr;
252 name = inet_ntop(AF_INET6, &sin6->sin6_addr, buf, INET6_ADDRSTRLEN);
253 printf("%s:%d", name, ntohs(sin6->sin6_port));
254 break;
255 }
256 case AF_CONN:
257 {
258 struct sockaddr_conn *sconn;
259
260 sconn = (struct sockaddr_conn *)addr;
261 printf("%p:%d", sconn->sconn_addr, ntohs(sconn->sconn_port));
262 break;
263 }
264 default:
265 printf("Unknown family: %d", addr->sa_family);
266 break;
267 }
268 addr = (struct sockaddr *)((caddr_t)addr + addr->sa_len);
269 if (i != n - 1) {
270 printf(",");
271 }
272 }
273 if (n > 0) {
274 usrsctp_freepaddrs(addrs);
275 }
276 printf("\n");
277 }
278 #endif
279
280 int
281 main(int argc, char *argv[])
282 {
283 struct sockaddr_in sin_s, sin_c;
284 struct sockaddr_conn sconn;
285 #ifdef _WIN32
286 SOCKET fd_c, fd_s;
287 #else
288 int fd_c, fd_s, rc;
289 #endif
290 struct socket *s_c, *s_s, *s_l;
291 #ifdef _WIN32
292 HANDLE tid_c, tid_s;
293 #else
294 pthread_t tid_c, tid_s;
295 #endif
296 int cur_buf_size, snd_buf_size, rcv_buf_size;
297 socklen_t opt_len;
298 struct sctp_sndinfo sndinfo;
299 char *line;
300 #ifdef _WIN32
301 WSADATA wsaData;
302 #endif
303 uint16_t client_port = 9900;
304 uint16_t server_port = 9901;
305
306 if (argc == 3) {
307 client_port = atoi(argv[1]);
308 server_port = atoi(argv[2]);
309 }
310
311 #ifdef _WIN32
312 if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0) {
313 fprintf(stderr, "WSAStartup failed\n");
314 exit (EXIT_FAILURE);
315 }
316 #endif
317 usrsctp_init(0, conn_output, debug_printf_stack);
318 usrsctp_enable_crc32c_offload();
319 /* set up a connected UDP socket */
320 #ifdef _WIN32
321 if ((fd_c = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET) {
322 fprintf(stderr, "socket() failed with error: %d\n", WSAGetLastError());
323 exit(EXIT_FAILURE);
324 }
325 if ((fd_s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET) {
326 fprintf(stderr, "socket() failed with error: %d\n", WSAGetLastError());
327 exit(EXIT_FAILURE);
328 }
329 #else
330 if ((fd_c = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
331 perror("socket");
332 exit(EXIT_FAILURE);
333 }
334 if ((fd_s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
335 perror("socket");
336 exit(EXIT_FAILURE);
337 }
338 #endif
339 memset(&sin_c, 0, sizeof(struct sockaddr_in));
340 sin_c.sin_family = AF_INET;
341 #ifdef HAVE_SIN_LEN
342 sin_c.sin_len = sizeof(struct sockaddr_in);
343 #endif
344 sin_c.sin_port = htons(client_port);
345 sin_c.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
346 memset(&sin_s, 0, sizeof(struct sockaddr_in));
347 sin_s.sin_family = AF_INET;
348 #ifdef HAVE_SIN_LEN
349 sin_s.sin_len = sizeof(struct sockaddr_in);
350 #endif
351 sin_s.sin_port = htons(server_port);
352 sin_s.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
353 #ifdef _WIN32
354 if (bind(fd_c, (struct sockaddr *)&sin_c, sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
355 fprintf(stderr, "bind() failed with error: %d\n", WSAGetLastError());
356 exit(EXIT_FAILURE);
357 }
358 if (bind(fd_s, (struct sockaddr *)&sin_s, sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
359 fprintf(stderr, "bind() failed with error: %d\n", WSAGetLastError());
360 exit(EXIT_FAILURE);
361 }
362 #else
363 if (bind(fd_c, (struct sockaddr *)&sin_c, sizeof(struct sockaddr_in)) < 0) {
364 perror("bind");
365 exit(EXIT_FAILURE);
366 }
367 if (bind(fd_s, (struct sockaddr *)&sin_s, sizeof(struct sockaddr_in)) < 0) {
368 perror("bind");
369 exit(EXIT_FAILURE);
370 }
371 #endif
372 #ifdef _WIN32
373 if (connect(fd_c, (struct sockaddr *)&sin_s, sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
374 fprintf(stderr, "connect() failed with error: %d\n", WSAGetLastError());
375 exit(EXIT_FAILURE);
376 }
377 if (connect(fd_s, (struct sockaddr *)&sin_c, sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
378 fprintf(stderr, "connect() failed with error: %d\n", WSAGetLastError());
379 exit(EXIT_FAILURE);
380 }
381 #else
382 if (connect(fd_c, (struct sockaddr *)&sin_s, sizeof(struct sockaddr_in)) < 0) {
383 perror("connect");
384 exit(EXIT_FAILURE);
385 }
386 if (connect(fd_s, (struct sockaddr *)&sin_c, sizeof(struct sockaddr_in)) < 0) {
387 perror("connect");
388 exit(EXIT_FAILURE);
389 }
390 #endif
391 #ifdef _WIN32
392 if ((tid_c = CreateThread(NULL, 0, &handle_packets, (void *)&fd_c, 0, NULL)) == NULL) {
393 fprintf(stderr, "CreateThread() failed with error: %d\n", GetLastError());
394 exit(EXIT_FAILURE);
395 }
396 if ((tid_s = CreateThread(NULL, 0, &handle_packets, (void *)&fd_s, 0, NULL)) == NULL) {
397 fprintf(stderr, "CreateThread() failed with error: %d\n", GetLastError());
398 exit(EXIT_FAILURE);
399 }
400 #else
401 if ((rc = pthread_create(&tid_c, NULL, &handle_packets, (void *)&fd_c)) != 0) {
402 fprintf(stderr, "pthread_create tid_c: %s\n", strerror(rc));
403 exit(EXIT_FAILURE);
404 }
405
406 if ((rc = pthread_create(&tid_s, NULL, &handle_packets, (void *)&fd_s)) != 0) {
407 fprintf(stderr, "pthread_create tid_s: %s\n", strerror(rc));
408 exit(EXIT_FAILURE);
409 };
410 #endif
411 #ifdef SCTP_DEBUG
412 usrsctp_sysctl_set_sctp_debug_on(SCTP_DEBUG_ALL);
413 #endif
414 usrsctp_sysctl_set_sctp_ecn_enable(0);
415 usrsctp_register_address((void *)&fd_c);
416 usrsctp_register_address((void *)&fd_s);
417 if ((s_c = usrsctp_socket(AF_CONN, SOCK_STREAM, IPPROTO_SCTP, receive_cb, NULL, 0, &fd_c)) == NULL) {
418 perror("usrsctp_socket");
419 exit(EXIT_FAILURE);
420 }
421 opt_len = (socklen_t)sizeof(int);
422 cur_buf_size = 0;
423 if (usrsctp_getsockopt(s_c, SOL_SOCKET, SO_SNDBUF, &cur_buf_size, &opt_len) < 0) {
424 perror("usrsctp_getsockopt");
425 exit(EXIT_FAILURE);
426 }
427 printf("Change send socket buffer size from %d ", cur_buf_size);
428 snd_buf_size = 1<<20; /* 1 MB */
429 if (usrsctp_setsockopt(s_c, SOL_SOCKET, SO_SNDBUF, &snd_buf_size, sizeof(int)) < 0) {
430 perror("usrsctp_setsockopt");
431 exit(EXIT_FAILURE);
432 }
433 opt_len = (socklen_t)sizeof(int);
434 cur_buf_size = 0;
435 if (usrsctp_getsockopt(s_c, SOL_SOCKET, SO_SNDBUF, &cur_buf_size, &opt_len) < 0) {
436 perror("usrsctp_getsockopt");
437 exit(EXIT_FAILURE);
438 }
439 printf("to %d.\n", cur_buf_size);
440 if ((s_l = usrsctp_socket(AF_CONN, SOCK_STREAM, IPPROTO_SCTP, receive_cb, NULL, 0, &fd_s)) == NULL) {
441 perror("usrsctp_socket");
442 exit(EXIT_FAILURE);
443 }
444 opt_len = (socklen_t)sizeof(int);
445 cur_buf_size = 0;
446 if (usrsctp_getsockopt(s_l, SOL_SOCKET, SO_RCVBUF, &cur_buf_size, &opt_len) < 0) {
447 perror("usrsctp_getsockopt");
448 exit(EXIT_FAILURE);
449 }
450 printf("Change receive socket buffer size from %d ", cur_buf_size);
451 rcv_buf_size = 1<<16; /* 64 KB */
452 if (usrsctp_setsockopt(s_l, SOL_SOCKET, SO_RCVBUF, &rcv_buf_size, sizeof(int)) < 0) {
453 perror("usrsctp_setsockopt");
454 exit(EXIT_FAILURE);
455 }
456 opt_len = (socklen_t)sizeof(int);
457 cur_buf_size = 0;
458 if (usrsctp_getsockopt(s_l, SOL_SOCKET, SO_RCVBUF, &cur_buf_size, &opt_len) < 0) {
459 perror("usrsctp_getsockopt");
460 exit(EXIT_FAILURE);
461 }
462 printf("to %d.\n", cur_buf_size);
463 /* Bind the client side. */
464 memset(&sconn, 0, sizeof(struct sockaddr_conn));
465 sconn.sconn_family = AF_CONN;
466 #ifdef HAVE_SCONN_LEN
467 sconn.sconn_len = sizeof(struct sockaddr_conn);
468 #endif
469 sconn.sconn_port = htons(5001);
470 sconn.sconn_addr = &fd_c;
471 if (usrsctp_bind(s_c, (struct sockaddr *)&sconn, sizeof(struct sockaddr_conn)) < 0) {
472 perror("usrsctp_bind");
473 exit(EXIT_FAILURE);
474 }
475 /* Bind the server side. */
476 memset(&sconn, 0, sizeof(struct sockaddr_conn));
477 sconn.sconn_family = AF_CONN;
478 #ifdef HAVE_SCONN_LEN
479 sconn.sconn_len = sizeof(struct sockaddr_conn);
480 #endif
481 sconn.sconn_port = htons(5001);
482 sconn.sconn_addr = &fd_s;
483 if (usrsctp_bind(s_l, (struct sockaddr *)&sconn, sizeof(struct sockaddr_conn)) < 0) {
484 perror("usrsctp_bind");
485 exit(EXIT_FAILURE);
486 }
487 /* Make server side passive... */
488 if (usrsctp_listen(s_l, 1) < 0) {
489 perror("usrsctp_listen");
490 exit(EXIT_FAILURE);
491 }
492 /* Initiate the handshake */
493 memset(&sconn, 0, sizeof(struct sockaddr_conn));
494 sconn.sconn_family = AF_CONN;
495 #ifdef HAVE_SCONN_LEN
496 sconn.sconn_len = sizeof(struct sockaddr_conn);
497 #endif
498 sconn.sconn_port = htons(5001);
499 sconn.sconn_addr = &fd_c;
500 if (usrsctp_connect(s_c, (struct sockaddr *)&sconn, sizeof(struct sockaddr_conn)) < 0) {
501 perror("usrsctp_connect");
502 exit(EXIT_FAILURE);
503 }
504 if ((s_s = usrsctp_accept(s_l, NULL, NULL)) == NULL) {
505 perror("usrsctp_accept");
506 exit(EXIT_FAILURE);
507 }
508 usrsctp_close(s_l);
509 if ((line = malloc(LINE_LENGTH)) == NULL) {
510 exit(EXIT_FAILURE);
511 }
512 memset(line, 'A', LINE_LENGTH);
513 sndinfo.snd_sid = 1;
514 sndinfo.snd_flags = 0;
515 sndinfo.snd_ppid = htonl(DISCARD_PPID);
516 sndinfo.snd_context = 0;
517 sndinfo.snd_assoc_id = 0;
518 /* Send a 1 MB message */
519 if (usrsctp_sendv(s_c, line, LINE_LENGTH, NULL, 0, (void *)&sndinfo,
520 (socklen_t)sizeof(struct sctp_sndinfo), SCTP_SENDV_SNDINFO, 0) < 0) {
521 perror("usrsctp_sendv");
522 exit(EXIT_FAILURE);
523 }
524 free(line);
525 usrsctp_shutdown(s_c, SHUT_WR);
526
527 while (usrsctp_finish() != 0) {
528 #ifdef _WIN32
529 Sleep(1000);
530 #else
531 sleep(1);
532 #endif
533 }
534 #ifdef _WIN32
535 TerminateThread(tid_c, 0);
536 WaitForSingleObject(tid_c, INFINITE);
537 TerminateThread(tid_s, 0);
538 WaitForSingleObject(tid_s, INFINITE);
539 if (closesocket(fd_c) == SOCKET_ERROR) {
540 fprintf(stderr, "closesocket() failed with error: %d\n", WSAGetLastError());
541 exit(EXIT_FAILURE);
542 }
543 if (closesocket(fd_s) == SOCKET_ERROR) {
544 fprintf(stderr, "closesocket() failed with error: %d\n", WSAGetLastError());
545 exit(EXIT_FAILURE);
546 }
547 WSACleanup();
548 #else
549 pthread_cancel(tid_c);
550 pthread_join(tid_c, NULL);
551 pthread_cancel(tid_s);
552 pthread_join(tid_s, NULL);
553 if (close(fd_c) < 0) {
554 perror("close");
555 exit(EXIT_FAILURE);
556 }
557 if (close(fd_s) < 0) {
558 perror("close");
559 exit(EXIT_FAILURE);
560 }
561 #endif
562 return (0);
563 }
564