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