1/*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. 9 * 10 * This software is licensed as described in the file COPYING, which 11 * you should have received as part of this distribution. The terms 12 * are also available at https://curl.haxx.se/docs/copyright.html. 13 * 14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell 15 * copies of the Software, and permit persons to whom the Software is 16 * furnished to do so, under the terms of the COPYING file. 17 * 18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 19 * KIND, either express or implied. 20 * 21 * SPDX-License-Identifier: curl 22 * 23 ***************************************************************************/ 24#include "test.h" 25 26#ifdef HAVE_INET_PTON 27 28#ifdef HAVE_NETINET_IN_H 29#include <netinet/in.h> 30#endif 31#ifdef HAVE_SYS_SOCKET_H 32#include <sys/socket.h> 33#endif 34#ifdef HAVE_ARPA_INET_H 35#include <arpa/inet.h> 36#endif 37 38#include "memdebug.h" 39 40/* to prevent libcurl from closing our socket */ 41static int closesocket_cb(void *clientp, curl_socket_t item) 42{ 43 (void)clientp; 44 (void)item; 45 return 0; 46} 47 48/* provide our own socket */ 49static curl_socket_t socket_cb(void *clientp, 50 curlsocktype purpose, 51 struct curl_sockaddr *address) 52{ 53 int s = *(int *)clientp; 54 (void)purpose; 55 (void)address; 56 return (curl_socket_t)s; 57} 58 59/* tell libcurl the socket is connected */ 60static int sockopt_cb(void *clientp, 61 curl_socket_t curlfd, 62 curlsocktype purpose) 63{ 64 (void)clientp; 65 (void)curlfd; 66 (void)purpose; 67 return CURL_SOCKOPT_ALREADY_CONNECTED; 68} 69 70/* Expected args: URL IP PORT */ 71int test(char *URL) 72{ 73 CURL *curl = NULL; 74 CURLcode res = TEST_ERR_MAJOR_BAD; 75 int status; 76 curl_socket_t client_fd = CURL_SOCKET_BAD; 77 struct sockaddr_in serv_addr; 78 unsigned short port; 79 80 if(!strcmp("check", URL)) 81 return 0; /* no output makes it not skipped */ 82 83 port = (unsigned short)atoi(libtest_arg3); 84 85 if(curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) { 86 fprintf(stderr, "curl_global_init() failed\n"); 87 return TEST_ERR_MAJOR_BAD; 88 } 89 90 /* 91 * This code connects to the TCP port "manually" so that we then can hand 92 * over this socket as "already connected" to libcurl and make sure that 93 * this works. 94 */ 95 client_fd = socket(AF_INET, SOCK_STREAM, 0); 96 if(client_fd == CURL_SOCKET_BAD) { 97 fprintf(stderr, "socket creation error\n"); 98 goto test_cleanup; 99 } 100 101 serv_addr.sin_family = AF_INET; 102 serv_addr.sin_port = htons(port); 103 104 if(inet_pton(AF_INET, libtest_arg2, &serv_addr.sin_addr) <= 0) { 105 fprintf(stderr, "inet_pton failed\n"); 106 goto test_cleanup; 107 } 108 109 status = connect(client_fd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)); 110 if(status < 0) { 111 fprintf(stderr, "connection failed\n"); 112 goto test_cleanup; 113 } 114 115 curl = curl_easy_init(); 116 if(!curl) { 117 fprintf(stderr, "curl_easy_init() failed\n"); 118 goto test_cleanup; 119 } 120 121 test_setopt(curl, CURLOPT_VERBOSE, 1L); 122 test_setopt(curl, CURLOPT_OPENSOCKETFUNCTION, socket_cb); 123 test_setopt(curl, CURLOPT_OPENSOCKETDATA, &client_fd); 124 test_setopt(curl, CURLOPT_SOCKOPTFUNCTION, sockopt_cb); 125 test_setopt(curl, CURLOPT_SOCKOPTDATA, NULL); 126 test_setopt(curl, CURLOPT_CLOSESOCKETFUNCTION, closesocket_cb); 127 test_setopt(curl, CURLOPT_CLOSESOCKETDATA, NULL); 128 test_setopt(curl, CURLOPT_VERBOSE, 1L); 129 test_setopt(curl, CURLOPT_HEADER, 1L); 130 test_setopt(curl, CURLOPT_URL, URL); 131 132 res = curl_easy_perform(curl); 133 134test_cleanup: 135 if(client_fd != CURL_SOCKET_BAD) 136 sclose(client_fd); 137 curl_easy_cleanup(curl); 138 curl_global_cleanup(); 139 140 return res; 141} 142#else 143int test(char *URL) 144{ 145 (void)URL; 146 printf("lacks inet_pton\n"); 147 return 0; 148} 149#endif 150