- Frank Hempel found out a bug and provided the fix:
[platform/upstream/curl.git] / lib / easy.c
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2009, 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 http://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  * $Id$
22  ***************************************************************************/
23
24 #include "setup.h"
25
26 /* -- WIN32 approved -- */
27 #include <stdio.h>
28 #include <string.h>
29 #include <stdarg.h>
30 #include <stdlib.h>
31 #include <ctype.h>
32 #include <errno.h>
33
34 #include "strequal.h"
35
36 #ifdef WIN32
37 #include <time.h>
38 #include <io.h>
39 #else
40 #ifdef HAVE_SYS_SOCKET_H
41 #include <sys/socket.h>
42 #endif
43 #ifdef HAVE_NETINET_IN_H
44 #include <netinet/in.h>
45 #endif
46 #ifdef HAVE_SYS_TIME_H
47 #include <sys/time.h>
48 #endif
49 #ifdef HAVE_UNISTD_H
50 #include <unistd.h>
51 #endif
52 #ifdef HAVE_NETDB_H
53 #include <netdb.h>
54 #endif
55 #ifdef HAVE_ARPA_INET_H
56 #include <arpa/inet.h>
57 #endif
58 #ifdef HAVE_NET_IF_H
59 #include <net/if.h>
60 #endif
61 #ifdef HAVE_SYS_IOCTL_H
62 #include <sys/ioctl.h>
63 #endif
64
65 #ifdef HAVE_SYS_PARAM_H
66 #include <sys/param.h>
67 #endif
68
69 #endif  /* WIN32 ... */
70
71 #include "urldata.h"
72 #include <curl/curl.h>
73 #include "transfer.h"
74 #include "sslgen.h"
75 #include "url.h"
76 #include "getinfo.h"
77 #include "hostip.h"
78 #include "share.h"
79 #include "strdup.h"
80 #include "memory.h"
81 #include "progress.h"
82 #include "easyif.h"
83 #include "select.h"
84 #include "sendf.h" /* for failf function prototype */
85 #include "http_ntlm.h"
86 #include "connect.h" /* for Curl_getconnectinfo */
87 #include "slist.h"
88
89 #define _MPRINTF_REPLACE /* use our functions only */
90 #include <curl/mprintf.h>
91
92 #if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV)
93 #include <iconv.h>
94 /* set default codesets for iconv */
95 #ifndef CURL_ICONV_CODESET_OF_NETWORK
96 #define CURL_ICONV_CODESET_OF_NETWORK "ISO8859-1"
97 #endif
98 #ifndef CURL_ICONV_CODESET_FOR_UTF8
99 #define CURL_ICONV_CODESET_FOR_UTF8   "UTF-8"
100 #endif
101 #define ICONV_ERROR  (size_t)-1
102 #endif /* CURL_DOES_CONVERSIONS && HAVE_ICONV */
103
104 /* The last #include file should be: */
105 #include "memdebug.h"
106
107 /* win32_cleanup() is for win32 socket cleanup functionality, the opposite
108    of win32_init() */
109 static void win32_cleanup(void)
110 {
111 #ifdef USE_WINSOCK
112   WSACleanup();
113 #endif
114 #ifdef USE_WINDOWS_SSPI
115   Curl_sspi_global_cleanup();
116 #endif
117 }
118
119 /* win32_init() performs win32 socket initialization to properly setup the
120    stack to allow networking */
121 static CURLcode win32_init(void)
122 {
123 #ifdef USE_WINSOCK
124   WORD wVersionRequested;
125   WSADATA wsaData;
126   int res;
127
128 #if defined(ENABLE_IPV6) && (USE_WINSOCK < 2)
129   Error IPV6_requires_winsock2
130 #endif
131
132   wVersionRequested = MAKEWORD(USE_WINSOCK, USE_WINSOCK);
133
134   res = WSAStartup(wVersionRequested, &wsaData);
135
136   if(res != 0)
137     /* Tell the user that we couldn't find a useable */
138     /* winsock.dll.     */
139     return CURLE_FAILED_INIT;
140
141   /* Confirm that the Windows Sockets DLL supports what we need.*/
142   /* Note that if the DLL supports versions greater */
143   /* than wVersionRequested, it will still return */
144   /* wVersionRequested in wVersion. wHighVersion contains the */
145   /* highest supported version. */
146
147   if( LOBYTE( wsaData.wVersion ) != LOBYTE(wVersionRequested) ||
148        HIBYTE( wsaData.wVersion ) != HIBYTE(wVersionRequested) ) {
149     /* Tell the user that we couldn't find a useable */
150
151     /* winsock.dll. */
152     WSACleanup();
153     return CURLE_FAILED_INIT;
154   }
155   /* The Windows Sockets DLL is acceptable. Proceed. */
156 #endif
157
158 #ifdef USE_WINDOWS_SSPI
159   {
160     CURLcode err = Curl_sspi_global_init();
161     if (err != CURLE_OK)
162       return err;
163   }
164 #endif
165
166   return CURLE_OK;
167 }
168
169 #ifdef USE_LIBIDN
170 /*
171  * Initialise use of IDNA library.
172  * It falls back to ASCII if $CHARSET isn't defined. This doesn't work for
173  * idna_to_ascii_lz().
174  */
175 static void idna_init (void)
176 {
177 #ifdef WIN32
178   char buf[60];
179   UINT cp = GetACP();
180
181   if(!getenv("CHARSET") && cp > 0) {
182     snprintf(buf, sizeof(buf), "CHARSET=cp%u", cp);
183     putenv(buf);
184   }
185 #else
186   /* to do? */
187 #endif
188 }
189 #endif  /* USE_LIBIDN */
190
191 /* true globals -- for curl_global_init() and curl_global_cleanup() */
192 static unsigned int  initialized;
193 static long          init_flags;
194
195 /*
196  * strdup (and other memory functions) is redefined in complicated
197  * ways, but at this point it must be defined as the system-supplied strdup
198  * so the callback pointer is initialized correctly.
199  */
200 #if defined(_WIN32_WCE)
201 #define system_strdup _strdup
202 #elif !defined(HAVE_STRDUP)
203 #define system_strdup curlx_strdup
204 #else
205 #define system_strdup strdup
206 #endif
207
208 #if defined(_MSC_VER) && defined(_DLL)
209 #  pragma warning(disable:4232) /* MSVC extension, dllimport identity */
210 #endif
211
212 #ifndef __SYMBIAN32__
213 /*
214  * If a memory-using function (like curl_getenv) is used before
215  * curl_global_init() is called, we need to have these pointers set already.
216  */
217 curl_malloc_callback Curl_cmalloc = (curl_malloc_callback)malloc;
218 curl_free_callback Curl_cfree = (curl_free_callback)free;
219 curl_realloc_callback Curl_crealloc = (curl_realloc_callback)realloc;
220 curl_strdup_callback Curl_cstrdup = (curl_strdup_callback)system_strdup;
221 curl_calloc_callback Curl_ccalloc = (curl_calloc_callback)calloc;
222 #else
223 /*
224  * Symbian OS doesn't support initialization to code in writeable static data.
225  * Initialization will occur in the curl_global_init() call.
226  */
227 curl_malloc_callback Curl_cmalloc;
228 curl_free_callback Curl_cfree;
229 curl_realloc_callback Curl_crealloc;
230 curl_strdup_callback Curl_cstrdup;
231 curl_calloc_callback Curl_ccalloc;
232 #endif
233
234 #if defined(_MSC_VER) && defined(_DLL)
235 #  pragma warning(default:4232) /* MSVC extension, dllimport identity */
236 #endif
237
238 /**
239  * curl_global_init() globally initializes cURL given a bitwise set of the
240  * different features of what to initialize.
241  */
242 CURLcode curl_global_init(long flags)
243 {
244   if(initialized++)
245     return CURLE_OK;
246
247   /* Setup the default memory functions here (again) */
248   Curl_cmalloc = (curl_malloc_callback)malloc;
249   Curl_cfree = (curl_free_callback)free;
250   Curl_crealloc = (curl_realloc_callback)realloc;
251   Curl_cstrdup = (curl_strdup_callback)system_strdup;
252   Curl_ccalloc = (curl_calloc_callback)calloc;
253
254   if(flags & CURL_GLOBAL_SSL)
255     if(!Curl_ssl_init()) {
256       DEBUGF(fprintf(stderr, "Error: Curl_ssl_init failed\n"));
257       return CURLE_FAILED_INIT;
258     }
259
260   if(flags & CURL_GLOBAL_WIN32)
261     if(win32_init() != CURLE_OK) {
262       DEBUGF(fprintf(stderr, "Error: win32_init failed\n"));
263       return CURLE_FAILED_INIT;
264     }
265
266 #ifdef __AMIGA__
267   if(!amiga_init()) {
268     DEBUGF(fprintf(stderr, "Error: amiga_init failed\n"));
269     return CURLE_FAILED_INIT;
270   }
271 #endif
272
273 #ifdef NETWARE
274   if(netware_init()) {
275     DEBUGF(fprintf(stderr, "Warning: LONG namespace not available\n"));
276   }
277 #endif
278
279 #ifdef USE_LIBIDN
280   idna_init();
281 #endif
282
283   init_flags  = flags;
284
285   return CURLE_OK;
286 }
287
288 /*
289  * curl_global_init_mem() globally initializes cURL and also registers the
290  * user provided callback routines.
291  */
292 CURLcode curl_global_init_mem(long flags, curl_malloc_callback m,
293                               curl_free_callback f, curl_realloc_callback r,
294                               curl_strdup_callback s, curl_calloc_callback c)
295 {
296   CURLcode code = CURLE_OK;
297
298   /* Invalid input, return immediately */
299   if(!m || !f || !r || !s || !c)
300     return CURLE_FAILED_INIT;
301
302   /* Already initialized, don't do it again */
303   if( initialized )
304     return CURLE_OK;
305
306   /* Call the actual init function first */
307   code = curl_global_init(flags);
308   if(code == CURLE_OK) {
309     Curl_cmalloc = m;
310     Curl_cfree = f;
311     Curl_cstrdup = s;
312     Curl_crealloc = r;
313     Curl_ccalloc = c;
314   }
315
316   return code;
317 }
318
319 /**
320  * curl_global_cleanup() globally cleanups cURL, uses the value of
321  * "init_flags" to determine what needs to be cleaned up and what doesn't.
322  */
323 void curl_global_cleanup(void)
324 {
325   if(!initialized)
326     return;
327
328   if(--initialized)
329     return;
330
331   Curl_global_host_cache_dtor();
332
333   if(init_flags & CURL_GLOBAL_SSL)
334     Curl_ssl_cleanup();
335
336   if(init_flags & CURL_GLOBAL_WIN32)
337     win32_cleanup();
338
339 #ifdef __AMIGA__
340   amiga_cleanup();
341 #endif
342
343   init_flags  = 0;
344 }
345
346 /*
347  * curl_easy_init() is the external interface to alloc, setup and init an
348  * easy handle that is returned. If anything goes wrong, NULL is returned.
349  */
350 CURL *curl_easy_init(void)
351 {
352   CURLcode res;
353   struct SessionHandle *data;
354
355   /* Make sure we inited the global SSL stuff */
356   if(!initialized) {
357     res = curl_global_init(CURL_GLOBAL_DEFAULT);
358     if(res) {
359       /* something in the global init failed, return nothing */
360       DEBUGF(fprintf(stderr, "Error: curl_global_init failed\n"));
361       return NULL;
362     }
363   }
364
365   /* We use curl_open() with undefined URL so far */
366   res = Curl_open(&data);
367   if(res != CURLE_OK) {
368     DEBUGF(fprintf(stderr, "Error: Curl_open failed\n"));
369     return NULL;
370   }
371
372   return data;
373 }
374
375 /*
376  * curl_easy_setopt() is the external interface for setting options on an
377  * easy handle.
378  */
379
380 #undef curl_easy_setopt
381 CURLcode curl_easy_setopt(CURL *curl, CURLoption tag, ...)
382 {
383   va_list arg;
384   struct SessionHandle *data = curl;
385   CURLcode ret;
386
387   if(!curl)
388     return CURLE_BAD_FUNCTION_ARGUMENT;
389
390   va_start(arg, tag);
391
392   ret = Curl_setopt(data, tag, arg);
393
394   va_end(arg);
395   return ret;
396 }
397
398 #ifdef CURL_MULTIEASY
399 /***************************************************************************
400  * This function is still only for testing purposes. It makes a great way
401  * to run the full test suite on the multi interface instead of the easy one.
402  ***************************************************************************
403  *
404  * The *new* curl_easy_perform() is the external interface that performs a
405  * transfer previously setup.
406  *
407  * Wrapper-function that: creates a multi handle, adds the easy handle to it,
408  * runs curl_multi_perform() until the transfer is done, then detaches the
409  * easy handle, destroys the multi handle and returns the easy handle's return
410  * code. This will make everything internally use and assume multi interface.
411  */
412 CURLcode curl_easy_perform(CURL *easy)
413 {
414   CURLM *multi;
415   CURLMcode mcode;
416   CURLcode code = CURLE_OK;
417   int still_running;
418   struct timeval timeout;
419   int rc;
420   CURLMsg *msg;
421   fd_set fdread;
422   fd_set fdwrite;
423   fd_set fdexcep;
424   int maxfd;
425
426   if(!easy)
427     return CURLE_BAD_FUNCTION_ARGUMENT;
428
429   multi = curl_multi_init();
430   if(!multi)
431     return CURLE_OUT_OF_MEMORY;
432
433   mcode = curl_multi_add_handle(multi, easy);
434   if(mcode) {
435     curl_multi_cleanup(multi);
436     if(mcode == CURLM_OUT_OF_MEMORY)
437       return CURLE_OUT_OF_MEMORY;
438     else
439       return CURLE_FAILED_INIT;
440   }
441
442   /* we start some action by calling perform right away */
443
444   do {
445     while(CURLM_CALL_MULTI_PERFORM ==
446           curl_multi_perform(multi, &still_running));
447
448     if(!still_running)
449       break;
450
451     FD_ZERO(&fdread);
452     FD_ZERO(&fdwrite);
453     FD_ZERO(&fdexcep);
454
455     /* timeout once per second */
456     timeout.tv_sec = 1;
457     timeout.tv_usec = 0;
458
459     /* Old deprecated style: get file descriptors from the transfers */
460     curl_multi_fdset(multi, &fdread, &fdwrite, &fdexcep, &maxfd);
461     rc = Curl_select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);
462
463     /* The way is to extract the sockets and wait for them without using
464        select. This whole alternative version should probably rather use the
465        curl_multi_socket() approach. */
466
467     if(rc == -1)
468       /* select error */
469       break;
470
471     /* timeout or data to send/receive => loop! */
472   } while(still_running);
473
474   msg = curl_multi_info_read(multi, &rc);
475   if(msg)
476     code = msg->data.result;
477
478   mcode = curl_multi_remove_handle(multi, easy);
479   /* what to do if it fails? */
480
481   mcode = curl_multi_cleanup(multi);
482   /* what to do if it fails? */
483
484   return code;
485 }
486 #else
487 /*
488  * curl_easy_perform() is the external interface that performs a transfer
489  * previously setup.
490  */
491 CURLcode curl_easy_perform(CURL *curl)
492 {
493   struct SessionHandle *data = (struct SessionHandle *)curl;
494
495   if(!data)
496     return CURLE_BAD_FUNCTION_ARGUMENT;
497
498   if( ! (data->share && data->share->hostcache) ) {
499     /* this handle is not using a shared dns cache */
500
501     if(data->set.global_dns_cache &&
502        (data->dns.hostcachetype != HCACHE_GLOBAL)) {
503       /* global dns cache was requested but still isn't */
504       struct curl_hash *ptr;
505
506       if(data->dns.hostcachetype == HCACHE_PRIVATE) {
507         /* if the current cache is private, kill it first */
508         Curl_hash_destroy(data->dns.hostcache);
509         data->dns.hostcachetype = HCACHE_NONE;
510         data->dns.hostcache = NULL;
511       }
512
513       ptr = Curl_global_host_cache_init();
514       if(ptr) {
515         /* only do this if the global cache init works */
516         data->dns.hostcache = ptr;
517         data->dns.hostcachetype = HCACHE_GLOBAL;
518       }
519     }
520
521     if(!data->dns.hostcache) {
522       data->dns.hostcachetype = HCACHE_PRIVATE;
523       data->dns.hostcache = Curl_mk_dnscache();
524
525       if(!data->dns.hostcache)
526         /* While we possibly could survive and do good without a host cache,
527            the fact that creating it failed indicates that things are truly
528            screwed up and we should bail out! */
529         return CURLE_OUT_OF_MEMORY;
530     }
531
532   }
533
534   if(!data->state.connc) {
535     /* oops, no connection cache, make one up */
536     data->state.connc = Curl_mk_connc(CONNCACHE_PRIVATE, -1);
537     if(!data->state.connc)
538       return CURLE_OUT_OF_MEMORY;
539   }
540
541   return Curl_perform(data);
542 }
543 #endif
544
545 /*
546  * curl_easy_cleanup() is the external interface to cleaning/freeing the given
547  * easy handle.
548  */
549 void curl_easy_cleanup(CURL *curl)
550 {
551   struct SessionHandle *data = (struct SessionHandle *)curl;
552
553   if(!data)
554     return;
555
556   Curl_close(data);
557 }
558
559 /*
560  * Store a pointed to the multi handle within the easy handle's data struct.
561  */
562 void Curl_easy_addmulti(struct SessionHandle *data,
563                         void *multi)
564 {
565   data->multi = multi;
566   if(multi == NULL)
567     /* the association is cleared, mark the easy handle as not used by an
568        interface */
569     data->state.used_interface = Curl_if_none;
570 }
571
572 void Curl_easy_initHandleData(struct SessionHandle *data)
573 {
574     memset(&data->req, 0, sizeof(struct SingleRequest));
575
576     data->req.maxdownload = -1;
577 }
578
579 /*
580  * curl_easy_getinfo() is an external interface that allows an app to retrieve
581  * information from a performed transfer and similar.
582  */
583 #undef curl_easy_getinfo
584 CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ...)
585 {
586   va_list arg;
587   void *paramp;
588   struct SessionHandle *data = (struct SessionHandle *)curl;
589
590   va_start(arg, info);
591   paramp = va_arg(arg, void *);
592
593   return Curl_getinfo(data, info, paramp);
594 }
595
596 /*
597  * curl_easy_duphandle() is an external interface to allow duplication of a
598  * given input easy handle. The returned handle will be a new working handle
599  * with all options set exactly as the input source handle.
600  */
601 CURL *curl_easy_duphandle(CURL *incurl)
602 {
603   bool fail = TRUE;
604   struct SessionHandle *data=(struct SessionHandle *)incurl;
605
606   struct SessionHandle *outcurl = calloc(sizeof(struct SessionHandle), 1);
607
608   if(NULL == outcurl)
609     return NULL; /* failure */
610
611   do {
612
613     /*
614      * We setup a few buffers we need. We should probably make them
615      * get setup on-demand in the code, as that would probably decrease
616      * the likeliness of us forgetting to init a buffer here in the future.
617      */
618     outcurl->state.headerbuff = malloc(HEADERSIZE);
619     if(!outcurl->state.headerbuff) {
620       break;
621     }
622     outcurl->state.headersize=HEADERSIZE;
623
624     /* copy all userdefined values */
625     if(Curl_dupset(outcurl, data) != CURLE_OK)
626       break;
627
628     /* the connection cache is setup on demand */
629     outcurl->state.connc = NULL;
630
631     outcurl->state.lastconnect = -1;
632
633     outcurl->progress.flags    = data->progress.flags;
634     outcurl->progress.callback = data->progress.callback;
635
636 #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
637     if(data->cookies) {
638       /* If cookies are enabled in the parent handle, we enable them
639          in the clone as well! */
640       outcurl->cookies = Curl_cookie_init(data,
641                                           data->cookies->filename,
642                                           outcurl->cookies,
643                                           data->set.cookiesession);
644       if(!outcurl->cookies) {
645         break;
646       }
647     }
648 #endif   /* CURL_DISABLE_HTTP */
649
650     /* duplicate all values in 'change' */
651
652 #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
653     if(data->change.cookielist) {
654       outcurl->change.cookielist =
655         Curl_slist_duplicate(data->change.cookielist);
656
657       if (!outcurl->change.cookielist)
658         break;
659     }
660 #endif   /* CURL_DISABLE_HTTP */
661
662     if(data->change.url) {
663       outcurl->change.url = strdup(data->change.url);
664       if(!outcurl->change.url)
665         break;
666       outcurl->change.url_alloc = TRUE;
667     }
668
669     if(data->change.referer) {
670       outcurl->change.referer = strdup(data->change.referer);
671       if(!outcurl->change.referer)
672         break;
673       outcurl->change.referer_alloc = TRUE;
674     }
675
676 #ifdef USE_ARES
677     /* If we use ares, we setup a new ares channel for the new handle */
678     if(ARES_SUCCESS != ares_init(&outcurl->state.areschannel))
679       break;
680 #endif
681
682 #if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV)
683     outcurl->inbound_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
684                                      CURL_ICONV_CODESET_OF_NETWORK);
685     outcurl->outbound_cd = iconv_open(CURL_ICONV_CODESET_OF_NETWORK,
686                                       CURL_ICONV_CODESET_OF_HOST);
687     outcurl->utf8_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
688                                   CURL_ICONV_CODESET_FOR_UTF8);
689 #endif
690
691     Curl_easy_initHandleData(outcurl);
692
693     outcurl->magic = CURLEASY_MAGIC_NUMBER;
694
695     fail = FALSE; /* we reach this point and thus we are OK */
696
697   } while(0);
698
699   if(fail) {
700     if(outcurl) {
701       if(outcurl->state.connc &&
702          (outcurl->state.connc->type == CONNCACHE_PRIVATE))
703         Curl_rm_connc(outcurl->state.connc);
704       if(outcurl->state.headerbuff)
705         free(outcurl->state.headerbuff);
706 #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
707       if(outcurl->change.cookielist)
708         curl_slist_free_all(outcurl->change.cookielist);
709 #endif
710       if(outcurl->change.url)
711         free(outcurl->change.url);
712       if(outcurl->change.referer)
713         free(outcurl->change.referer);
714       Curl_freeset(outcurl);
715       free(outcurl); /* free the memory again */
716       outcurl = NULL;
717     }
718   }
719
720   return outcurl;
721 }
722
723 /*
724  * curl_easy_reset() is an external interface that allows an app to re-
725  * initialize a session handle to the default values.
726  */
727 void curl_easy_reset(CURL *curl)
728 {
729   struct SessionHandle *data = (struct SessionHandle *)curl;
730
731   Curl_safefree(data->state.pathbuffer);
732   data->state.pathbuffer=NULL;
733
734   Curl_safefree(data->state.proto.generic);
735   data->state.proto.generic=NULL;
736
737   /* zero out UserDefined data: */
738   Curl_freeset(data);
739   memset(&data->set, 0, sizeof(struct UserDefined));
740   (void)Curl_init_userdefined(&data->set);
741
742   /* zero out Progress data: */
743   memset(&data->progress, 0, sizeof(struct Progress));
744
745   /* init Handle data */
746   Curl_easy_initHandleData(data);
747
748   data->progress.flags |= PGRS_HIDE;
749   data->state.current_speed = -1; /* init to negative == impossible */
750 }
751
752 /*
753  * curl_easy_pause() allows an application to pause or unpause a specific
754  * transfer and direction. This function sets the full new state for the
755  * current connection this easy handle operates on.
756  *
757  * NOTE: if you have the receiving paused and you call this function to remove
758  * the pausing, you may get your write callback called at this point.
759  *
760  * Action is a bitmask consisting of CURLPAUSE_* bits in curl/curl.h
761  */
762 CURLcode curl_easy_pause(CURL *curl, int action)
763 {
764   struct SessionHandle *data = (struct SessionHandle *)curl;
765   struct SingleRequest *k = &data->req;
766   CURLcode result = CURLE_OK;
767
768   /* first switch off both pause bits */
769   int newstate = k->keepon &~ (KEEP_READ_PAUSE| KEEP_WRITE_PAUSE);
770
771   /* set the new desired pause bits */
772   newstate |= ((action & CURLPAUSE_RECV)?KEEP_READ_PAUSE:0) |
773     ((action & CURLPAUSE_SEND)?KEEP_WRITE_PAUSE:0);
774
775   /* put it back in the keepon */
776   k->keepon = newstate;
777
778   if(!(newstate & KEEP_READ_PAUSE) && data->state.tempwrite) {
779     /* we have a buffer for writing that we now seem to be able to deliver since
780        the receive pausing is lifted! */
781
782     /* get the pointer, type and length in local copies since the function may
783        return PAUSE again and then we'll get a new copy allocted and stored in
784        the tempwrite variables */
785     char *tempwrite = data->state.tempwrite;
786     char *freewrite = tempwrite; /* store this pointer to free it later */
787     size_t tempsize = data->state.tempwritesize;
788     int temptype = data->state.tempwritetype;
789     size_t chunklen;
790
791     /* clear tempwrite here just to make sure it gets cleared if there's no
792        further use of it, and make sure we don't clear it after the function
793        invoke as it may have been set to a new value by then */
794     data->state.tempwrite = NULL;
795
796     /* since the write callback API is define to never exceed
797        CURL_MAX_WRITE_SIZE bytes in a single call, and since we may in fact
798        have more data than that in our buffer here, we must loop sending the
799        data in multiple calls until there's no data left or we get another
800        pause returned.
801
802        A tricky part is that the function we call will "buffer" the data
803        itself when it pauses on a particular buffer, so we may need to do some
804        extra trickery if we get a pause return here.
805     */
806     do {
807       chunklen = (tempsize > CURL_MAX_WRITE_SIZE)?CURL_MAX_WRITE_SIZE:tempsize;
808
809       result = Curl_client_write(data->state.current_conn,
810                                  temptype, tempwrite, chunklen);
811       if(result)
812         /* failures abort the loop at once */
813         break;
814
815       if(data->state.tempwrite && (tempsize - chunklen)) {
816         /* Ouch, the reading is again paused and the block we send is now
817            "cached". If this is the final chunk we can leave it like this, but
818            if we have more chunks that are cached after this, we need to free
819            the newly cached one and put back a version that is truly the entire
820            contents that is saved for later
821         */
822         char *newptr;
823
824         /* note that tempsize is still the size as before the callback was
825            used, and thus the whole piece of data to keep */
826         newptr = realloc(data->state.tempwrite, tempsize);
827
828         if(!newptr) {
829           free(data->state.tempwrite); /* free old area */
830           data->state.tempwrite = NULL;
831           result = CURLE_OUT_OF_MEMORY;
832           /* tempwrite will be freed further down */
833           break;
834         }
835         data->state.tempwrite = newptr; /* store new pointer */
836         memcpy(newptr, tempwrite, tempsize);
837         data->state.tempwritesize = tempsize; /* store new size */
838         /* tempwrite will be freed further down */
839         break; /* go back to pausing until further notice */
840       }
841       else {
842         tempsize -= chunklen;  /* left after the call above */
843         tempwrite += chunklen; /* advance the pointer */
844       }
845
846     } while((result == CURLE_OK) && tempsize);
847
848     free(freewrite); /* this is unconditionally no longer used */
849   }
850
851   return result;
852 }
853
854 #ifdef CURL_DOES_CONVERSIONS
855 /*
856  * Curl_convert_to_network() is an internal function
857  * for performing ASCII conversions on non-ASCII platforms.
858  */
859 CURLcode Curl_convert_to_network(struct SessionHandle *data,
860                                  char *buffer, size_t length)
861 {
862   CURLcode rc;
863
864   if(data->set.convtonetwork) {
865     /* use translation callback */
866     rc = data->set.convtonetwork(buffer, length);
867     if(rc != CURLE_OK) {
868       failf(data,
869             "CURLOPT_CONV_TO_NETWORK_FUNCTION callback returned %i: %s",
870             rc, curl_easy_strerror(rc));
871     }
872     return(rc);
873   } else {
874 #ifdef HAVE_ICONV
875     /* do the translation ourselves */
876     char *input_ptr, *output_ptr;
877     size_t in_bytes, out_bytes, rc;
878     int error;
879
880     /* open an iconv conversion descriptor if necessary */
881     if(data->outbound_cd == (iconv_t)-1) {
882       data->outbound_cd = iconv_open(CURL_ICONV_CODESET_OF_NETWORK,
883                                      CURL_ICONV_CODESET_OF_HOST);
884       if(data->outbound_cd == (iconv_t)-1) {
885         error = ERRNO;
886         failf(data,
887               "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s",
888                CURL_ICONV_CODESET_OF_NETWORK,
889                CURL_ICONV_CODESET_OF_HOST,
890                error, strerror(error));
891         return CURLE_CONV_FAILED;
892       }
893     }
894     /* call iconv */
895     input_ptr = output_ptr = buffer;
896     in_bytes = out_bytes = length;
897     rc = iconv(data->outbound_cd, (const char**)&input_ptr, &in_bytes,
898                &output_ptr, &out_bytes);
899     if((rc == ICONV_ERROR) || (in_bytes != 0)) {
900       error = ERRNO;
901       failf(data,
902         "The Curl_convert_to_network iconv call failed with errno %i: %s",
903              error, strerror(error));
904       return CURLE_CONV_FAILED;
905     }
906 #else
907     failf(data, "CURLOPT_CONV_TO_NETWORK_FUNCTION callback required");
908     return CURLE_CONV_REQD;
909 #endif /* HAVE_ICONV */
910   }
911
912   return CURLE_OK;
913 }
914
915 /*
916  * Curl_convert_from_network() is an internal function
917  * for performing ASCII conversions on non-ASCII platforms.
918  */
919 CURLcode Curl_convert_from_network(struct SessionHandle *data,
920                                       char *buffer, size_t length)
921 {
922   CURLcode rc;
923
924   if(data->set.convfromnetwork) {
925     /* use translation callback */
926     rc = data->set.convfromnetwork(buffer, length);
927     if(rc != CURLE_OK) {
928       failf(data,
929             "CURLOPT_CONV_FROM_NETWORK_FUNCTION callback returned %i: %s",
930             rc, curl_easy_strerror(rc));
931     }
932     return(rc);
933   }
934   else {
935 #ifdef HAVE_ICONV
936     /* do the translation ourselves */
937     char *input_ptr, *output_ptr;
938     size_t in_bytes, out_bytes, rc;
939     int error;
940
941     /* open an iconv conversion descriptor if necessary */
942     if(data->inbound_cd == (iconv_t)-1) {
943       data->inbound_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
944                                     CURL_ICONV_CODESET_OF_NETWORK);
945       if(data->inbound_cd == (iconv_t)-1) {
946         error = ERRNO;
947         failf(data,
948               "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s",
949               CURL_ICONV_CODESET_OF_HOST,
950               CURL_ICONV_CODESET_OF_NETWORK,
951               error, strerror(error));
952         return CURLE_CONV_FAILED;
953       }
954     }
955     /* call iconv */
956     input_ptr = output_ptr = buffer;
957     in_bytes = out_bytes = length;
958     rc = iconv(data->inbound_cd, (const char **)&input_ptr, &in_bytes,
959                &output_ptr, &out_bytes);
960     if((rc == ICONV_ERROR) || (in_bytes != 0)) {
961       error = ERRNO;
962       failf(data,
963             "The Curl_convert_from_network iconv call failed with errno %i: %s",
964             error, strerror(error));
965       return CURLE_CONV_FAILED;
966     }
967 #else
968     failf(data, "CURLOPT_CONV_FROM_NETWORK_FUNCTION callback required");
969     return CURLE_CONV_REQD;
970 #endif /* HAVE_ICONV */
971   }
972
973   return CURLE_OK;
974 }
975
976 /*
977  * Curl_convert_from_utf8() is an internal function
978  * for performing UTF-8 conversions on non-ASCII platforms.
979  */
980 CURLcode Curl_convert_from_utf8(struct SessionHandle *data,
981                                      char *buffer, size_t length)
982 {
983   CURLcode rc;
984
985   if(data->set.convfromutf8) {
986     /* use translation callback */
987     rc = data->set.convfromutf8(buffer, length);
988     if(rc != CURLE_OK) {
989       failf(data,
990             "CURLOPT_CONV_FROM_UTF8_FUNCTION callback returned %i: %s",
991             rc, curl_easy_strerror(rc));
992     }
993     return(rc);
994   } else {
995 #ifdef HAVE_ICONV
996     /* do the translation ourselves */
997     const char *input_ptr;
998     char *output_ptr;
999     size_t in_bytes, out_bytes, rc;
1000     int error;
1001
1002     /* open an iconv conversion descriptor if necessary */
1003     if(data->utf8_cd == (iconv_t)-1) {
1004       data->utf8_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
1005                                  CURL_ICONV_CODESET_FOR_UTF8);
1006       if(data->utf8_cd == (iconv_t)-1) {
1007         error = ERRNO;
1008         failf(data,
1009               "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s",
1010               CURL_ICONV_CODESET_OF_HOST,
1011               CURL_ICONV_CODESET_FOR_UTF8,
1012               error, strerror(error));
1013         return CURLE_CONV_FAILED;
1014       }
1015     }
1016     /* call iconv */
1017     input_ptr = output_ptr = buffer;
1018     in_bytes = out_bytes = length;
1019     rc = iconv(data->utf8_cd, &input_ptr, &in_bytes,
1020                &output_ptr, &out_bytes);
1021     if((rc == ICONV_ERROR) || (in_bytes != 0)) {
1022       error = ERRNO;
1023       failf(data,
1024             "The Curl_convert_from_utf8 iconv call failed with errno %i: %s",
1025             error, strerror(error));
1026       return CURLE_CONV_FAILED;
1027     }
1028     if(output_ptr < input_ptr) {
1029       /* null terminate the now shorter output string */
1030       *output_ptr = 0x00;
1031     }
1032 #else
1033     failf(data, "CURLOPT_CONV_FROM_UTF8_FUNCTION callback required");
1034     return CURLE_CONV_REQD;
1035 #endif /* HAVE_ICONV */
1036   }
1037
1038   return CURLE_OK;
1039 }
1040
1041 #endif /* CURL_DOES_CONVERSIONS */
1042
1043 static CURLcode easy_connection(struct SessionHandle *data,
1044                                 curl_socket_t *sfd,
1045                                 struct connectdata **connp)
1046 {
1047   CURLcode ret;
1048   long sockfd;
1049
1050   if(data == NULL)
1051     return CURLE_BAD_FUNCTION_ARGUMENT;
1052
1053   /* only allow these to be called on handles with CURLOPT_CONNECT_ONLY */
1054   if(!data->set.connect_only) {
1055     failf(data, "CONNECT_ONLY is required!");
1056     return CURLE_UNSUPPORTED_PROTOCOL;
1057   }
1058
1059   ret = Curl_getconnectinfo(data, &sockfd, connp);
1060   if(ret != CURLE_OK)
1061     return ret;
1062
1063   if(sockfd == -1) {
1064     failf(data, "Failed to get recent socket");
1065     return CURLE_UNSUPPORTED_PROTOCOL;
1066   }
1067
1068   *sfd = (curl_socket_t)sockfd; /* we know that this is actually a socket
1069                                    descriptor so the typecast is fine here */
1070
1071   return CURLE_OK;
1072 }
1073
1074 /*
1075  * Receives data from the connected socket. Use after successful
1076  * curl_easy_perform() with CURLOPT_CONNECT_ONLY option.
1077  * Returns CURLE_OK on success, error code on error.
1078  */
1079 CURLcode curl_easy_recv(CURL *curl, void *buffer, size_t buflen, size_t *n)
1080 {
1081   curl_socket_t sfd;
1082   CURLcode ret;
1083   int ret1;
1084   ssize_t n1;
1085   struct connectdata *c;
1086   struct SessionHandle *data = (struct SessionHandle *)curl;
1087
1088   ret = easy_connection(data, &sfd, &c);
1089   if(ret)
1090     return ret;
1091
1092   *n = 0;
1093   ret1 = Curl_read(c, sfd, buffer, buflen, &n1);
1094
1095   if(ret1 == -1)
1096     return CURLE_AGAIN;
1097
1098   if(n1 == -1)
1099     return CURLE_RECV_ERROR;
1100
1101   *n = (size_t)n1;
1102
1103   return CURLE_OK;
1104 }
1105
1106 /*
1107  * Sends data over the connected socket. Use after successful
1108  * curl_easy_perform() with CURLOPT_CONNECT_ONLY option.
1109  */
1110 CURLcode curl_easy_send(CURL *curl, const void *buffer, size_t buflen,
1111                         size_t *n)
1112 {
1113   curl_socket_t sfd;
1114   CURLcode ret;
1115   ssize_t n1;
1116   struct connectdata *c = NULL;
1117   struct SessionHandle *data = (struct SessionHandle *)curl;
1118
1119   ret = easy_connection(data, &sfd, &c);
1120   if(ret)
1121     return ret;
1122
1123   *n = 0;
1124   ret = Curl_write(c, sfd, buffer, buflen, &n1);
1125
1126   if(n1 == -1)
1127     return CURLE_SEND_ERROR;
1128
1129   /* detect EAGAIN */
1130   if((CURLE_OK == ret) && (0 == n1))
1131     return CURLE_AGAIN;
1132
1133   *n = (size_t)n1;
1134
1135   return ret;
1136 }