http_client.c 9.0 KB

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