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