1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2008, Daniel Stenberg, <daniel@haxx.se>, et al.
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.
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.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 * $Id: easy.c,v 1.1.1.1 2008-09-23 16:32:05 hoffman Exp $
22 ***************************************************************************/
26 /* -- WIN32 approved -- */
40 #ifdef HAVE_SYS_SOCKET_H
41 #include <sys/socket.h>
43 #ifdef HAVE_NETINET_IN_H
44 #include <netinet/in.h>
46 #ifdef HAVE_SYS_TIME_H
55 #ifdef HAVE_ARPA_INET_H
56 #include <arpa/inet.h>
61 #ifdef HAVE_SYS_IOCTL_H
62 #include <sys/ioctl.h>
66 #ifdef HAVE_SYS_PARAM_H
67 #include <sys/param.h>
70 #endif /* WIN32 ... */
73 #include <curl/curl.h>
85 #include "sendf.h" /* for failf function prototype */
86 #include "http_ntlm.h"
87 #include "connect.h" /* for Curl_getconnectinfo */
89 #define _MPRINTF_REPLACE /* use our functions only */
90 #include <curl/mprintf.h>
92 #if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV)
94 /* set default codesets for iconv */
95 #ifndef CURL_ICONV_CODESET_OF_NETWORK
96 #define CURL_ICONV_CODESET_OF_NETWORK "ISO8859-1"
98 #ifndef CURL_ICONV_CODESET_FOR_UTF8
99 #define CURL_ICONV_CODESET_FOR_UTF8 "UTF-8"
101 #define ICONV_ERROR (size_t)-1
102 #endif /* CURL_DOES_CONVERSIONS && HAVE_ICONV */
104 /* The last #include file should be: */
105 #include "memdebug.h"
107 /* win32_cleanup() is for win32 socket cleanup functionality, the opposite
109 static void win32_cleanup(void)
114 #ifdef USE_WINDOWS_SSPI
115 Curl_ntlm_global_cleanup();
119 /* win32_init() performs win32 socket initialization to properly setup the
120 stack to allow networking */
121 static CURLcode
win32_init(void)
124 WORD wVersionRequested
;
128 #if defined(ENABLE_IPV6) && (USE_WINSOCK < 2)
129 Error IPV6_requires_winsock2
132 wVersionRequested
= MAKEWORD(USE_WINSOCK
, USE_WINSOCK
);
134 err
= WSAStartup(wVersionRequested
, &wsaData
);
137 /* Tell the user that we couldn't find a useable */
139 return CURLE_FAILED_INIT
;
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. */
147 if( LOBYTE( wsaData
.wVersion
) != LOBYTE(wVersionRequested
) ||
148 HIBYTE( wsaData
.wVersion
) != HIBYTE(wVersionRequested
) ) {
149 /* Tell the user that we couldn't find a useable */
153 return CURLE_FAILED_INIT
;
155 /* The Windows Sockets DLL is acceptable. Proceed. */
158 #ifdef USE_WINDOWS_SSPI
160 CURLcode err
= Curl_ntlm_global_init();
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().
175 static void idna_init (void)
181 if(!getenv("CHARSET") && cp
> 0) {
182 snprintf(buf
, sizeof(buf
), "CHARSET=cp%u", cp
);
189 #endif /* USE_LIBIDN */
191 /* true globals -- for curl_global_init() and curl_global_cleanup() */
192 static unsigned int initialized
;
193 static long init_flags
;
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.
200 #if defined(_WIN32_WCE)
201 #define system_strdup _strdup
202 #elif !defined(HAVE_STRDUP)
203 #define system_strdup curlx_strdup
205 #define system_strdup strdup
208 #if defined(_MSC_VER) && defined(_DLL)
209 # pragma warning(disable:4232) /* MSVC extension, dllimport identity */
212 #ifndef __SYMBIAN32__
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.
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
;
224 * Symbian OS doesn't support initialization to code in writeable static data.
225 * Initialization will occur in the curl_global_init() call.
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
;
234 #if defined(_MSC_VER) && defined(_DLL)
235 # pragma warning(default:4232) /* MSVC extension, dllimport identity */
239 * curl_global_init() globally initializes cURL given a bitwise set of the
240 * different features of what to initialize.
242 CURLcode
curl_global_init(long flags
)
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
;
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
;
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
;
268 DEBUGF(fprintf(stderr
, "Error: amiga_init failed\n"));
269 return CURLE_FAILED_INIT
;
275 DEBUGF(fprintf(stderr
, "Warning: LONG namespace not available\n"));
289 * curl_global_init_mem() globally initializes cURL and also registers the
290 * user provided callback routines.
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
)
296 CURLcode code
= CURLE_OK
;
298 /* Invalid input, return immediately */
299 if(!m
|| !f
|| !r
|| !s
|| !c
)
300 return CURLE_FAILED_INIT
;
302 /* Already initialized, don't do it again */
306 /* Call the actual init function first */
307 code
= curl_global_init(flags
);
308 if(code
== CURLE_OK
) {
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.
323 void curl_global_cleanup(void)
331 Curl_global_host_cache_dtor();
333 if(init_flags
& CURL_GLOBAL_SSL
)
336 if(init_flags
& CURL_GLOBAL_WIN32
)
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.
350 CURL
*curl_easy_init(void)
353 struct SessionHandle
*data
;
355 /* Make sure we inited the global SSL stuff */
357 res
= curl_global_init(CURL_GLOBAL_DEFAULT
);
359 /* something in the global init failed, return nothing */
360 DEBUGF(fprintf(stderr
, "Error: curl_global_init failed\n"));
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"));
376 * curl_easy_setopt() is the external interface for setting options on an
380 #undef curl_easy_setopt
381 CURLcode
curl_easy_setopt(CURL
*curl
, CURLoption tag
, ...)
384 struct SessionHandle
*data
= curl
;
388 return CURLE_BAD_FUNCTION_ARGUMENT
;
392 ret
= Curl_setopt(data
, tag
, arg
);
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 ***************************************************************************
404 * The *new* curl_easy_perform() is the external interface that performs a
405 * transfer previously setup.
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.
412 CURLcode
curl_easy_perform(CURL
*easy
)
416 CURLcode code
= CURLE_OK
;
418 struct timeval timeout
;
427 return CURLE_BAD_FUNCTION_ARGUMENT
;
429 multi
= curl_multi_init();
431 return CURLE_OUT_OF_MEMORY
;
433 mcode
= curl_multi_add_handle(multi
, easy
);
435 curl_multi_cleanup(multi
);
436 if(mcode
== CURLM_OUT_OF_MEMORY
)
437 return CURLE_OUT_OF_MEMORY
;
439 return CURLE_FAILED_INIT
;
442 /* we start some action by calling perform right away */
445 while(CURLM_CALL_MULTI_PERFORM
==
446 curl_multi_perform(multi
, &still_running
));
455 /* timeout once per second */
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
);
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. */
471 /* timeout or data to send/receive => loop! */
472 } while(still_running
);
474 msg
= curl_multi_info_read(multi
, &rc
);
476 code
= msg
->data
.result
;
478 mcode
= curl_multi_remove_handle(multi
, easy
);
479 /* what to do if it fails? */
481 mcode
= curl_multi_cleanup(multi
);
482 /* what to do if it fails? */
488 * curl_easy_perform() is the external interface that performs a transfer
491 CURLcode
curl_easy_perform(CURL
*curl
)
493 struct SessionHandle
*data
= (struct SessionHandle
*)curl
;
496 return CURLE_BAD_FUNCTION_ARGUMENT
;
498 if( ! (data
->share
&& data
->share
->hostcache
) ) {
499 /* this handle is not using a shared dns cache */
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
;
506 if(data
->dns
.hostcachetype
== HCACHE_PRIVATE
)
507 /* if the current cache is private, kill it first */
508 Curl_hash_destroy(data
->dns
.hostcache
);
510 ptr
= Curl_global_host_cache_init();
512 /* only do this if the global cache init works */
513 data
->dns
.hostcache
= ptr
;
514 data
->dns
.hostcachetype
= HCACHE_GLOBAL
;
518 if(!data
->dns
.hostcache
) {
519 data
->dns
.hostcachetype
= HCACHE_PRIVATE
;
520 data
->dns
.hostcache
= Curl_mk_dnscache();
522 if(!data
->dns
.hostcache
)
523 /* While we possibly could survive and do good without a host cache,
524 the fact that creating it failed indicates that things are truly
525 screwed up and we should bail out! */
526 return CURLE_OUT_OF_MEMORY
;
531 if(!data
->state
.connc
) {
532 /* oops, no connection cache, make one up */
533 data
->state
.connc
= Curl_mk_connc(CONNCACHE_PRIVATE
, -1);
534 if(!data
->state
.connc
)
535 return CURLE_OUT_OF_MEMORY
;
538 return Curl_perform(data
);
543 * curl_easy_cleanup() is the external interface to cleaning/freeing the given
546 void curl_easy_cleanup(CURL
*curl
)
548 struct SessionHandle
*data
= (struct SessionHandle
*)curl
;
557 * Store a pointed to the multi handle within the easy handle's data struct.
559 void Curl_easy_addmulti(struct SessionHandle
*data
,
564 /* the association is cleared, mark the easy handle as not used by an
566 data
->state
.used_interface
= Curl_if_none
;
569 void Curl_easy_initHandleData(struct SessionHandle
*data
)
571 memset(&data
->req
, 0, sizeof(struct SingleRequest
));
573 data
->req
.maxdownload
= -1;
577 * curl_easy_getinfo() is an external interface that allows an app to retrieve
578 * information from a performed transfer and similar.
580 #undef curl_easy_getinfo
581 CURLcode
curl_easy_getinfo(CURL
*curl
, CURLINFO info
, ...)
585 struct SessionHandle
*data
= (struct SessionHandle
*)curl
;
588 paramp
= va_arg(arg
, void *);
590 return Curl_getinfo(data
, info
, paramp
);
594 * curl_easy_duphandle() is an external interface to allow duplication of a
595 * given input easy handle. The returned handle will be a new working handle
596 * with all options set exactly as the input source handle.
598 CURL
*curl_easy_duphandle(CURL
*incurl
)
601 struct SessionHandle
*data
=(struct SessionHandle
*)incurl
;
603 struct SessionHandle
*outcurl
= (struct SessionHandle
*)
604 calloc(sizeof(struct SessionHandle
), 1);
607 return NULL
; /* failure */
612 * We setup a few buffers we need. We should probably make them
613 * get setup on-demand in the code, as that would probably decrease
614 * the likeliness of us forgetting to init a buffer here in the future.
616 outcurl
->state
.headerbuff
=(char*)malloc(HEADERSIZE
);
617 if(!outcurl
->state
.headerbuff
) {
620 outcurl
->state
.headersize
=HEADERSIZE
;
622 /* copy all userdefined values */
623 if(Curl_dupset(outcurl
, data
) != CURLE_OK
)
626 if(data
->state
.used_interface
== Curl_if_multi
)
627 outcurl
->state
.connc
= data
->state
.connc
;
629 outcurl
->state
.connc
= Curl_mk_connc(CONNCACHE_PRIVATE
, -1);
631 if(!outcurl
->state
.connc
)
634 outcurl
->state
.lastconnect
= -1;
636 outcurl
->progress
.flags
= data
->progress
.flags
;
637 outcurl
->progress
.callback
= data
->progress
.callback
;
639 #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
641 /* If cookies are enabled in the parent handle, we enable them
642 in the clone as well! */
643 outcurl
->cookies
= Curl_cookie_init(data
,
644 data
->cookies
->filename
,
646 data
->set
.cookiesession
);
647 if(!outcurl
->cookies
) {
651 #endif /* CURL_DISABLE_HTTP */
653 /* duplicate all values in 'change' */
655 if(data
->change
.url
) {
656 outcurl
->change
.url
= strdup(data
->change
.url
);
657 if(!outcurl
->change
.url
)
659 outcurl
->change
.url_alloc
= TRUE
;
662 if(data
->change
.referer
) {
663 outcurl
->change
.referer
= strdup(data
->change
.referer
);
664 if(!outcurl
->change
.referer
)
666 outcurl
->change
.referer_alloc
= TRUE
;
670 /* If we use ares, we setup a new ares channel for the new handle */
671 if(ARES_SUCCESS
!= ares_init(&outcurl
->state
.areschannel
))
675 #if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV)
676 outcurl
->inbound_cd
= iconv_open(CURL_ICONV_CODESET_OF_HOST
,
677 CURL_ICONV_CODESET_OF_NETWORK
);
678 outcurl
->outbound_cd
= iconv_open(CURL_ICONV_CODESET_OF_NETWORK
,
679 CURL_ICONV_CODESET_OF_HOST
);
680 outcurl
->utf8_cd
= iconv_open(CURL_ICONV_CODESET_OF_HOST
,
681 CURL_ICONV_CODESET_FOR_UTF8
);
684 Curl_easy_initHandleData(outcurl
);
686 outcurl
->magic
= CURLEASY_MAGIC_NUMBER
;
688 fail
= FALSE
; /* we reach this point and thus we are OK */
694 if(outcurl
->state
.connc
&&
695 (outcurl
->state
.connc
->type
== CONNCACHE_PRIVATE
))
696 Curl_rm_connc(outcurl
->state
.connc
);
697 if(outcurl
->state
.headerbuff
)
698 free(outcurl
->state
.headerbuff
);
699 if(outcurl
->change
.url
)
700 free(outcurl
->change
.url
);
701 if(outcurl
->change
.referer
)
702 free(outcurl
->change
.referer
);
703 Curl_freeset(outcurl
);
704 free(outcurl
); /* free the memory again */
713 * curl_easy_reset() is an external interface that allows an app to re-
714 * initialize a session handle to the default values.
716 void curl_easy_reset(CURL
*curl
)
718 struct SessionHandle
*data
= (struct SessionHandle
*)curl
;
720 Curl_safefree(data
->state
.pathbuffer
);
721 data
->state
.pathbuffer
=NULL
;
723 Curl_safefree(data
->state
.proto
.generic
);
724 data
->state
.proto
.generic
=NULL
;
726 /* zero out UserDefined data: */
728 memset(&data
->set
, 0, sizeof(struct UserDefined
));
730 /* zero out Progress data: */
731 memset(&data
->progress
, 0, sizeof(struct Progress
));
733 /* init Handle data */
734 Curl_easy_initHandleData(data
);
736 /* The remainder of these calls have been taken from Curl_open() */
738 data
->set
.out
= stdout
; /* default output to stdout */
739 data
->set
.in
= stdin
; /* default input from stdin */
740 data
->set
.err
= stderr
; /* default stderr to stderr */
742 /* use fwrite as default function to store output */
743 data
->set
.fwrite_func
= (curl_write_callback
)fwrite
;
745 /* use fread as default function to read input */
746 data
->set
.fread_func
= (curl_read_callback
)fread
;
748 data
->set
.infilesize
= -1; /* we don't know any size */
749 data
->set
.postfieldsize
= -1; /* unknown size */
750 data
->set
.maxredirs
= -1; /* allow any amount by default */
751 data
->state
.current_speed
= -1; /* init to negative == impossible */
753 data
->set
.httpreq
= HTTPREQ_GET
; /* Default HTTP request */
754 data
->set
.ftp_use_epsv
= TRUE
; /* FTP defaults to EPSV operations */
755 data
->set
.ftp_use_eprt
= TRUE
; /* FTP defaults to EPRT operations */
757 data
->set
.dns_cache_timeout
= 60; /* Timeout every 60 seconds by default */
759 /* make libcurl quiet by default: */
760 data
->set
.hide_progress
= TRUE
; /* CURLOPT_NOPROGRESS changes these */
761 data
->progress
.flags
|= PGRS_HIDE
;
763 /* Set the default size of the SSL session ID cache */
764 data
->set
.ssl
.numsessions
= 5;
766 data
->set
.proxyport
= CURL_DEFAULT_PROXY_PORT
; /* from url.h */
767 data
->set
.proxytype
= CURLPROXY_HTTP
; /* defaults to HTTP proxy */
768 data
->set
.httpauth
= CURLAUTH_BASIC
; /* defaults to basic */
769 data
->set
.proxyauth
= CURLAUTH_BASIC
; /* defaults to basic */
772 * libcurl 7.10 introduced SSL verification *by default*! This needs to be
773 * switched off unless wanted.
775 data
->set
.ssl
.verifypeer
= TRUE
;
776 data
->set
.ssl
.verifyhost
= 2;
777 /* This is our prefered CA cert bundle/path since install time */
778 #if defined(CURL_CA_BUNDLE)
779 (void) curl_easy_setopt(curl
, CURLOPT_CAINFO
, (char *) CURL_CA_BUNDLE
);
780 #elif defined(CURL_CA_PATH)
781 (void) curl_easy_setopt(curl
, CURLOPT_CAPATH
, (char *) CURL_CA_PATH
);
784 data
->set
.ssh_auth_types
= CURLSSH_AUTH_DEFAULT
; /* defaults to any auth
786 data
->set
.new_file_perms
= 0644; /* Default permissions */
787 data
->set
.new_directory_perms
= 0755; /* Default permissions */
791 * curl_easy_pause() allows an application to pause or unpause a specific
792 * transfer and direction. This function sets the full new state for the
793 * current connection this easy handle operates on.
795 * NOTE: if you have the receiving paused and you call this function to remove
796 * the pausing, you may get your write callback called at this point.
798 * Action is a bitmask consisting of CURLPAUSE_* bits in curl/curl.h
800 CURLcode
curl_easy_pause(CURL
*curl
, int action
)
802 struct SessionHandle
*data
= (struct SessionHandle
*)curl
;
803 struct SingleRequest
*k
= &data
->req
;
804 CURLcode result
= CURLE_OK
;
806 /* first switch off both pause bits */
807 int newstate
= k
->keepon
&~ (KEEP_READ_PAUSE
| KEEP_WRITE_PAUSE
);
809 /* set the new desired pause bits */
810 newstate
|= ((action
& CURLPAUSE_RECV
)?KEEP_READ_PAUSE
:0) |
811 ((action
& CURLPAUSE_SEND
)?KEEP_WRITE_PAUSE
:0);
813 /* put it back in the keepon */
814 k
->keepon
= newstate
;
816 if(!(newstate
& KEEP_READ_PAUSE
) && data
->state
.tempwrite
) {
817 /* we have a buffer for writing that we now seem to be able to deliver since
818 the receive pausing is lifted! */
820 /* get the pointer, type and length in local copies since the function may
821 return PAUSE again and then we'll get a new copy allocted and stored in
822 the tempwrite variables */
823 char *tempwrite
= data
->state
.tempwrite
;
824 size_t tempsize
= data
->state
.tempwritesize
;
825 int temptype
= data
->state
.tempwritetype
;
828 /* clear tempwrite here just to make sure it gets cleared if there's no
829 further use of it, and make sure we don't clear it after the function
830 invoke as it may have been set to a new value by then */
831 data
->state
.tempwrite
= NULL
;
833 /* since the write callback API is define to never exceed
834 CURL_MAX_WRITE_SIZE bytes in a single call, and since we may in fact
835 have more data than that in our buffer here, we must loop sending the
836 data in multiple calls until there's no data left or we get another
839 A tricky part is that the function we call will "buffer" the data
840 itself when it pauses on a particular buffer, so we may need to do some
841 extra trickery if we get a pause return here.
844 chunklen
= (tempsize
> CURL_MAX_WRITE_SIZE
)?CURL_MAX_WRITE_SIZE
:tempsize
;
846 result
= Curl_client_write(data
->state
.current_conn
,
847 temptype
, tempwrite
, chunklen
);
849 /* failures abort the loop at once */
852 if(data
->state
.tempwrite
&& (tempsize
- chunklen
)) {
853 /* Ouch, the reading is again paused and the block we send is now
854 "cached". If this is the final chunk we can leave it like this, but
855 if we have more chunks that is cached after this, we need to free
856 the newly cached one and put back a version that is truly the entire
857 contents that is saved for later
861 free(data
->state
.tempwrite
); /* free the one just cached as it isn't
864 /* note that tempsize is still the size as before the callback was
865 used, and thus the whole piece of data to keep */
866 newptr
= malloc(tempsize
);
868 result
= CURLE_OUT_OF_MEMORY
;
869 /* tempwrite will be freed further down */
872 data
->state
.tempwrite
= newptr
; /* store new pointer */
873 memcpy(newptr
, tempwrite
, tempsize
);
874 data
->state
.tempwritesize
= tempsize
; /* store new size */
875 /* tempwrite will be freed further down */
876 break; /* go back to pausing until further notice */
879 tempsize
-= chunklen
; /* left after the call above */
880 tempwrite
+= chunklen
; /* advance the pointer */
883 } while((result
== CURLE_OK
) && tempsize
);
885 free(tempwrite
); /* this is unconditionally no longer used */
891 #ifdef CURL_DOES_CONVERSIONS
893 * Curl_convert_to_network() is an internal function
894 * for performing ASCII conversions on non-ASCII platforms.
896 CURLcode
Curl_convert_to_network(struct SessionHandle
*data
,
897 char *buffer
, size_t length
)
901 if(data
->set
.convtonetwork
) {
902 /* use translation callback */
903 rc
= data
->set
.convtonetwork(buffer
, length
);
906 "CURLOPT_CONV_TO_NETWORK_FUNCTION callback returned %i: %s",
907 rc
, curl_easy_strerror(rc
));
912 /* do the translation ourselves */
913 char *input_ptr
, *output_ptr
;
914 size_t in_bytes
, out_bytes
, rc
;
917 /* open an iconv conversion descriptor if necessary */
918 if(data
->outbound_cd
== (iconv_t
)-1) {
919 data
->outbound_cd
= iconv_open(CURL_ICONV_CODESET_OF_NETWORK
,
920 CURL_ICONV_CODESET_OF_HOST
);
921 if(data
->outbound_cd
== (iconv_t
)-1) {
924 "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s",
925 CURL_ICONV_CODESET_OF_NETWORK
,
926 CURL_ICONV_CODESET_OF_HOST
,
927 error
, strerror(error
));
928 return CURLE_CONV_FAILED
;
932 input_ptr
= output_ptr
= buffer
;
933 in_bytes
= out_bytes
= length
;
934 rc
= iconv(data
->outbound_cd
, (const char**)&input_ptr
, &in_bytes
,
935 &output_ptr
, &out_bytes
);
936 if((rc
== ICONV_ERROR
) || (in_bytes
!= 0)) {
939 "The Curl_convert_to_network iconv call failed with errno %i: %s",
940 error
, strerror(error
));
941 return CURLE_CONV_FAILED
;
944 failf(data
, "CURLOPT_CONV_TO_NETWORK_FUNCTION callback required");
945 return CURLE_CONV_REQD
;
946 #endif /* HAVE_ICONV */
953 * Curl_convert_from_network() is an internal function
954 * for performing ASCII conversions on non-ASCII platforms.
956 CURLcode
Curl_convert_from_network(struct SessionHandle
*data
,
957 char *buffer
, size_t length
)
961 if(data
->set
.convfromnetwork
) {
962 /* use translation callback */
963 rc
= data
->set
.convfromnetwork(buffer
, length
);
966 "CURLOPT_CONV_FROM_NETWORK_FUNCTION callback returned %i: %s",
967 rc
, curl_easy_strerror(rc
));
973 /* do the translation ourselves */
974 char *input_ptr
, *output_ptr
;
975 size_t in_bytes
, out_bytes
, rc
;
978 /* open an iconv conversion descriptor if necessary */
979 if(data
->inbound_cd
== (iconv_t
)-1) {
980 data
->inbound_cd
= iconv_open(CURL_ICONV_CODESET_OF_HOST
,
981 CURL_ICONV_CODESET_OF_NETWORK
);
982 if(data
->inbound_cd
== (iconv_t
)-1) {
985 "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s",
986 CURL_ICONV_CODESET_OF_HOST
,
987 CURL_ICONV_CODESET_OF_NETWORK
,
988 error
, strerror(error
));
989 return CURLE_CONV_FAILED
;
993 input_ptr
= output_ptr
= buffer
;
994 in_bytes
= out_bytes
= length
;
995 rc
= iconv(data
->inbound_cd
, (const char **)&input_ptr
, &in_bytes
,
996 &output_ptr
, &out_bytes
);
997 if((rc
== ICONV_ERROR
) || (in_bytes
!= 0)) {
1000 "The Curl_convert_from_network iconv call failed with errno %i: %s",
1001 error
, strerror(error
));
1002 return CURLE_CONV_FAILED
;
1005 failf(data
, "CURLOPT_CONV_FROM_NETWORK_FUNCTION callback required");
1006 return CURLE_CONV_REQD
;
1007 #endif /* HAVE_ICONV */
1014 * Curl_convert_from_utf8() is an internal function
1015 * for performing UTF-8 conversions on non-ASCII platforms.
1017 CURLcode
Curl_convert_from_utf8(struct SessionHandle
*data
,
1018 char *buffer
, size_t length
)
1022 if(data
->set
.convfromutf8
) {
1023 /* use translation callback */
1024 rc
= data
->set
.convfromutf8(buffer
, length
);
1025 if(rc
!= CURLE_OK
) {
1027 "CURLOPT_CONV_FROM_UTF8_FUNCTION callback returned %i: %s",
1028 rc
, curl_easy_strerror(rc
));
1033 /* do the translation ourselves */
1034 const char *input_ptr
;
1036 size_t in_bytes
, out_bytes
, rc
;
1039 /* open an iconv conversion descriptor if necessary */
1040 if(data
->utf8_cd
== (iconv_t
)-1) {
1041 data
->utf8_cd
= iconv_open(CURL_ICONV_CODESET_OF_HOST
,
1042 CURL_ICONV_CODESET_FOR_UTF8
);
1043 if(data
->utf8_cd
== (iconv_t
)-1) {
1046 "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s",
1047 CURL_ICONV_CODESET_OF_HOST
,
1048 CURL_ICONV_CODESET_FOR_UTF8
,
1049 error
, strerror(error
));
1050 return CURLE_CONV_FAILED
;
1054 input_ptr
= output_ptr
= buffer
;
1055 in_bytes
= out_bytes
= length
;
1056 rc
= iconv(data
->utf8_cd
, &input_ptr
, &in_bytes
,
1057 &output_ptr
, &out_bytes
);
1058 if((rc
== ICONV_ERROR
) || (in_bytes
!= 0)) {
1061 "The Curl_convert_from_utf8 iconv call failed with errno %i: %s",
1062 error
, strerror(error
));
1063 return CURLE_CONV_FAILED
;
1065 if(output_ptr
< input_ptr
) {
1066 /* null terminate the now shorter output string */
1070 failf(data
, "CURLOPT_CONV_FROM_UTF8_FUNCTION callback required");
1071 return CURLE_CONV_REQD
;
1072 #endif /* HAVE_ICONV */
1078 #endif /* CURL_DOES_CONVERSIONS */
1080 static CURLcode
easy_connection(struct SessionHandle
*data
,
1082 struct connectdata
**connp
)
1088 return CURLE_BAD_FUNCTION_ARGUMENT
;
1090 /* only allow these to be called on handles with CURLOPT_CONNECT_ONLY */
1091 if(!data
->set
.connect_only
) {
1092 failf(data
, "CONNECT_ONLY is required!");
1093 return CURLE_UNSUPPORTED_PROTOCOL
;
1096 ret
= Curl_getconnectinfo(data
, &sockfd
, connp
);
1101 failf(data
, "Failed to get recent socket");
1102 return CURLE_UNSUPPORTED_PROTOCOL
;
1105 *sfd
= (curl_socket_t
)sockfd
; /* we know that this is actually a socket
1106 descriptor so the typecast is fine here */
1112 * Receives data from the connected socket. Use after successful
1113 * curl_easy_perform() with CURLOPT_CONNECT_ONLY option.
1114 * Returns CURLE_OK on success, error code on error.
1116 CURLcode
curl_easy_recv(CURL
*curl
, void *buffer
, size_t buflen
, size_t *n
)
1122 struct connectdata
*c
;
1123 struct SessionHandle
*data
= (struct SessionHandle
*)curl
;
1125 ret
= easy_connection(data
, &sfd
, &c
);
1130 ret1
= Curl_read(c
, sfd
, buffer
, buflen
, &n1
);
1136 return CURLE_RECV_ERROR
;
1144 * Sends data over the connected socket. Use after successful
1145 * curl_easy_perform() with CURLOPT_CONNECT_ONLY option.
1147 CURLcode
curl_easy_send(CURL
*curl
, const void *buffer
, size_t buflen
,
1153 struct connectdata
*c
= NULL
;
1154 struct SessionHandle
*data
= (struct SessionHandle
*)curl
;
1156 ret
= easy_connection(data
, &sfd
, &c
);
1161 ret
= Curl_write(c
, sfd
, buffer
, buflen
, &n1
);
1164 return CURLE_SEND_ERROR
;
1167 if((CURLE_OK
== ret
) && (0 == n1
))