blob: 19cbefedafe9a102159a420e6fcc05a478b45328 [file] [log] [blame]
James Kuszmaul4cb043c2021-01-17 11:25:51 -08001/*
2 * Copyright (C) 2016 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
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
55int done = 0;
56int writePending = 1;
57
58static const char *request_prefix = "GET";
59static const char *request_postfix = "HTTP/1.0\r\nUser-agent: libusrsctp\r\nConnection: close\r\n\r\n";
60char request[512];
61
62#ifdef _WIN32
63typedef char* caddr_t;
64#endif
65
66#define BUFFERSIZE (1<<16)
67
68
69static void handle_upcall(struct socket *sock, void *arg, int flags)
70{
71 int events = usrsctp_get_events(sock);
72 int bytesSent = 0;
73 char *buf;
74
75 if ((events & SCTP_EVENT_WRITE) && writePending) {
76 writePending = 0;
77 printf("\nHTTP request:\n%s\n", request);
78 printf("\nHTTP response:\n");
79
80 /* send GET request */
81 bytesSent = usrsctp_sendv(sock, request, strlen(request), NULL, 0, NULL, 0, SCTP_SENDV_NOINFO, 0);
82 if (bytesSent < 0) {
83 perror("usrsctp_sendv");
84 usrsctp_close(sock);
85 } else {
86 printf("%d bytes sent\n", bytesSent);
87 }
88 }
89
90 if ((events & SCTP_EVENT_READ) && !done) {
91 struct sctp_recvv_rn rn;
92 ssize_t n;
93 struct sockaddr_in addr;
94 buf = malloc(BUFFERSIZE);
95 int flags = 0;
96 socklen_t len = (socklen_t)sizeof(struct sockaddr_in);
97 unsigned int infotype = 0;
98 socklen_t infolen = sizeof(struct sctp_recvv_rn);
99 memset(&rn, 0, sizeof(struct sctp_recvv_rn));
100 n = usrsctp_recvv(sock, buf, BUFFERSIZE, (struct sockaddr *) &addr, &len, (void *)&rn,
101 &infolen, &infotype, &flags);
102 if (n > 0)
103 n = write(1, buf, n);
104 done = 1;
105 usrsctp_close(sock);
106 free(buf);
107 return;
108 }
109}
110
111void
112debug_printf(const char *format, ...)
113{
114 va_list ap;
115
116 va_start(ap, format);
117 vprintf(format, ap);
118 va_end(ap);
119}
120
121int
122main(int argc, char *argv[])
123{
124 struct socket *sock;
125 struct sockaddr_in addr4;
126 struct sockaddr_in6 addr6;
127 struct sctp_udpencaps encaps;
128 int result;
129
130 if (argc < 3) {
131 printf("Usage: http_client remote_addr remote_port [local_port] [local_encaps_port] [remote_encaps_port] [uri]\n");
132 return(EXIT_FAILURE);
133 }
134
135 result = 0;
136 if (argc > 4) {
137 usrsctp_init(atoi(argv[4]), NULL, debug_printf);
138 } else {
139 usrsctp_init(9899, NULL, debug_printf);
140 }
141
142#ifdef SCTP_DEBUG
143 usrsctp_sysctl_set_sctp_debug_on(SCTP_DEBUG_NONE);
144#endif
145
146 usrsctp_sysctl_set_sctp_blackhole(2);
147
148 if ((sock = usrsctp_socket(AF_INET6, SOCK_STREAM, IPPROTO_SCTP, NULL, NULL, 0, NULL)) == NULL) {
149 perror("usrsctp_socket");
150 result = 1;
151 goto out;
152 }
153
154 usrsctp_set_non_blocking(sock, 1);
155
156 if (argc > 3) {
157 memset((void *)&addr6, 0, sizeof(struct sockaddr_in6));
158#ifdef HAVE_SIN6_LEN
159 addr6.sin6_len = sizeof(struct sockaddr_in6);
160#endif
161 addr6.sin6_family = AF_INET6;
162 addr6.sin6_port = htons(atoi(argv[3]));
163 addr6.sin6_addr = in6addr_any;
164 if (usrsctp_bind(sock, (struct sockaddr *)&addr6, sizeof(struct sockaddr_in6)) < 0) {
165 perror("bind");
166 usrsctp_close(sock);
167 result = 2;
168 goto out;
169 }
170 }
171
172 if (argc > 5) {
173 memset(&encaps, 0, sizeof(struct sctp_udpencaps));
174 encaps.sue_address.ss_family = AF_INET6;
175 encaps.sue_port = htons(atoi(argv[5]));
176 if (usrsctp_setsockopt(sock, IPPROTO_SCTP, SCTP_REMOTE_UDP_ENCAPS_PORT, (const void *)&encaps, (socklen_t)sizeof(struct sctp_udpencaps)) < 0) {
177 perror("setsockopt");
178 usrsctp_close(sock);
179 result = 3;
180 goto out;
181 }
182 }
183
184 if (argc > 6) {
185#ifdef _WIN32
186 _snprintf(request, sizeof(request), "%s %s %s", request_prefix, argv[6], request_postfix);
187#else
188 snprintf(request, sizeof(request), "%s %s %s", request_prefix, argv[6], request_postfix);
189#endif
190 } else {
191#ifdef _WIN32
192 _snprintf(request, sizeof(request), "%s %s %s", request_prefix, "/", request_postfix);
193#else
194 snprintf(request, sizeof(request), "%s %s %s", request_prefix, "/", request_postfix);
195#endif
196 }
197
198 usrsctp_set_upcall(sock, handle_upcall, NULL);
199
200 memset((void *)&addr4, 0, sizeof(struct sockaddr_in));
201 memset((void *)&addr6, 0, sizeof(struct sockaddr_in6));
202#ifdef HAVE_SIN_LEN
203 addr4.sin_len = sizeof(struct sockaddr_in);
204#endif
205#ifdef HAVE_SIN6_LEN
206 addr6.sin6_len = sizeof(struct sockaddr_in6);
207#endif
208 addr4.sin_family = AF_INET;
209 addr6.sin6_family = AF_INET6;
210 addr4.sin_port = htons(atoi(argv[2]));
211 addr6.sin6_port = htons(atoi(argv[2]));
212 if (inet_pton(AF_INET6, argv[1], &addr6.sin6_addr) == 1) {
213 if (usrsctp_connect(sock, (struct sockaddr *)&addr6, sizeof(struct sockaddr_in6)) < 0) {
214 if (errno != EINPROGRESS) {
215 perror("usrsctp_connect");
216 usrsctp_close(sock);
217 result = 4;
218 goto out;
219 }
220 }
221 } else if (inet_pton(AF_INET, argv[1], &addr4.sin_addr) == 1) {
222 if (usrsctp_connect(sock, (struct sockaddr *)&addr4, sizeof(struct sockaddr_in)) < 0) {
223 if (errno != EINPROGRESS) {
224 perror("usrsctp_connect");
225 usrsctp_close(sock);
226 result = 5;
227 goto out;
228 }
229 }
230 } else {
231 printf("Illegal destination address\n");
232 usrsctp_close(sock);
233 result = 6;
234 goto out;
235 }
236 while (!done) {
237#ifdef _WIN32
238 Sleep(1*1000);
239#else
240 sleep(1);
241#endif
242 }
243out:
244 while (usrsctp_finish() != 0) {
245#ifdef _WIN32
246 Sleep(1000);
247#else
248 sleep(1);
249#endif
250 }
251 return (result);
252}