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