dos2unix'd the file
[curltunnel.git] / libcurl_tunnel.c
blobacd26ebc9cf47c612c2e736138a596e54e5018b0
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <sys/select.h>
4 #include <curl/curl.h>
5 #include <getopt.h>
6 #include <unistd.h>
8 #define _FILE_OFFSET_BITS 64 /* for curl_off_t magic */
9 #define SIZE 655536
11 #define VERSION "0.1-dev"
13 struct gengetopt_args_info {
14 char *proxy_arg;
15 char *user_arg;
16 char *dest_arg;
18 int help_given;
19 int verbose_given;
20 int user_given;
21 int proxy_given;
22 int dest_given;
25 static void print_options(void)
27 printf("curltunnel\nCopyright 2007 curltunnel Project\nV " VERSION "\n"
28 "\n"
29 "-h --help Print help and exit\n"
30 "-p --proxy=STRING Proxy host:port combination to connect to\n"
31 "-u --user=STRING User:Password combination to send to proxy\n"
32 "-d --dest=STRING Host:port combination to tunnel to\n"
33 "-v --verbose Print messages about what's going on\n");
36 static char * gengetopt_strdup(char *s)
38 char *n, *pn, *ps=s;
39 while(*ps) ps++;
40 n=(char *)malloc(1+ps-s);
41 if(n!=NULL)
43 for(ps=s,pn=n;*ps;ps++,pn++)
44 *pn = *ps;
45 *pn=0;
47 return n;
50 static int command_line_parser(int argc, char * const *argv, struct gengetopt_args_info *args_info)
52 int c;
54 #define clear_args()\
56 args_info->help_given = 0;\
57 args_info->verbose_given = 0;\
58 args_info->user_given = 0;\
59 args_info->proxy_given = 0;\
60 args_info->dest_given = 0;\
61 args_info->proxy_arg = NULL;\
62 args_info->user_arg = NULL;\
63 args_info->dest_arg = NULL;\
65 clear_args();
67 optarg = 0;
68 optind = 1;
69 opterr = 1;
70 optopt = '?';
72 while(1)
74 int option_index = 0;
76 static struct option long_options[] = {
77 { "help", 0, NULL, 'h' },
78 { "verbose", 0, NULL, 'v' },
79 { "proxy", 1, NULL, 'p' },
80 { "user", 1, NULL, 'u' },
81 { "dest", 1, NULL, 'd' },
82 { NULL, 0, NULL, 0}
85 c = getopt_long(argc,argv,"hvp:u:d:", long_options, &option_index);
87 if(c==-1) break;
89 switch(c)
91 case 'h':
92 clear_args();
93 print_options();
94 exit(0);
95 case 'v':
96 args_info->verbose_given = !(args_info->verbose_given);
97 if(args_info->verbose_given)
98 printf("Verbose mode on\n");
99 break;
100 case 'p':
101 if(args_info->proxy_given)
103 fprintf(stderr,"curltunnel: `--proxy' (`-p') option given more than once\n");
104 clear_args();
105 exit(1);
107 args_info->proxy_given = 1;
108 args_info->proxy_arg = gengetopt_strdup(optarg);
109 break;
110 case 'u':
111 if(args_info->user_given)
113 fprintf(stderr,"curltunnel: `--user' (`-u') option given more than once\n");
114 clear_args();
115 exit(1);
117 args_info->user_given = 1;
118 args_info->user_arg = gengetopt_strdup(optarg);
119 break;
120 case 'd':
121 if(args_info->dest_given)
123 fprintf(stderr,"curltunnel: `--dest' (`-d') option given more than once\n");
124 clear_args();
125 exit(1);
127 args_info->dest_given = 1;
128 args_info->dest_arg = gengetopt_strdup(optarg);
129 break;
133 if(!args_info->proxy_given || !args_info->dest_given)
135 clear_args();
136 print_options();
137 exit(0);
140 return 0;
143 static int fd_read(int fd, void *buf, size_t len)
145 int bytes_read;
146 bytes_read = read(fd,buf,len);
147 return bytes_read;
150 static int fd_write(int fd, void *buf, size_t len)
152 int bytes_written;
153 bytes_written = write(fd,buf,len);
154 return bytes_written;
157 static int fdcopy(int fdin, int fdout)
159 char buf[SIZE];
160 int n;
162 if((n=fd_read(fdin,buf,SIZE))<0)
164 fprintf(stderr,"Read Error\n");
165 exit(1);
168 if(n==0)
169 return 1;
171 if(fd_write(fdout,buf,n)!=n)
173 fprintf(stderr,"Write Error\n");
174 exit(1);
177 return 0;
180 static void wait_and_act(int sockfd, int verbose)
182 struct timeval timeout;
183 int rc; /* select() return code */
184 long timeout_ms = 10000;
186 fd_set fdread;
187 fd_set fdwrite;
188 fd_set fdexcep;
189 int maxfd=sockfd;
191 while(1==1)
193 FD_ZERO(&fdread);
194 FD_ZERO(&fdwrite);
195 FD_ZERO(&fdexcep);
197 /* set timeout to wait */
198 timeout.tv_sec = timeout_ms/1000;
199 timeout.tv_usec = (timeout_ms%1000)*1000;
201 FD_SET(fileno(stdin), &fdread);
202 FD_SET(sockfd, &fdread);
203 /* FD_SET(sockfd, &fdwrite); */
205 rc = select(maxfd+1,
206 (fd_set *)&fdread,
207 (fd_set *)&fdwrite,
208 (fd_set *)&fdexcep, &timeout);
210 if(rc==-1) {
211 /* select error */
212 fprintf(stderr,"select() error\n");
213 break;
215 if(rc==0){
216 /* timeout! */
217 /* fprintf(stderr,"Timeout\n"); */
218 if(verbose)
219 fprintf(stderr,"VERBOSE: Timeout after %ldms\n", timeout_ms);
221 else
223 /* use FD_ISSET() to check what happened, then read/write accordingly */
224 if (FD_ISSET(fileno(stdin), &fdread))
226 rc=fdcopy(fileno(stdin),sockfd);
227 if(!rc)
228 break;
229 if(verbose)
230 fprintf(stderr,"VERBOSE: Sent %d bytes from stdin to socket\n", rc);
232 if (FD_ISSET(sockfd,&fdread))
234 rc=fdcopy(sockfd,fileno(stdout));
235 if(!rc)
236 break;
237 if(verbose)
238 fprintf(stderr,"VERBOSE: Sent %d bytes from socket to stdin\n", rc);
244 int main(int argc, char *argv[])
246 CURLcode ret;
247 long sckt;
248 struct gengetopt_args_info args_info;
250 command_line_parser(argc,argv,&args_info);
252 CURL *hnd = curl_easy_init();
254 curl_easy_setopt(hnd, CURLOPT_URL, args_info.dest_arg);
255 curl_easy_setopt(hnd, CURLOPT_PROXY, args_info.proxy_arg);
256 curl_easy_setopt(hnd, CURLOPT_PROXYUSERPWD, args_info.user_arg);
257 curl_easy_setopt(hnd, CURLOPT_USERAGENT, "curltunnel/" VERSION);
258 curl_easy_setopt(hnd, CURLOPT_HTTPPROXYTUNNEL, 1);
259 curl_easy_setopt(hnd, CURLOPT_CONNECT_ONLY, 1);
260 if(args_info.verbose_given)
261 curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1);
262 ret = curl_easy_perform(hnd);
264 if(ret == CURLE_OK)
266 /* Extract socket, and select() */
267 ret = curl_easy_getinfo(hnd, CURLINFO_LASTSOCKET, &sckt);
269 if((sckt==-1) || ret){
270 fprintf(stderr,"[ERR] Couldn't get socket");
271 return 1;
274 wait_and_act((int)sckt, args_info.verbose_given);
276 curl_easy_cleanup(hnd);
277 return 0;