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 /*
32  * Usage: client remote_addr remote_port [local_port] [local_encaps_port] [remote_encaps_port]
33  */
34 
35 #ifdef _WIN32
36 #define _CRT_SECURE_NO_WARNINGS
37 #endif
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <stdarg.h>
42 #ifndef _WIN32
43 #include <unistd.h>
44 #endif
45 #include <sys/types.h>
46 #ifndef _WIN32
47 #include <sys/socket.h>
48 #include <netinet/in.h>
49 #include <arpa/inet.h>
50 #else
51 #include <io.h>
52 #endif
53 #include <usrsctp.h>
54 #include "programs_helper.h"
55 
56 int done = 0;
57 
58 #ifdef _WIN32
59 typedef char* caddr_t;
60 #endif
61 
62 
63 
64 static int
receive_cb(struct socket * sock,union sctp_sockstore addr,void * data,size_t datalen,struct sctp_rcvinfo rcv,int flags,void * ulp_info)65 receive_cb(struct socket *sock, union sctp_sockstore addr, void *data,
66            size_t datalen, struct sctp_rcvinfo rcv, int flags, void *ulp_info)
67 {
68 	if (data == NULL) {
69 		done = 1;
70 		usrsctp_close(sock);
71 	} else {
72 		if (flags & MSG_NOTIFICATION) {
73 			handle_notification((union sctp_notification *)data, datalen);
74 		} else {
75 #ifdef _WIN32
76 			_write(_fileno(stdout), data, (unsigned int)datalen);
77 #else
78 			if (write(fileno(stdout), data, datalen) < 0) {
79 				perror("write");
80 			}
81 #endif
82 		}
83 		free(data);
84 	}
85 	return (1);
86 }
87 
88 int
main(int argc,char * argv[])89 main(int argc, char *argv[])
90 {
91 	struct socket *sock;
92 	struct sockaddr *addr, *addrs;
93 	struct sockaddr_in addr4;
94 	struct sockaddr_in6 addr6;
95 	struct sctp_udpencaps encaps;
96 	struct sctpstat stat;
97 	struct sctp_event event;
98 	uint16_t event_types[] = {SCTP_ASSOC_CHANGE,
99 	                          SCTP_PEER_ADDR_CHANGE,
100 	                          SCTP_SEND_FAILED_EVENT};
101 	char buffer[80];
102 	unsigned int i;
103 	int n;
104 
105 	if (argc < 3) {
106 		printf("%s", "Usage: client remote_addr remote_port local_port local_encaps_port remote_encaps_port\n");
107 		return (-1);
108 	}
109 	if (argc > 4) {
110 		usrsctp_init(atoi(argv[4]), NULL, debug_printf_stack);
111 	} else {
112 		usrsctp_init(9899, NULL, debug_printf_stack);
113 	}
114 #ifdef SCTP_DEBUG
115 	usrsctp_sysctl_set_sctp_debug_on(SCTP_DEBUG_NONE);
116 #endif
117 	usrsctp_sysctl_set_sctp_blackhole(2);
118 	usrsctp_sysctl_set_sctp_no_csum_on_loopback(0);
119 
120 	if ((sock = usrsctp_socket(AF_INET6, SOCK_STREAM, IPPROTO_SCTP, receive_cb, NULL, 0, NULL)) == NULL) {
121 		perror("usrsctp_socket");
122 	}
123 	memset(&event, 0, sizeof(event));
124 	event.se_assoc_id = SCTP_ALL_ASSOC;
125 	event.se_on = 1;
126 	for (i = 0; i < sizeof(event_types)/sizeof(uint16_t); i++) {
127 		event.se_type = event_types[i];
128 		if (usrsctp_setsockopt(sock, IPPROTO_SCTP, SCTP_EVENT, &event, sizeof(event)) < 0) {
129 			perror("setsockopt SCTP_EVENT");
130 		}
131 	}
132 	if (argc > 3) {
133 		memset((void *)&addr6, 0, sizeof(struct sockaddr_in6));
134 #ifdef HAVE_SIN6_LEN
135 		addr6.sin6_len = sizeof(struct sockaddr_in6);
136 #endif
137 		addr6.sin6_family = AF_INET6;
138 		addr6.sin6_port = htons(atoi(argv[3]));
139 		addr6.sin6_addr = in6addr_any;
140 		if (usrsctp_bind(sock, (struct sockaddr *)&addr6, sizeof(struct sockaddr_in6)) < 0) {
141 			perror("bind");
142 		}
143 	}
144 	if (argc > 5) {
145 		memset(&encaps, 0, sizeof(struct sctp_udpencaps));
146 		encaps.sue_address.ss_family = AF_INET6;
147 		encaps.sue_port = htons(atoi(argv[5]));
148 		if (usrsctp_setsockopt(sock, IPPROTO_SCTP, SCTP_REMOTE_UDP_ENCAPS_PORT, (const void*)&encaps, (socklen_t)sizeof(struct sctp_udpencaps)) < 0) {
149 			perror("setsockopt");
150 		}
151 	}
152 	memset((void *)&addr4, 0, sizeof(struct sockaddr_in));
153 	memset((void *)&addr6, 0, sizeof(struct sockaddr_in6));
154 #ifdef HAVE_SIN_LEN
155 	addr4.sin_len = sizeof(struct sockaddr_in);
156 #endif
157 #ifdef HAVE_SIN6_LEN
158 	addr6.sin6_len = sizeof(struct sockaddr_in6);
159 #endif
160 	addr4.sin_family = AF_INET;
161 	addr6.sin6_family = AF_INET6;
162 	addr4.sin_port = htons(atoi(argv[2]));
163 	addr6.sin6_port = htons(atoi(argv[2]));
164 	if (inet_pton(AF_INET6, argv[1], &addr6.sin6_addr) == 1) {
165 		if (usrsctp_connect(sock, (struct sockaddr *)&addr6, sizeof(struct sockaddr_in6)) < 0) {
166 			perror("usrsctp_connect");
167 		}
168 	} else if (inet_pton(AF_INET, argv[1], &addr4.sin_addr) == 1) {
169 		if (usrsctp_connect(sock, (struct sockaddr *)&addr4, sizeof(struct sockaddr_in)) < 0) {
170 			perror("usrsctp_connect");
171 		}
172 	} else {
173 		printf("Illegal destination address.\n");
174 	}
175 	if ((n = usrsctp_getladdrs(sock, 0, &addrs)) < 0) {
176 		perror("usrsctp_getladdrs");
177 	} else {
178 		addr = addrs;
179 		printf("Local addresses: ");
180 		for (i = 0; i < (unsigned int)n; i++) {
181 			if (i > 0) {
182 				printf("%s", ", ");
183 			}
184 			switch (addr->sa_family) {
185 			case AF_INET:
186 			{
187 				struct sockaddr_in *sin;
188 				char buf[INET_ADDRSTRLEN];
189 				const char *name;
190 
191 				sin = (struct sockaddr_in *)addr;
192 				name = inet_ntop(AF_INET, &sin->sin_addr, buf, INET_ADDRSTRLEN);
193 				printf("%s", name);
194 #ifndef HAVE_SA_LEN
195 				addr = (struct sockaddr *)((caddr_t)addr + sizeof(struct sockaddr_in));
196 #endif
197 				break;
198 			}
199 			case AF_INET6:
200 			{
201 				struct sockaddr_in6 *sin6;
202 				char buf[INET6_ADDRSTRLEN];
203 				const char *name;
204 
205 				sin6 = (struct sockaddr_in6 *)addr;
206 				name = inet_ntop(AF_INET6, &sin6->sin6_addr, buf, INET6_ADDRSTRLEN);
207 				printf("%s", name);
208 #ifndef HAVE_SA_LEN
209 				addr = (struct sockaddr *)((caddr_t)addr + sizeof(struct sockaddr_in6));
210 #endif
211 				break;
212 			}
213 			default:
214 				break;
215 			}
216 #ifdef HAVE_SA_LEN
217 			addr = (struct sockaddr *)((caddr_t)addr + addr->sa_len);
218 #endif
219 		}
220 		printf(".\n");
221 		usrsctp_freeladdrs(addrs);
222 	}
223 	if ((n = usrsctp_getpaddrs(sock, 0, &addrs)) < 0) {
224 		perror("usrsctp_getpaddrs");
225 	} else {
226 		addr = addrs;
227 		printf("Peer addresses: ");
228 		for (i = 0; i < (unsigned int)n; i++) {
229 			if (i > 0) {
230 				printf("%s", ", ");
231 			}
232 			switch (addr->sa_family) {
233 			case AF_INET:
234 			{
235 				struct sockaddr_in *sin;
236 				char buf[INET_ADDRSTRLEN];
237 				const char *name;
238 
239 				sin = (struct sockaddr_in *)addr;
240 				name = inet_ntop(AF_INET, &sin->sin_addr, buf, INET_ADDRSTRLEN);
241 				printf("%s", name);
242 #ifndef HAVE_SA_LEN
243 				addr = (struct sockaddr *)((caddr_t)addr + sizeof(struct sockaddr_in));
244 #endif
245 				break;
246 			}
247 			case AF_INET6:
248 			{
249 				struct sockaddr_in6 *sin6;
250 				char buf[INET6_ADDRSTRLEN];
251 				const char *name;
252 
253 				sin6 = (struct sockaddr_in6 *)addr;
254 				name = inet_ntop(AF_INET6, &sin6->sin6_addr, buf, INET6_ADDRSTRLEN);
255 				printf("%s", name);
256 #ifndef HAVE_SA_LEN
257 				addr = (struct sockaddr *)((caddr_t)addr + sizeof(struct sockaddr_in6));
258 #endif
259 				break;
260 			}
261 			default:
262 				break;
263 			}
264 #ifdef HAVE_SA_LEN
265 			addr = (struct sockaddr *)((caddr_t)addr + addr->sa_len);
266 #endif
267 		}
268 		printf(".\n");
269 		usrsctp_freepaddrs(addrs);
270 	}
271 	while ((fgets(buffer, sizeof(buffer), stdin) != NULL) && !done) {
272 		usrsctp_sendv(sock, buffer, strlen(buffer), NULL, 0, NULL, 0, SCTP_SENDV_NOINFO, 0);
273 	}
274 	if (!done) {
275 		if (usrsctp_shutdown(sock, SHUT_WR) < 0) {
276 			perror("usrsctp_shutdown");
277 		}
278 	}
279 	while (!done) {
280 #ifdef _WIN32
281 		Sleep(1 * 1000);
282 #else
283 		sleep(1);
284 #endif
285 	}
286 	usrsctp_get_stat(&stat);
287 	printf("Number of packets (sent/received): (%u/%u).\n",
288 	       stat.sctps_outpackets, stat.sctps_inpackets);
289 	while (usrsctp_finish() != 0) {
290 #ifdef _WIN32
291 		Sleep(1 * 1000);
292 #else
293 		sleep(1);
294 #endif
295 	}
296 	return(0);
297 }
298