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 BUFFER_SIZE 80
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_buf;
70 	ssize_t length;
71 	char buf[MAX_PACKET_SIZE];
72 
73 #ifdef _WIN32
74 	fdp = (SOCKET *)arg;
75 #else
76 	fdp = (int *)arg;
77 #endif
78 	for (;;) {
79 #if defined(__NetBSD__)
80 		pthread_testcancel();
81 #endif
82 		length = recv(*fdp, buf, MAX_PACKET_SIZE, 0);
83 		if (length > 0) {
84 			if ((dump_buf = usrsctp_dumppacket(buf, (size_t)length, SCTP_DUMP_INBOUND)) != NULL) {
85 				fprintf(stderr, "%s", dump_buf);
86 				usrsctp_freedumpbuffer(dump_buf);
87 			}
88 			usrsctp_conninput(fdp, buf, (size_t)length, 0);
89 		}
90 	}
91 #ifdef _WIN32
92 	return 0;
93 #else
94 	return (NULL);
95 #endif
96 }
97 
98 static int
conn_output(void * addr,void * buf,size_t length,uint8_t tos,uint8_t set_df)99 conn_output(void *addr, void *buf, size_t length, uint8_t tos, uint8_t set_df)
100 {
101 	char *dump_buf;
102 #ifdef _WIN32
103 	SOCKET *fdp;
104 #else
105 	int *fdp;
106 #endif
107 
108 #ifdef _WIN32
109 	fdp = (SOCKET *)addr;
110 #else
111 	fdp = (int *)addr;
112 #endif
113 	if ((dump_buf = usrsctp_dumppacket(buf, length, SCTP_DUMP_OUTBOUND)) != NULL) {
114 		fprintf(stderr, "%s", dump_buf);
115 		usrsctp_freedumpbuffer(dump_buf);
116 	}
117 #ifdef _WIN32
118 	if (send(*fdp, buf, (int)length, 0) == SOCKET_ERROR) {
119 		return (WSAGetLastError());
120 #else
121 	if (send(*fdp, buf, length, 0) < 0) {
122 		return (errno);
123 #endif
124 	} else {
125 		return (0);
126 	}
127 }
128 
129 static int
130 receive_cb(struct socket *sock, union sctp_sockstore addr, void *data,
131            size_t datalen, struct sctp_rcvinfo rcv, int flags, void *ulp_info)
132 {
133 
134 	if (data) {
135 		if (flags & MSG_NOTIFICATION) {
136 			printf("Notification of length %d received.\n", (int)datalen);
137 		} else {
138 			printf("Msg of length %d received via %p:%u on stream %u with SSN %u and TSN %u, PPID %u, context %u.\n",
139 			       (int)datalen,
140 			       addr.sconn.sconn_addr,
141 			       ntohs(addr.sconn.sconn_port),
142 			       rcv.rcv_sid,
143 			       rcv.rcv_ssn,
144 			       rcv.rcv_tsn,
145 			       ntohl(rcv.rcv_ppid),
146 			       rcv.rcv_context);
147 		}
148 		free(data);
149 	} else {
150 		usrsctp_deregister_address(ulp_info);
151 		usrsctp_close(sock);
152 	}
153 	return (1);
154 }
155 
156 int
157 main(int argc, char *argv[])
158 {
159 	struct sockaddr_in sin;
160 	struct sockaddr_conn sconn;
161 #ifdef _WIN32
162 	SOCKET fd;
163 #else
164 	int fd, rc;
165 #endif
166 	struct socket *s;
167 #ifdef _WIN32
168 	HANDLE tid;
169 #else
170 	pthread_t tid;
171 #endif
172 	struct sctp_sndinfo sndinfo;
173 	char buffer[BUFFER_SIZE];
174 #ifdef _WIN32
175 	WSADATA wsaData;
176 #endif
177 
178 	if (argc < 4) {
179 		fprintf(stderr, "error: this program requires 4 arguments!\n");
180 		exit(EXIT_FAILURE);
181 	}
182 
183 #ifdef _WIN32
184 	if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0) {
185 		fprintf(stderr, "WSAStartup failed\n");
186 		exit (EXIT_FAILURE);
187 	}
188 #endif
189 	usrsctp_init(0, conn_output, debug_printf_stack);
190 	/* set up a connected UDP socket */
191 #ifdef _WIN32
192 	if ((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET) {
193 		fprintf(stderr, "socket() failed with error: %d\n", WSAGetLastError());
194 		exit(EXIT_FAILURE);
195 	}
196 #else
197 	if ((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
198 		perror("socket");
199 		exit(EXIT_FAILURE);
200 	}
201 #endif
202 	memset(&sin, 0, sizeof(struct sockaddr_in));
203 	sin.sin_family = AF_INET;
204 #ifdef HAVE_SIN_LEN
205 	sin.sin_len = sizeof(struct sockaddr_in);
206 #endif
207 	sin.sin_port = htons(atoi(argv[2]));
208 	if (!inet_pton(AF_INET, argv[1], &sin.sin_addr.s_addr)){
209 		fprintf(stderr, "error: invalid address\n");
210 		exit(EXIT_FAILURE);
211 	}
212 #ifdef _WIN32
213 	if (bind(fd, (struct sockaddr *)&sin, sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
214 		fprintf(stderr, "bind() failed with error: %d\n", WSAGetLastError());
215 		exit(EXIT_FAILURE);
216 	}
217 #else
218 	if (bind(fd, (struct sockaddr *)&sin, sizeof(struct sockaddr_in)) < 0) {
219 		perror("bind");
220 		exit(EXIT_FAILURE);
221 	}
222 #endif
223 	memset(&sin, 0, sizeof(struct sockaddr_in));
224 	sin.sin_family = AF_INET;
225 #ifdef HAVE_SIN_LEN
226 	sin.sin_len = sizeof(struct sockaddr_in);
227 #endif
228 	sin.sin_port = htons(atoi(argv[4]));
229 	if (!inet_pton(AF_INET, argv[3], &sin.sin_addr.s_addr)){
230 		printf("error: invalid address\n");
231 		exit(EXIT_FAILURE);
232 	}
233 #ifdef _WIN32
234 	if (connect(fd, (struct sockaddr *)&sin, sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
235 		fprintf(stderr, "connect() failed with error: %d\n", WSAGetLastError());
236 		exit(EXIT_FAILURE);
237 	}
238 #else
239 	if (connect(fd, (struct sockaddr *)&sin, sizeof(struct sockaddr_in)) < 0) {
240 		perror("connect");
241 		exit(EXIT_FAILURE);
242 	}
243 #endif
244 #ifdef SCTP_DEBUG
245 	usrsctp_sysctl_set_sctp_debug_on(SCTP_DEBUG_NONE);
246 #endif
247 	usrsctp_sysctl_set_sctp_ecn_enable(0);
248 	usrsctp_register_address((void *)&fd);
249 #ifdef _WIN32
250 	if ((tid = CreateThread(NULL, 0, &handle_packets, (void *)&fd, 0, NULL)) == NULL) {
251 		fprintf(stderr, "CreateThread() failed with error: %d\n", GetLastError());
252 		exit(EXIT_FAILURE);
253 	}
254 #else
255 	if ((rc = pthread_create(&tid, NULL, &handle_packets, (void *)&fd)) != 0) {
256 		fprintf(stderr, "pthread_create: %s\n", strerror(rc));
257 		exit(EXIT_FAILURE);
258 	}
259 #endif
260 	if ((s = usrsctp_socket(AF_CONN, SOCK_STREAM, IPPROTO_SCTP, receive_cb, NULL, 0, &fd)) == NULL) {
261 		perror("usrsctp_socket");
262 	}
263 
264 	memset(&sconn, 0, sizeof(struct sockaddr_conn));
265 	sconn.sconn_family = AF_CONN;
266 #ifdef HAVE_SCONN_LEN
267 	sconn.sconn_len = sizeof(struct sockaddr_conn);
268 #endif
269 	sconn.sconn_port = htons(0);
270 	sconn.sconn_addr = NULL;
271 	if (usrsctp_bind(s, (struct sockaddr *)&sconn, sizeof(struct sockaddr_conn)) < 0) {
272 		perror("usrsctp_bind");
273 	}
274 
275 	memset(&sconn, 0, sizeof(struct sockaddr_conn));
276 	sconn.sconn_family = AF_CONN;
277 #ifdef HAVE_SCONN_LEN
278 	sconn.sconn_len = sizeof(struct sockaddr_conn);
279 #endif
280 	sconn.sconn_port = htons(5001);
281 	sconn.sconn_addr = &fd;
282 	if (usrsctp_connect(s, (struct sockaddr *)&sconn, sizeof(struct sockaddr_conn)) < 0) {
283 		perror("usrsctp_connect");
284 	}
285 	memset(buffer, 'A', BUFFER_SIZE);
286 	sndinfo.snd_sid = 1;
287 	sndinfo.snd_flags = 0;
288 	sndinfo.snd_ppid = htonl(DISCARD_PPID);
289 	sndinfo.snd_context = 0;
290 	sndinfo.snd_assoc_id = 0;
291 	if (usrsctp_sendv(s, buffer, BUFFER_SIZE, NULL, 0, (void *)&sndinfo,
292 	                  (socklen_t)sizeof(struct sctp_sndinfo), SCTP_SENDV_SNDINFO, 0) < 0) {
293 		perror("usrsctp_sendv");
294 	}
295 
296 	usrsctp_shutdown(s, SHUT_WR);
297 	while (usrsctp_finish() != 0) {
298 #ifdef _WIN32
299 		Sleep(1000);
300 #else
301 		sleep(1);
302 #endif
303 	}
304 #ifdef _WIN32
305 	TerminateThread(tid, 0);
306 	WaitForSingleObject(tid, INFINITE);
307 	if (closesocket(fd) == SOCKET_ERROR) {
308 		fprintf(stderr, "closesocket() failed with error: %d\n", WSAGetLastError());
309 	}
310 	WSACleanup();
311 #else
312 	pthread_cancel(tid);
313 	pthread_join(tid, NULL);
314 	if (close(fd) < 0) {
315 		perror("close");
316 	}
317 #endif
318 	return (0);
319 }
320