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