• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
write_data(void * ptr,size_t size,size_t nmemb,void * stream)54 static 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 
closecb(void * clientp,curl_socket_t item)60 static 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 
opensocket(void * clientp,curlsocktype purpose,struct curl_sockaddr * address)67 static 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 
sockopt_callback(void * clientp,curl_socket_t curlfd,curlsocktype purpose)80 static 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 
main(void)90 int 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