1 /*
2 * Copyright (C) 2016-2019 Felix Weinrank
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: http_client remote_addr remote_port [local_port] [local_encaps_port] [remote_encaps_port] [uri]
33 *
34 * Example
35 * Client: $ ./http_client 212.201.121.100 80 0 9899 9899 /cgi-bin/he
36 * ./http_client 2a02:c6a0:4015:10::100 80 0 9899 9899 /cgi-bin/he
37 */
38
39 #ifdef _WIN32
40 #define _CRT_SECURE_NO_WARNINGS
41 #endif
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <stdarg.h>
46 #ifndef _WIN32
47 #include <unistd.h>
48 #endif
49 #include <sys/types.h>
50 #ifndef _WIN32
51 #include <sys/socket.h>
52 #include <netinet/in.h>
53 #include <arpa/inet.h>
54 #include <sys/time.h>
55 #else
56 #include <io.h>
57 #include <sys/types.h>
58 #include <sys/timeb.h>
59 #endif
60 #include <usrsctp.h>
61 #include "programs_helper.h"
62
63 #define RETVAL_CATCHALL 50
64 #define RETVAL_TIMEOUT 60
65 #define RETVAL_ECONNREFUSED 61
66
67 int done = 0;
68 static const char *request_prefix = "GET";
69 static const char *request_postfix = "HTTP/1.0\r\nUser-agent: libusrsctp\r\nConnection: close\r\n\r\n";
70 char request[512];
71
72 #ifdef _WIN32
73 typedef char* caddr_t;
74 #endif
75
76 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)77 receive_cb(struct socket *sock, union sctp_sockstore addr, void *data,
78 size_t datalen, struct sctp_rcvinfo rcv, int flags, void *ulp_info)
79 {
80 if (data == NULL) {
81 done = 1;
82 usrsctp_close(sock);
83 } else {
84 if (flags & MSG_NOTIFICATION) {
85 handle_notification((union sctp_notification *)data, datalen);
86 } else {
87 #ifdef _WIN32
88 _write(_fileno(stdout), data, (unsigned int)datalen);
89 #else
90 if (write(fileno(stdout), data, datalen) < 0) {
91 perror("write");
92 }
93 #endif
94 }
95 free(data);
96 }
97 return (1);
98 }
99
100 int
main(int argc,char * argv[])101 main(int argc, char *argv[])
102 {
103 struct socket *sock;
104 struct sockaddr *addr;
105 socklen_t addr_len;
106 struct sockaddr_in addr4;
107 struct sockaddr_in6 addr6;
108 struct sockaddr_in bind4;
109 struct sockaddr_in6 bind6;
110 struct sctp_udpencaps encaps;
111 struct sctp_sndinfo sndinfo;
112 struct sctp_rtoinfo rtoinfo;
113 struct sctp_initmsg initmsg;
114 struct sctp_event event;
115 int result = 0;
116 unsigned int i;
117 uint8_t address_family = 0;
118 uint16_t event_types[] = {SCTP_ASSOC_CHANGE,
119 SCTP_PEER_ADDR_CHANGE,
120 SCTP_SEND_FAILED_EVENT,
121 SCTP_REMOTE_ERROR,
122 SCTP_SHUTDOWN_EVENT,
123 SCTP_ADAPTATION_INDICATION,
124 SCTP_PARTIAL_DELIVERY_EVENT
125 };
126
127 if (argc < 3) {
128 printf("Usage: http_client remote_addr remote_port [local_port] [local_encaps_port] [remote_encaps_port] [uri]\n");
129 return(EXIT_FAILURE);
130 }
131
132 memset((void *)&addr4, 0, sizeof(struct sockaddr_in));
133 memset((void *)&addr6, 0, sizeof(struct sockaddr_in6));
134
135 if (inet_pton(AF_INET, argv[1], &addr4.sin_addr) == 1) {
136 address_family = AF_INET;
137
138 addr = (struct sockaddr *)&addr4;
139 addr_len = sizeof(addr4);
140 #ifdef HAVE_SIN_LEN
141 addr4.sin_len = sizeof(struct sockaddr_in);
142 #endif
143 addr4.sin_family = AF_INET;
144 addr4.sin_port = htons(atoi(argv[2]));
145 } else if (inet_pton(AF_INET6, argv[1], &addr6.sin6_addr) == 1) {
146 address_family = AF_INET6;
147
148 addr = (struct sockaddr *)&addr6;
149 addr_len = sizeof(addr6);
150 #ifdef HAVE_SIN6_LEN
151 addr6.sin6_len = sizeof(struct sockaddr_in6);
152 #endif
153 addr6.sin6_family = AF_INET6;
154 addr6.sin6_port = htons(atoi(argv[2]));
155 } else {
156 printf("Unsupported destination address - use IPv4 or IPv6 address\n");
157 result = RETVAL_CATCHALL;
158 goto out;
159 }
160
161 if (argc > 4) {
162 usrsctp_init(atoi(argv[4]), NULL, debug_printf_stack);
163 } else {
164 usrsctp_init(9899, NULL, debug_printf_stack);
165 }
166
167 #ifdef SCTP_DEBUG
168 usrsctp_sysctl_set_sctp_debug_on(SCTP_DEBUG_ALL);
169 #endif
170
171 usrsctp_sysctl_set_sctp_blackhole(2);
172 usrsctp_sysctl_set_sctp_no_csum_on_loopback(0);
173
174 if ((sock = usrsctp_socket(address_family, SOCK_STREAM, IPPROTO_SCTP, receive_cb, NULL, 0, NULL)) == NULL) {
175 perror("usrsctp_socket");
176 result = RETVAL_CATCHALL;
177 goto out;
178 }
179
180 memset(&event, 0, sizeof(event));
181 event.se_assoc_id = SCTP_ALL_ASSOC;
182 event.se_on = 1;
183 for (i = 0; i < sizeof(event_types) / sizeof(uint16_t); i++) {
184 event.se_type = event_types[i];
185 if (usrsctp_setsockopt(sock, IPPROTO_SCTP, SCTP_EVENT, &event, sizeof(event)) < 0) {
186 perror("setsockopt SCTP_EVENT");
187 }
188 }
189
190 rtoinfo.srto_assoc_id = 0;
191 rtoinfo.srto_initial = 1000;
192 rtoinfo.srto_min = 1000;
193 rtoinfo.srto_max = 8000;
194 if (usrsctp_setsockopt(sock, IPPROTO_SCTP, SCTP_RTOINFO, (const void *)&rtoinfo, (socklen_t)sizeof(struct sctp_rtoinfo)) < 0) {
195 perror("setsockopt");
196 usrsctp_close(sock);
197 result = RETVAL_CATCHALL;
198 goto out;
199 }
200 initmsg.sinit_num_ostreams = 1;
201 initmsg.sinit_max_instreams = 1;
202 initmsg.sinit_max_attempts = 5;
203 initmsg.sinit_max_init_timeo = 4000;
204 if (usrsctp_setsockopt(sock, IPPROTO_SCTP, SCTP_INITMSG, (const void *)&initmsg, (socklen_t)sizeof(struct sctp_initmsg)) < 0) {
205 perror("setsockopt");
206 usrsctp_close(sock);
207 result = RETVAL_CATCHALL;
208 goto out;
209 }
210
211 if (argc > 3) {
212
213 if (address_family == AF_INET) {
214 memset((void *)&bind4, 0, sizeof(struct sockaddr_in));
215 #ifdef HAVE_SIN_LEN
216 bind4.sin_len = sizeof(struct sockaddr_in6);
217 #endif
218 bind4.sin_family = AF_INET;
219 bind4.sin_port = htons(atoi(argv[3]));
220 bind4.sin_addr.s_addr = htonl(INADDR_ANY);
221
222 if (usrsctp_bind(sock, (struct sockaddr *)&bind4, sizeof(bind4)) < 0) {
223 perror("bind");
224 usrsctp_close(sock);
225 result = RETVAL_CATCHALL;
226 goto out;
227 }
228 } else {
229 memset((void *)&bind6, 0, sizeof(struct sockaddr_in6));
230 #ifdef HAVE_SIN6_LEN
231 bind6.sin6_len = sizeof(struct sockaddr_in6);
232 #endif
233 bind6.sin6_family = AF_INET6;
234 bind6.sin6_port = htons(atoi(argv[3]));
235 bind6.sin6_addr = in6addr_any;
236 if (usrsctp_bind(sock, (struct sockaddr *)&bind6, sizeof(bind6)) < 0) {
237 perror("bind");
238 usrsctp_close(sock);
239 result = RETVAL_CATCHALL;
240 goto out;
241 }
242 }
243 }
244
245 if (argc > 5) {
246 memset(&encaps, 0, sizeof(struct sctp_udpencaps));
247 encaps.sue_address.ss_family = address_family;
248 encaps.sue_port = htons(atoi(argv[5]));
249 if (usrsctp_setsockopt(sock, IPPROTO_SCTP, SCTP_REMOTE_UDP_ENCAPS_PORT, (const void *)&encaps, (socklen_t)sizeof(struct sctp_udpencaps)) < 0) {
250 perror("setsockopt");
251 usrsctp_close(sock);
252 result = RETVAL_CATCHALL;
253 goto out;
254 }
255 }
256
257 if (argc > 6) {
258 #ifdef _WIN32
259 if (_snprintf(request, sizeof(request), "%s %s %s", request_prefix, argv[6], request_postfix) < 0) {
260 #else
261 if (snprintf(request, sizeof(request), "%s %s %s", request_prefix, argv[6], request_postfix) < 0) {
262 #endif
263 request[0] = '\0';
264 }
265 } else {
266 #ifdef _WIN32
267 if (_snprintf(request, sizeof(request), "%s %s %s", request_prefix, "/", request_postfix) < 0) {
268 #else
269 if (snprintf(request, sizeof(request), "%s %s %s", request_prefix, "/", request_postfix) < 0) {
270 #endif
271 request[0] = '\0';
272 }
273 }
274
275 printf("\nHTTP request:\n%s\n", request);
276 printf("\nHTTP response:\n");
277
278 if (usrsctp_connect(sock, addr, addr_len) < 0) {
279 if (errno == ECONNREFUSED) {
280 result = RETVAL_ECONNREFUSED;
281 } else if (errno == ETIMEDOUT) {
282 result = RETVAL_TIMEOUT;
283 } else {
284 result = RETVAL_CATCHALL;
285 }
286 perror("usrsctp_connect");
287 usrsctp_close(sock);
288
289 goto out;
290 }
291
292 memset(&sndinfo, 0, sizeof(struct sctp_sndinfo));
293 sndinfo.snd_ppid = htonl(63); /* PPID for HTTP/SCTP */
294 /* send GET request */
295 if (usrsctp_sendv(sock, request, strlen(request), NULL, 0, &sndinfo, sizeof(struct sctp_sndinfo), SCTP_SENDV_SNDINFO, 0) < 0) {
296 perror("usrsctp_sendv");
297 usrsctp_close(sock);
298 result = RETVAL_CATCHALL;
299 goto out;
300 }
301
302 while (!done) {
303 #ifdef _WIN32
304 Sleep(1*1000);
305 #else
306 sleep(1);
307 #endif
308 }
309 out:
310 while (usrsctp_finish() != 0) {
311 #ifdef _WIN32
312 Sleep(1000);
313 #else
314 sleep(1);
315 #endif
316 }
317 printf("Finished, returning with %d\n", result);
318 return (result);
319 }
320