1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2010, 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 ***************************************************************************/
25 /* -- WIN32 approved -- */
39 #ifdef HAVE_SYS_SOCKET_H
40 #include <sys/socket.h>
42 #ifdef HAVE_NETINET_IN_H
43 #include <netinet/in.h>
45 #ifdef HAVE_SYS_TIME_H
54 #ifdef HAVE_ARPA_INET_H
55 #include <arpa/inet.h>
60 #ifdef HAVE_SYS_IOCTL_H
61 #include <sys/ioctl.h>
64 #ifdef HAVE_SYS_PARAM_H
65 #include <sys/param.h>
68 #endif /* WIN32 ... */
71 #include <curl/curl.h>
79 #include "curl_memory.h"
83 #include "sendf.h" /* for failf function prototype */
84 #include "http_ntlm.h"
85 #include "connect.h" /* for Curl_getconnectinfo */
87 #include "curl_rand.h"
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_sspi_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 res = 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_sspi_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) && !defined(__POCC__)
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) && !defined(__POCC__)
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"));
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;
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;
299 /* Preset pseudo-random number sequence. */
307 * curl_global_init_mem() globally initializes cURL and also registers the
308 * user provided callback routines.
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)
314 CURLcode code = CURLE_OK;
316 /* Invalid input, return immediately */
317 if(!m || !f || !r || !s || !c)
318 return CURLE_FAILED_INIT;
320 /* Already initialized, don't do it again */
324 /* Call the actual init function first */
325 code = curl_global_init(flags);
326 if(code == CURLE_OK) {
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.
341 void curl_global_cleanup(void)
349 Curl_global_host_cache_dtor();
351 if(init_flags & CURL_GLOBAL_SSL)
354 #ifdef CARES_HAVE_ARES_LIBRARY_CLEANUP
355 ares_library_cleanup();
358 if(init_flags & CURL_GLOBAL_WIN32)
365 #if defined(USE_LIBSSH2) && defined(HAVE_LIBSSH2_EXIT)
366 (void)libssh2_exit();
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.
376 CURL *curl_easy_init(void)
379 struct SessionHandle *data;
381 /* Make sure we inited the global SSL stuff */
383 res = curl_global_init(CURL_GLOBAL_DEFAULT);
385 /* something in the global init failed, return nothing */
386 DEBUGF(fprintf(stderr, "Error: curl_global_init failed\n"));
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"));
402 * curl_easy_setopt() is the external interface for setting options on an
406 #undef curl_easy_setopt
407 CURLcode curl_easy_setopt(CURL *curl, CURLoption tag, ...)
410 struct SessionHandle *data = curl;
414 return CURLE_BAD_FUNCTION_ARGUMENT;
418 ret = Curl_setopt(data, tag, arg);
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 ***************************************************************************
430 * The *new* curl_easy_perform() is the external interface that performs a
431 * transfer previously setup.
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.
438 CURLcode curl_easy_perform(CURL *easy)
442 CURLcode code = CURLE_OK;
444 struct timeval timeout;
453 return CURLE_BAD_FUNCTION_ARGUMENT;
455 multi = curl_multi_init();
457 return CURLE_OUT_OF_MEMORY;
459 mcode = curl_multi_add_handle(multi, easy);
461 curl_multi_cleanup(multi);
462 if(mcode == CURLM_OUT_OF_MEMORY)
463 return CURLE_OUT_OF_MEMORY;
465 return CURLE_FAILED_INIT;
468 /* we start some action by calling perform right away */
471 while(CURLM_CALL_MULTI_PERFORM ==
472 curl_multi_perform(multi, &still_running));
481 /* timeout once per second */
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);
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. */
497 /* timeout or data to send/receive => loop! */
498 } while(still_running);
500 msg = curl_multi_info_read(multi, &rc);
502 code = msg->data.result;
504 mcode = curl_multi_remove_handle(multi, easy);
505 /* what to do if it fails? */
507 mcode = curl_multi_cleanup(multi);
508 /* what to do if it fails? */
514 * curl_easy_perform() is the external interface that performs a transfer
517 CURLcode curl_easy_perform(CURL *curl)
519 struct SessionHandle *data = (struct SessionHandle *)curl;
522 return CURLE_BAD_FUNCTION_ARGUMENT;
524 if( ! (data->share && data->share->hostcache) ) {
525 /* this handle is not using a shared dns cache */
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;
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;
539 ptr = Curl_global_host_cache_init();
541 /* only do this if the global cache init works */
542 data->dns.hostcache = ptr;
543 data->dns.hostcachetype = HCACHE_GLOBAL;
547 if(!data->dns.hostcache) {
548 data->dns.hostcachetype = HCACHE_PRIVATE;
549 data->dns.hostcache = Curl_mk_dnscache();
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;
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;
567 return Curl_perform(data);
572 * curl_easy_cleanup() is the external interface to cleaning/freeing the given
575 void curl_easy_cleanup(CURL *curl)
577 struct SessionHandle *data = (struct SessionHandle *)curl;
586 * Store a pointed to the multi handle within the easy handle's data struct.
588 void Curl_easy_addmulti(struct SessionHandle *data,
593 /* the association is cleared, mark the easy handle as not used by an
595 data->state.used_interface = Curl_if_none;
598 void Curl_easy_initHandleData(struct SessionHandle *data)
600 memset(&data->req, 0, sizeof(struct SingleRequest));
602 data->req.maxdownload = -1;
606 * curl_easy_getinfo() is an external interface that allows an app to retrieve
607 * information from a performed transfer and similar.
609 #undef curl_easy_getinfo
610 CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ...)
614 struct SessionHandle *data = (struct SessionHandle *)curl;
617 paramp = va_arg(arg, void *);
619 return Curl_getinfo(data, info, paramp);
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.
627 CURL *curl_easy_duphandle(CURL *incurl)
629 struct SessionHandle *data=(struct SessionHandle *)incurl;
631 struct SessionHandle *outcurl = calloc(1, sizeof(struct SessionHandle));
636 * We setup a few buffers we need. We should probably make them
637 * get setup on-demand in the code, as that would probably decrease
638 * the likeliness of us forgetting to init a buffer here in the future.
640 outcurl->state.headerbuff = malloc(HEADERSIZE);
641 if(!outcurl->state.headerbuff)
643 outcurl->state.headersize = HEADERSIZE;
645 /* copy all userdefined values */
646 if(Curl_dupset(outcurl, data) != CURLE_OK)
649 /* the connection cache is setup on demand */
650 outcurl->state.connc = NULL;
652 outcurl->state.lastconnect = -1;
654 outcurl->progress.flags = data->progress.flags;
655 outcurl->progress.callback = data->progress.callback;
657 #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
659 /* If cookies are enabled in the parent handle, we enable them
660 in the clone as well! */
661 outcurl->cookies = Curl_cookie_init(data,
662 data->cookies->filename,
664 data->set.cookiesession);
665 if(!outcurl->cookies)
668 #endif /* CURL_DISABLE_HTTP */
670 /* duplicate all values in 'change' */
672 #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
673 if(data->change.cookielist) {
674 outcurl->change.cookielist =
675 Curl_slist_duplicate(data->change.cookielist);
676 if(!outcurl->change.cookielist)
679 #endif /* CURL_DISABLE_HTTP */
681 if(data->change.url) {
682 outcurl->change.url = strdup(data->change.url);
683 if(!outcurl->change.url)
685 outcurl->change.url_alloc = TRUE;
688 if(data->change.referer) {
689 outcurl->change.referer = strdup(data->change.referer);
690 if(!outcurl->change.referer)
692 outcurl->change.referer_alloc = TRUE;
696 /* If we use ares, we clone the ares channel for the new handle */
697 if(ARES_SUCCESS != ares_dup(&outcurl->state.areschannel,
698 data->state.areschannel))
702 #if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV)
703 outcurl->inbound_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
704 CURL_ICONV_CODESET_OF_NETWORK);
705 outcurl->outbound_cd = iconv_open(CURL_ICONV_CODESET_OF_NETWORK,
706 CURL_ICONV_CODESET_OF_HOST);
707 outcurl->utf8_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
708 CURL_ICONV_CODESET_FOR_UTF8);
711 Curl_easy_initHandleData(outcurl);
713 outcurl->magic = CURLEASY_MAGIC_NUMBER;
715 /* we reach this point and thus we are OK */
722 if(outcurl->state.connc &&
723 (outcurl->state.connc->type == CONNCACHE_PRIVATE))
724 Curl_rm_connc(outcurl->state.connc);
725 if(outcurl->state.headerbuff)
726 free(outcurl->state.headerbuff);
727 #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
728 if(outcurl->change.cookielist)
729 curl_slist_free_all(outcurl->change.cookielist);
731 if(outcurl->change.url)
732 free(outcurl->change.url);
733 if(outcurl->change.referer)
734 free(outcurl->change.referer);
735 Curl_freeset(outcurl);
743 * curl_easy_reset() is an external interface that allows an app to re-
744 * initialize a session handle to the default values.
746 void curl_easy_reset(CURL *curl)
748 struct SessionHandle *data = (struct SessionHandle *)curl;
750 Curl_safefree(data->state.pathbuffer);
751 data->state.pathbuffer=NULL;
753 Curl_safefree(data->state.proto.generic);
754 data->state.proto.generic=NULL;
756 /* zero out UserDefined data: */
758 memset(&data->set, 0, sizeof(struct UserDefined));
759 (void)Curl_init_userdefined(&data->set);
761 /* zero out Progress data: */
762 memset(&data->progress, 0, sizeof(struct Progress));
764 /* init Handle data */
765 Curl_easy_initHandleData(data);
767 data->progress.flags |= PGRS_HIDE;
768 data->state.current_speed = -1; /* init to negative == impossible */
772 * curl_easy_pause() allows an application to pause or unpause a specific
773 * transfer and direction. This function sets the full new state for the
774 * current connection this easy handle operates on.
776 * NOTE: if you have the receiving paused and you call this function to remove
777 * the pausing, you may get your write callback called at this point.
779 * Action is a bitmask consisting of CURLPAUSE_* bits in curl/curl.h
781 CURLcode curl_easy_pause(CURL *curl, int action)
783 struct SessionHandle *data = (struct SessionHandle *)curl;
784 struct SingleRequest *k = &data->req;
785 CURLcode result = CURLE_OK;
787 /* first switch off both pause bits */
788 int newstate = k->keepon &~ (KEEP_RECV_PAUSE| KEEP_SEND_PAUSE);
790 /* set the new desired pause bits */
791 newstate |= ((action & CURLPAUSE_RECV)?KEEP_RECV_PAUSE:0) |
792 ((action & CURLPAUSE_SEND)?KEEP_SEND_PAUSE:0);
794 /* put it back in the keepon */
795 k->keepon = newstate;
797 if(!(newstate & KEEP_RECV_PAUSE) && data->state.tempwrite) {
798 /* we have a buffer for sending that we now seem to be able to deliver since
799 the receive pausing is lifted! */
801 /* get the pointer, type and length in local copies since the function may
802 return PAUSE again and then we'll get a new copy allocted and stored in
803 the tempwrite variables */
804 char *tempwrite = data->state.tempwrite;
805 char *freewrite = tempwrite; /* store this pointer to free it later */
806 size_t tempsize = data->state.tempwritesize;
807 int temptype = data->state.tempwritetype;
810 /* clear tempwrite here just to make sure it gets cleared if there's no
811 further use of it, and make sure we don't clear it after the function
812 invoke as it may have been set to a new value by then */
813 data->state.tempwrite = NULL;
815 /* since the write callback API is define to never exceed
816 CURL_MAX_WRITE_SIZE bytes in a single call, and since we may in fact
817 have more data than that in our buffer here, we must loop sending the
818 data in multiple calls until there's no data left or we get another
821 A tricky part is that the function we call will "buffer" the data
822 itself when it pauses on a particular buffer, so we may need to do some
823 extra trickery if we get a pause return here.
826 chunklen = (tempsize > CURL_MAX_WRITE_SIZE)?CURL_MAX_WRITE_SIZE:tempsize;
828 result = Curl_client_write(data->state.current_conn,
829 temptype, tempwrite, chunklen);
831 /* failures abort the loop at once */
834 if(data->state.tempwrite && (tempsize - chunklen)) {
835 /* Ouch, the reading is again paused and the block we send is now
836 "cached". If this is the final chunk we can leave it like this, but
837 if we have more chunks that are cached after this, we need to free
838 the newly cached one and put back a version that is truly the entire
839 contents that is saved for later
843 /* note that tempsize is still the size as before the callback was
844 used, and thus the whole piece of data to keep */
845 newptr = realloc(data->state.tempwrite, tempsize);
848 free(data->state.tempwrite); /* free old area */
849 data->state.tempwrite = NULL;
850 result = CURLE_OUT_OF_MEMORY;
851 /* tempwrite will be freed further down */
854 data->state.tempwrite = newptr; /* store new pointer */
855 memcpy(newptr, tempwrite, tempsize);
856 data->state.tempwritesize = tempsize; /* store new size */
857 /* tempwrite will be freed further down */
858 break; /* go back to pausing until further notice */
861 tempsize -= chunklen; /* left after the call above */
862 tempwrite += chunklen; /* advance the pointer */
865 } while((result == CURLE_OK) && tempsize);
867 free(freewrite); /* this is unconditionally no longer used */
873 #ifdef CURL_DOES_CONVERSIONS
875 * Curl_convert_to_network() is an internal function
876 * for performing ASCII conversions on non-ASCII platforms.
878 CURLcode Curl_convert_to_network(struct SessionHandle *data,
879 char *buffer, size_t length)
883 if(data->set.convtonetwork) {
884 /* use translation callback */
885 rc = data->set.convtonetwork(buffer, length);
888 "CURLOPT_CONV_TO_NETWORK_FUNCTION callback returned %d: %s",
889 (int)rc, curl_easy_strerror(rc));
895 /* do the translation ourselves */
896 char *input_ptr, *output_ptr;
897 size_t in_bytes, out_bytes, rc;
900 /* open an iconv conversion descriptor if necessary */
901 if(data->outbound_cd == (iconv_t)-1) {
902 data->outbound_cd = iconv_open(CURL_ICONV_CODESET_OF_NETWORK,
903 CURL_ICONV_CODESET_OF_HOST);
904 if(data->outbound_cd == (iconv_t)-1) {
907 "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s",
908 CURL_ICONV_CODESET_OF_NETWORK,
909 CURL_ICONV_CODESET_OF_HOST,
910 error, strerror(error));
911 return CURLE_CONV_FAILED;
915 input_ptr = output_ptr = buffer;
916 in_bytes = out_bytes = length;
917 rc = iconv(data->outbound_cd, (const char**)&input_ptr, &in_bytes,
918 &output_ptr, &out_bytes);
919 if((rc == ICONV_ERROR) || (in_bytes != 0)) {
922 "The Curl_convert_to_network iconv call failed with errno %i: %s",
923 error, strerror(error));
924 return CURLE_CONV_FAILED;
927 failf(data, "CURLOPT_CONV_TO_NETWORK_FUNCTION callback required");
928 return CURLE_CONV_REQD;
929 #endif /* HAVE_ICONV */
936 * Curl_convert_from_network() is an internal function
937 * for performing ASCII conversions on non-ASCII platforms.
939 CURLcode Curl_convert_from_network(struct SessionHandle *data,
940 char *buffer, size_t length)
944 if(data->set.convfromnetwork) {
945 /* use translation callback */
946 rc = data->set.convfromnetwork(buffer, length);
949 "CURLOPT_CONV_FROM_NETWORK_FUNCTION callback returned %d: %s",
950 (int)rc, curl_easy_strerror(rc));
956 /* do the translation ourselves */
957 char *input_ptr, *output_ptr;
958 size_t in_bytes, out_bytes, rc;
961 /* open an iconv conversion descriptor if necessary */
962 if(data->inbound_cd == (iconv_t)-1) {
963 data->inbound_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
964 CURL_ICONV_CODESET_OF_NETWORK);
965 if(data->inbound_cd == (iconv_t)-1) {
968 "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s",
969 CURL_ICONV_CODESET_OF_HOST,
970 CURL_ICONV_CODESET_OF_NETWORK,
971 error, strerror(error));
972 return CURLE_CONV_FAILED;
976 input_ptr = output_ptr = buffer;
977 in_bytes = out_bytes = length;
978 rc = iconv(data->inbound_cd, (const char **)&input_ptr, &in_bytes,
979 &output_ptr, &out_bytes);
980 if((rc == ICONV_ERROR) || (in_bytes != 0)) {
983 "The Curl_convert_from_network iconv call failed with errno %i: %s",
984 error, strerror(error));
985 return CURLE_CONV_FAILED;
988 failf(data, "CURLOPT_CONV_FROM_NETWORK_FUNCTION callback required");
989 return CURLE_CONV_REQD;
990 #endif /* HAVE_ICONV */
997 * Curl_convert_from_utf8() is an internal function
998 * for performing UTF-8 conversions on non-ASCII platforms.
1000 CURLcode Curl_convert_from_utf8(struct SessionHandle *data,
1001 char *buffer, size_t length)
1005 if(data->set.convfromutf8) {
1006 /* use translation callback */
1007 rc = data->set.convfromutf8(buffer, length);
1008 if(rc != CURLE_OK) {
1010 "CURLOPT_CONV_FROM_UTF8_FUNCTION callback returned %d: %s",
1011 (int)rc, curl_easy_strerror(rc));
1017 /* do the translation ourselves */
1018 const char *input_ptr;
1020 size_t in_bytes, out_bytes, rc;
1023 /* open an iconv conversion descriptor if necessary */
1024 if(data->utf8_cd == (iconv_t)-1) {
1025 data->utf8_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
1026 CURL_ICONV_CODESET_FOR_UTF8);
1027 if(data->utf8_cd == (iconv_t)-1) {
1030 "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s",
1031 CURL_ICONV_CODESET_OF_HOST,
1032 CURL_ICONV_CODESET_FOR_UTF8,
1033 error, strerror(error));
1034 return CURLE_CONV_FAILED;
1038 input_ptr = output_ptr = buffer;
1039 in_bytes = out_bytes = length;
1040 rc = iconv(data->utf8_cd, &input_ptr, &in_bytes,
1041 &output_ptr, &out_bytes);
1042 if((rc == ICONV_ERROR) || (in_bytes != 0)) {
1045 "The Curl_convert_from_utf8 iconv call failed with errno %i: %s",
1046 error, strerror(error));
1047 return CURLE_CONV_FAILED;
1049 if(output_ptr < input_ptr) {
1050 /* null terminate the now shorter output string */
1054 failf(data, "CURLOPT_CONV_FROM_UTF8_FUNCTION callback required");
1055 return CURLE_CONV_REQD;
1056 #endif /* HAVE_ICONV */
1062 #endif /* CURL_DOES_CONVERSIONS */
1064 static CURLcode easy_connection(struct SessionHandle *data,
1066 struct connectdata **connp)
1069 return CURLE_BAD_FUNCTION_ARGUMENT;
1071 /* only allow these to be called on handles with CURLOPT_CONNECT_ONLY */
1072 if(!data->set.connect_only) {
1073 failf(data, "CONNECT_ONLY is required!");
1074 return CURLE_UNSUPPORTED_PROTOCOL;
1077 *sfd = Curl_getconnectinfo(data, connp);
1079 if(*sfd == CURL_SOCKET_BAD) {
1080 failf(data, "Failed to get recent socket");
1081 return CURLE_UNSUPPORTED_PROTOCOL;
1088 * Receives data from the connected socket. Use after successful
1089 * curl_easy_perform() with CURLOPT_CONNECT_ONLY option.
1090 * Returns CURLE_OK on success, error code on error.
1092 CURLcode curl_easy_recv(CURL *curl, void *buffer, size_t buflen, size_t *n)
1097 struct connectdata *c;
1098 struct SessionHandle *data = (struct SessionHandle *)curl;
1100 ret = easy_connection(data, &sfd, &c);
1105 ret = Curl_read(c, sfd, buffer, buflen, &n1);
1116 * Sends data over the connected socket. Use after successful
1117 * curl_easy_perform() with CURLOPT_CONNECT_ONLY option.
1119 CURLcode curl_easy_send(CURL *curl, const void *buffer, size_t buflen,
1125 struct connectdata *c = NULL;
1126 struct SessionHandle *data = (struct SessionHandle *)curl;
1128 ret = easy_connection(data, &sfd, &c);
1133 ret = Curl_write(c, sfd, buffer, buflen, &n1);
1136 return CURLE_SEND_ERROR;
1139 if((CURLE_OK == ret) && (0 == n1))