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