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.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/* <DESC> 25 * Pass in a custom socket for libcurl to use. 26 * </DESC> 27 */ 28#include <stdio.h> 29#include <string.h> 30#include <stdlib.h> 31#include <curl/curl.h> 32 33#ifdef _WIN32 34#include <winsock2.h> 35#define close closesocket 36#else 37#include <sys/types.h> /* socket types */ 38#include <sys/socket.h> /* socket definitions */ 39#include <netinet/in.h> 40#include <arpa/inet.h> /* inet (3) functions */ 41#include <unistd.h> /* misc. Unix functions */ 42#endif 43 44#include <errno.h> 45 46/* The IP address and port number to connect to */ 47#define IPADDR "127.0.0.1" 48#define PORTNUM 80 49 50#ifndef INADDR_NONE 51#define INADDR_NONE 0xffffffff 52#endif 53 54static size_t write_data(void *ptr, size_t size, size_t nmemb, void *stream) 55{ 56 size_t written = fwrite(ptr, size, nmemb, (FILE *)stream); 57 return written; 58} 59 60static int closecb(void *clientp, curl_socket_t item) 61{ 62 (void)clientp; 63 printf("libcurl wants to close %d now\n", (int)item); 64 return 0; 65} 66 67static curl_socket_t opensocket(void *clientp, 68 curlsocktype purpose, 69 struct curl_sockaddr *address) 70{ 71 curl_socket_t sockfd; 72 (void)purpose; 73 (void)address; 74 sockfd = *(curl_socket_t *)clientp; 75 /* the actual externally set socket is passed in via the OPENSOCKETDATA 76 option */ 77 return sockfd; 78} 79 80static int sockopt_callback(void *clientp, curl_socket_t curlfd, 81 curlsocktype purpose) 82{ 83 (void)clientp; 84 (void)curlfd; 85 (void)purpose; 86 /* This return code was added in libcurl 7.21.5 */ 87 return CURL_SOCKOPT_ALREADY_CONNECTED; 88} 89 90int main(void) 91{ 92 CURL *curl; 93 CURLcode res; 94 struct sockaddr_in servaddr; /* socket address structure */ 95 curl_socket_t sockfd; 96 97#ifdef _WIN32 98 WSADATA wsaData; 99 int initwsa = WSAStartup(MAKEWORD(2, 2), &wsaData); 100 if(initwsa) { 101 printf("WSAStartup failed: %d\n", initwsa); 102 return 1; 103 } 104#endif 105 106 curl = curl_easy_init(); 107 if(curl) { 108 /* 109 * Note that libcurl will internally think that you connect to the host 110 * and port that you specify in the URL option. 111 */ 112 curl_easy_setopt(curl, CURLOPT_URL, "http://99.99.99.99:9999"); 113 114 /* Create the socket "manually" */ 115 sockfd = socket(AF_INET, SOCK_STREAM, 0); 116 if(sockfd == CURL_SOCKET_BAD) { 117 printf("Error creating listening socket.\n"); 118 return 3; 119 } 120 121 memset(&servaddr, 0, sizeof(servaddr)); 122 servaddr.sin_family = AF_INET; 123 servaddr.sin_port = htons(PORTNUM); 124 125 servaddr.sin_addr.s_addr = inet_addr(IPADDR); 126 if(INADDR_NONE == servaddr.sin_addr.s_addr) { 127 close(sockfd); 128 return 2; 129 } 130 131 if(connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) == 132 -1) { 133 close(sockfd); 134 printf("client error: connect: %s\n", strerror(errno)); 135 return 1; 136 } 137 138 /* no progress meter please */ 139 curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1L); 140 141 /* send all data to this function */ 142 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data); 143 144 /* call this function to get a socket */ 145 curl_easy_setopt(curl, CURLOPT_OPENSOCKETFUNCTION, opensocket); 146 curl_easy_setopt(curl, CURLOPT_OPENSOCKETDATA, &sockfd); 147 148 /* call this function to close sockets */ 149 curl_easy_setopt(curl, CURLOPT_CLOSESOCKETFUNCTION, closecb); 150 curl_easy_setopt(curl, CURLOPT_CLOSESOCKETDATA, &sockfd); 151 152 /* call this function to set options for the socket */ 153 curl_easy_setopt(curl, CURLOPT_SOCKOPTFUNCTION, sockopt_callback); 154 155 curl_easy_setopt(curl, CURLOPT_VERBOSE, 1); 156 157 res = curl_easy_perform(curl); 158 159 curl_easy_cleanup(curl); 160 161 close(sockfd); 162 163 if(res) { 164 printf("libcurl error: %d\n", res); 165 return 4; 166 } 167 } 168 169#ifdef _WIN32 170 WSACleanup(); 171#endif 172 return 0; 173} 174