1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2009, 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.
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>
65 #ifdef HAVE_SYS_PARAM_H
66 #include <sys/param.h>
69 #endif /* WIN32 ... */
72 #include <curl/curl.h>
80 #include "curl_memory.h"
84 #include "sendf.h" /* for failf function prototype */
85 #include "http_ntlm.h"
86 #include "connect.h" /* for Curl_getconnectinfo */
88 #include "formdata.h" /* For Curl_srand(). */
90 #define _MPRINTF_REPLACE /* use our functions only */
91 #include <curl/mprintf.h>
93 #if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV)
95 /* set default codesets for iconv */
96 #ifndef CURL_ICONV_CODESET_OF_NETWORK
97 #define CURL_ICONV_CODESET_OF_NETWORK "ISO8859-1"
99 #ifndef CURL_ICONV_CODESET_FOR_UTF8
100 #define CURL_ICONV_CODESET_FOR_UTF8 "UTF-8"
102 #define ICONV_ERROR (size_t)-1
103 #endif /* CURL_DOES_CONVERSIONS && HAVE_ICONV */
105 /* The last #include file should be: */
106 #include "memdebug.h"
108 /* win32_cleanup() is for win32 socket cleanup functionality, the opposite
110 static void win32_cleanup(void)
115 #ifdef USE_WINDOWS_SSPI
116 Curl_sspi_global_cleanup();
120 /* win32_init() performs win32 socket initialization to properly setup the
121 stack to allow networking */
122 static CURLcode win32_init(void)
125 WORD wVersionRequested;
129 #if defined(ENABLE_IPV6) && (USE_WINSOCK < 2)
130 Error IPV6_requires_winsock2
133 wVersionRequested = MAKEWORD(USE_WINSOCK, USE_WINSOCK);
135 res = WSAStartup(wVersionRequested, &wsaData);
138 /* Tell the user that we couldn't find a useable */
140 return CURLE_FAILED_INIT;
142 /* Confirm that the Windows Sockets DLL supports what we need.*/
143 /* Note that if the DLL supports versions greater */
144 /* than wVersionRequested, it will still return */
145 /* wVersionRequested in wVersion. wHighVersion contains the */
146 /* highest supported version. */
148 if( LOBYTE( wsaData.wVersion ) != LOBYTE(wVersionRequested) ||
149 HIBYTE( wsaData.wVersion ) != HIBYTE(wVersionRequested) ) {
150 /* Tell the user that we couldn't find a useable */
154 return CURLE_FAILED_INIT;
156 /* The Windows Sockets DLL is acceptable. Proceed. */
159 #ifdef USE_WINDOWS_SSPI
161 CURLcode err = Curl_sspi_global_init();
172 * Initialise use of IDNA library.
173 * It falls back to ASCII if $CHARSET isn't defined. This doesn't work for
174 * idna_to_ascii_lz().
176 static void idna_init (void)
182 if(!getenv("CHARSET") && cp > 0) {
183 snprintf(buf, sizeof(buf), "CHARSET=cp%u", cp);
190 #endif /* USE_LIBIDN */
192 /* true globals -- for curl_global_init() and curl_global_cleanup() */
193 static unsigned int initialized;
194 static long init_flags;
197 * strdup (and other memory functions) is redefined in complicated
198 * ways, but at this point it must be defined as the system-supplied strdup
199 * so the callback pointer is initialized correctly.
201 #if defined(_WIN32_WCE)
202 #define system_strdup _strdup
203 #elif !defined(HAVE_STRDUP)
204 #define system_strdup curlx_strdup
206 #define system_strdup strdup
209 #if defined(_MSC_VER) && defined(_DLL)
210 # pragma warning(disable:4232) /* MSVC extension, dllimport identity */
213 #ifndef __SYMBIAN32__
215 * If a memory-using function (like curl_getenv) is used before
216 * curl_global_init() is called, we need to have these pointers set already.
218 curl_malloc_callback Curl_cmalloc = (curl_malloc_callback)malloc;
219 curl_free_callback Curl_cfree = (curl_free_callback)free;
220 curl_realloc_callback Curl_crealloc = (curl_realloc_callback)realloc;
221 curl_strdup_callback Curl_cstrdup = (curl_strdup_callback)system_strdup;
222 curl_calloc_callback Curl_ccalloc = (curl_calloc_callback)calloc;
225 * Symbian OS doesn't support initialization to code in writeable static data.
226 * Initialization will occur in the curl_global_init() call.
228 curl_malloc_callback Curl_cmalloc;
229 curl_free_callback Curl_cfree;
230 curl_realloc_callback Curl_crealloc;
231 curl_strdup_callback Curl_cstrdup;
232 curl_calloc_callback Curl_ccalloc;
235 #if defined(_MSC_VER) && defined(_DLL)
236 # pragma warning(default:4232) /* MSVC extension, dllimport identity */
240 * curl_global_init() globally initializes cURL given a bitwise set of the
241 * different features of what to initialize.
243 CURLcode curl_global_init(long flags)
248 /* Setup the default memory functions here (again) */
249 Curl_cmalloc = (curl_malloc_callback)malloc;
250 Curl_cfree = (curl_free_callback)free;
251 Curl_crealloc = (curl_realloc_callback)realloc;
252 Curl_cstrdup = (curl_strdup_callback)system_strdup;
253 Curl_ccalloc = (curl_calloc_callback)calloc;
255 if(flags & CURL_GLOBAL_SSL)
256 if(!Curl_ssl_init()) {
257 DEBUGF(fprintf(stderr, "Error: Curl_ssl_init failed\n"));
258 return CURLE_FAILED_INIT;
261 if(flags & CURL_GLOBAL_WIN32)
262 if(win32_init() != CURLE_OK) {
263 DEBUGF(fprintf(stderr, "Error: win32_init failed\n"));
264 return CURLE_FAILED_INIT;
269 DEBUGF(fprintf(stderr, "Error: amiga_init failed\n"));
270 return CURLE_FAILED_INIT;
276 DEBUGF(fprintf(stderr, "Warning: LONG namespace not available\n"));
284 #ifdef CARES_HAVE_ARES_LIBRARY_INIT
285 if(ares_library_init(ARES_LIB_INIT_ALL)) {
286 DEBUGF(fprintf(stderr, "Error: ares_library_init failed\n"));
287 return CURLE_FAILED_INIT;
293 /* Preset pseudo-random number sequence. */
301 * curl_global_init_mem() globally initializes cURL and also registers the
302 * user provided callback routines.
304 CURLcode curl_global_init_mem(long flags, curl_malloc_callback m,
305 curl_free_callback f, curl_realloc_callback r,
306 curl_strdup_callback s, curl_calloc_callback c)
308 CURLcode code = CURLE_OK;
310 /* Invalid input, return immediately */
311 if(!m || !f || !r || !s || !c)
312 return CURLE_FAILED_INIT;
314 /* Already initialized, don't do it again */
318 /* Call the actual init function first */
319 code = curl_global_init(flags);
320 if(code == CURLE_OK) {
332 * curl_global_cleanup() globally cleanups cURL, uses the value of
333 * "init_flags" to determine what needs to be cleaned up and what doesn't.
335 void curl_global_cleanup(void)
343 Curl_global_host_cache_dtor();
345 if(init_flags & CURL_GLOBAL_SSL)
348 #ifdef CARES_HAVE_ARES_LIBRARY_CLEANUP
349 ares_library_cleanup();
352 if(init_flags & CURL_GLOBAL_WIN32)
363 * curl_easy_init() is the external interface to alloc, setup and init an
364 * easy handle that is returned. If anything goes wrong, NULL is returned.
366 CURL *curl_easy_init(void)
369 struct SessionHandle *data;
371 /* Make sure we inited the global SSL stuff */
373 res = curl_global_init(CURL_GLOBAL_DEFAULT);
375 /* something in the global init failed, return nothing */
376 DEBUGF(fprintf(stderr, "Error: curl_global_init failed\n"));
381 /* We use curl_open() with undefined URL so far */
382 res = Curl_open(&data);
383 if(res != CURLE_OK) {
384 DEBUGF(fprintf(stderr, "Error: Curl_open failed\n"));
392 * curl_easy_setopt() is the external interface for setting options on an
396 #undef curl_easy_setopt
397 CURLcode curl_easy_setopt(CURL *curl, CURLoption tag, ...)
400 struct SessionHandle *data = curl;
404 return CURLE_BAD_FUNCTION_ARGUMENT;
408 ret = Curl_setopt(data, tag, arg);
414 #ifdef CURL_MULTIEASY
415 /***************************************************************************
416 * This function is still only for testing purposes. It makes a great way
417 * to run the full test suite on the multi interface instead of the easy one.
418 ***************************************************************************
420 * The *new* curl_easy_perform() is the external interface that performs a
421 * transfer previously setup.
423 * Wrapper-function that: creates a multi handle, adds the easy handle to it,
424 * runs curl_multi_perform() until the transfer is done, then detaches the
425 * easy handle, destroys the multi handle and returns the easy handle's return
426 * code. This will make everything internally use and assume multi interface.
428 CURLcode curl_easy_perform(CURL *easy)
432 CURLcode code = CURLE_OK;
434 struct timeval timeout;
443 return CURLE_BAD_FUNCTION_ARGUMENT;
445 multi = curl_multi_init();
447 return CURLE_OUT_OF_MEMORY;
449 mcode = curl_multi_add_handle(multi, easy);
451 curl_multi_cleanup(multi);
452 if(mcode == CURLM_OUT_OF_MEMORY)
453 return CURLE_OUT_OF_MEMORY;
455 return CURLE_FAILED_INIT;
458 /* we start some action by calling perform right away */
461 while(CURLM_CALL_MULTI_PERFORM ==
462 curl_multi_perform(multi, &still_running));
471 /* timeout once per second */
475 /* Old deprecated style: get file descriptors from the transfers */
476 curl_multi_fdset(multi, &fdread, &fdwrite, &fdexcep, &maxfd);
477 rc = Curl_select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);
479 /* The way is to extract the sockets and wait for them without using
480 select. This whole alternative version should probably rather use the
481 curl_multi_socket() approach. */
487 /* timeout or data to send/receive => loop! */
488 } while(still_running);
490 msg = curl_multi_info_read(multi, &rc);
492 code = msg->data.result;
494 mcode = curl_multi_remove_handle(multi, easy);
495 /* what to do if it fails? */
497 mcode = curl_multi_cleanup(multi);
498 /* what to do if it fails? */
504 * curl_easy_perform() is the external interface that performs a transfer
507 CURLcode curl_easy_perform(CURL *curl)
509 struct SessionHandle *data = (struct SessionHandle *)curl;
512 return CURLE_BAD_FUNCTION_ARGUMENT;
514 if( ! (data->share && data->share->hostcache) ) {
515 /* this handle is not using a shared dns cache */
517 if(data->set.global_dns_cache &&
518 (data->dns.hostcachetype != HCACHE_GLOBAL)) {
519 /* global dns cache was requested but still isn't */
520 struct curl_hash *ptr;
522 if(data->dns.hostcachetype == HCACHE_PRIVATE) {
523 /* if the current cache is private, kill it first */
524 Curl_hash_destroy(data->dns.hostcache);
525 data->dns.hostcachetype = HCACHE_NONE;
526 data->dns.hostcache = NULL;
529 ptr = Curl_global_host_cache_init();
531 /* only do this if the global cache init works */
532 data->dns.hostcache = ptr;
533 data->dns.hostcachetype = HCACHE_GLOBAL;
537 if(!data->dns.hostcache) {
538 data->dns.hostcachetype = HCACHE_PRIVATE;
539 data->dns.hostcache = Curl_mk_dnscache();
541 if(!data->dns.hostcache)
542 /* While we possibly could survive and do good without a host cache,
543 the fact that creating it failed indicates that things are truly
544 screwed up and we should bail out! */
545 return CURLE_OUT_OF_MEMORY;
550 if(!data->state.connc) {
551 /* oops, no connection cache, make one up */
552 data->state.connc = Curl_mk_connc(CONNCACHE_PRIVATE, -1L);
553 if(!data->state.connc)
554 return CURLE_OUT_OF_MEMORY;
557 return Curl_perform(data);
562 * curl_easy_cleanup() is the external interface to cleaning/freeing the given
565 void curl_easy_cleanup(CURL *curl)
567 struct SessionHandle *data = (struct SessionHandle *)curl;
576 * Store a pointed to the multi handle within the easy handle's data struct.
578 void Curl_easy_addmulti(struct SessionHandle *data,
583 /* the association is cleared, mark the easy handle as not used by an
585 data->state.used_interface = Curl_if_none;
588 void Curl_easy_initHandleData(struct SessionHandle *data)
590 memset(&data->req, 0, sizeof(struct SingleRequest));
592 data->req.maxdownload = -1;
596 * curl_easy_getinfo() is an external interface that allows an app to retrieve
597 * information from a performed transfer and similar.
599 #undef curl_easy_getinfo
600 CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ...)
604 struct SessionHandle *data = (struct SessionHandle *)curl;
607 paramp = va_arg(arg, void *);
609 return Curl_getinfo(data, info, paramp);
613 * curl_easy_duphandle() is an external interface to allow duplication of a
614 * given input easy handle. The returned handle will be a new working handle
615 * with all options set exactly as the input source handle.
617 CURL *curl_easy_duphandle(CURL *incurl)
620 struct SessionHandle *data=(struct SessionHandle *)incurl;
622 struct SessionHandle *outcurl = calloc(sizeof(struct SessionHandle), 1);
625 return NULL; /* failure */
630 * We setup a few buffers we need. We should probably make them
631 * get setup on-demand in the code, as that would probably decrease
632 * the likeliness of us forgetting to init a buffer here in the future.
634 outcurl->state.headerbuff = malloc(HEADERSIZE);
635 if(!outcurl->state.headerbuff) {
638 outcurl->state.headersize=HEADERSIZE;
640 /* copy all userdefined values */
641 if(Curl_dupset(outcurl, data) != CURLE_OK)
644 /* the connection cache is setup on demand */
645 outcurl->state.connc = NULL;
647 outcurl->state.lastconnect = -1;
649 outcurl->progress.flags = data->progress.flags;
650 outcurl->progress.callback = data->progress.callback;
652 #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
654 /* If cookies are enabled in the parent handle, we enable them
655 in the clone as well! */
656 outcurl->cookies = Curl_cookie_init(data,
657 data->cookies->filename,
659 data->set.cookiesession);
660 if(!outcurl->cookies) {
664 #endif /* CURL_DISABLE_HTTP */
666 /* duplicate all values in 'change' */
668 #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
669 if(data->change.cookielist) {
670 outcurl->change.cookielist =
671 Curl_slist_duplicate(data->change.cookielist);
673 if (!outcurl->change.cookielist)
676 #endif /* CURL_DISABLE_HTTP */
678 if(data->change.url) {
679 outcurl->change.url = strdup(data->change.url);
680 if(!outcurl->change.url)
682 outcurl->change.url_alloc = TRUE;
685 if(data->change.referer) {
686 outcurl->change.referer = strdup(data->change.referer);
687 if(!outcurl->change.referer)
689 outcurl->change.referer_alloc = TRUE;
693 /* If we use ares, we setup a new ares channel for the new handle */
694 if(ARES_SUCCESS != ares_init(&outcurl->state.areschannel))
698 #if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV)
699 outcurl->inbound_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
700 CURL_ICONV_CODESET_OF_NETWORK);
701 outcurl->outbound_cd = iconv_open(CURL_ICONV_CODESET_OF_NETWORK,
702 CURL_ICONV_CODESET_OF_HOST);
703 outcurl->utf8_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
704 CURL_ICONV_CODESET_FOR_UTF8);
707 Curl_easy_initHandleData(outcurl);
709 outcurl->magic = CURLEASY_MAGIC_NUMBER;
711 fail = FALSE; /* we reach this point and thus we are OK */
717 if(outcurl->state.connc &&
718 (outcurl->state.connc->type == CONNCACHE_PRIVATE))
719 Curl_rm_connc(outcurl->state.connc);
720 if(outcurl->state.headerbuff)
721 free(outcurl->state.headerbuff);
722 #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
723 if(outcurl->change.cookielist)
724 curl_slist_free_all(outcurl->change.cookielist);
726 if(outcurl->change.url)
727 free(outcurl->change.url);
728 if(outcurl->change.referer)
729 free(outcurl->change.referer);
730 Curl_freeset(outcurl);
731 free(outcurl); /* free the memory again */
740 * curl_easy_reset() is an external interface that allows an app to re-
741 * initialize a session handle to the default values.
743 void curl_easy_reset(CURL *curl)
745 struct SessionHandle *data = (struct SessionHandle *)curl;
747 Curl_safefree(data->state.pathbuffer);
748 data->state.pathbuffer=NULL;
750 Curl_safefree(data->state.proto.generic);
751 data->state.proto.generic=NULL;
753 /* zero out UserDefined data: */
755 memset(&data->set, 0, sizeof(struct UserDefined));
756 (void)Curl_init_userdefined(&data->set);
758 /* zero out Progress data: */
759 memset(&data->progress, 0, sizeof(struct Progress));
761 /* init Handle data */
762 Curl_easy_initHandleData(data);
764 data->progress.flags |= PGRS_HIDE;
765 data->state.current_speed = -1; /* init to negative == impossible */
769 * curl_easy_pause() allows an application to pause or unpause a specific
770 * transfer and direction. This function sets the full new state for the
771 * current connection this easy handle operates on.
773 * NOTE: if you have the receiving paused and you call this function to remove
774 * the pausing, you may get your write callback called at this point.
776 * Action is a bitmask consisting of CURLPAUSE_* bits in curl/curl.h
778 CURLcode curl_easy_pause(CURL *curl, int action)
780 struct SessionHandle *data = (struct SessionHandle *)curl;
781 struct SingleRequest *k = &data->req;
782 CURLcode result = CURLE_OK;
784 /* first switch off both pause bits */
785 int newstate = k->keepon &~ (KEEP_RECV_PAUSE| KEEP_SEND_PAUSE);
787 /* set the new desired pause bits */
788 newstate |= ((action & CURLPAUSE_RECV)?KEEP_RECV_PAUSE:0) |
789 ((action & CURLPAUSE_SEND)?KEEP_SEND_PAUSE:0);
791 /* put it back in the keepon */
792 k->keepon = newstate;
794 if(!(newstate & KEEP_RECV_PAUSE) && data->state.tempwrite) {
795 /* we have a buffer for sending that we now seem to be able to deliver since
796 the receive pausing is lifted! */
798 /* get the pointer, type and length in local copies since the function may
799 return PAUSE again and then we'll get a new copy allocted and stored in
800 the tempwrite variables */
801 char *tempwrite = data->state.tempwrite;
802 char *freewrite = tempwrite; /* store this pointer to free it later */
803 size_t tempsize = data->state.tempwritesize;
804 int temptype = data->state.tempwritetype;
807 /* clear tempwrite here just to make sure it gets cleared if there's no
808 further use of it, and make sure we don't clear it after the function
809 invoke as it may have been set to a new value by then */
810 data->state.tempwrite = NULL;
812 /* since the write callback API is define to never exceed
813 CURL_MAX_WRITE_SIZE bytes in a single call, and since we may in fact
814 have more data than that in our buffer here, we must loop sending the
815 data in multiple calls until there's no data left or we get another
818 A tricky part is that the function we call will "buffer" the data
819 itself when it pauses on a particular buffer, so we may need to do some
820 extra trickery if we get a pause return here.
823 chunklen = (tempsize > CURL_MAX_WRITE_SIZE)?CURL_MAX_WRITE_SIZE:tempsize;
825 result = Curl_client_write(data->state.current_conn,
826 temptype, tempwrite, chunklen);
828 /* failures abort the loop at once */
831 if(data->state.tempwrite && (tempsize - chunklen)) {
832 /* Ouch, the reading is again paused and the block we send is now
833 "cached". If this is the final chunk we can leave it like this, but
834 if we have more chunks that are cached after this, we need to free
835 the newly cached one and put back a version that is truly the entire
836 contents that is saved for later
840 /* note that tempsize is still the size as before the callback was
841 used, and thus the whole piece of data to keep */
842 newptr = realloc(data->state.tempwrite, tempsize);
845 free(data->state.tempwrite); /* free old area */
846 data->state.tempwrite = NULL;
847 result = CURLE_OUT_OF_MEMORY;
848 /* tempwrite will be freed further down */
851 data->state.tempwrite = newptr; /* store new pointer */
852 memcpy(newptr, tempwrite, tempsize);
853 data->state.tempwritesize = tempsize; /* store new size */
854 /* tempwrite will be freed further down */
855 break; /* go back to pausing until further notice */
858 tempsize -= chunklen; /* left after the call above */
859 tempwrite += chunklen; /* advance the pointer */
862 } while((result == CURLE_OK) && tempsize);
864 free(freewrite); /* this is unconditionally no longer used */
870 #ifdef CURL_DOES_CONVERSIONS
872 * Curl_convert_to_network() is an internal function
873 * for performing ASCII conversions on non-ASCII platforms.
875 CURLcode Curl_convert_to_network(struct SessionHandle *data,
876 char *buffer, size_t length)
880 if(data->set.convtonetwork) {
881 /* use translation callback */
882 rc = data->set.convtonetwork(buffer, length);
885 "CURLOPT_CONV_TO_NETWORK_FUNCTION callback returned %i: %s",
886 rc, curl_easy_strerror(rc));
891 /* do the translation ourselves */
892 char *input_ptr, *output_ptr;
893 size_t in_bytes, out_bytes, rc;
896 /* open an iconv conversion descriptor if necessary */
897 if(data->outbound_cd == (iconv_t)-1) {
898 data->outbound_cd = iconv_open(CURL_ICONV_CODESET_OF_NETWORK,
899 CURL_ICONV_CODESET_OF_HOST);
900 if(data->outbound_cd == (iconv_t)-1) {
903 "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s",
904 CURL_ICONV_CODESET_OF_NETWORK,
905 CURL_ICONV_CODESET_OF_HOST,
906 error, strerror(error));
907 return CURLE_CONV_FAILED;
911 input_ptr = output_ptr = buffer;
912 in_bytes = out_bytes = length;
913 rc = iconv(data->outbound_cd, (const char**)&input_ptr, &in_bytes,
914 &output_ptr, &out_bytes);
915 if((rc == ICONV_ERROR) || (in_bytes != 0)) {
918 "The Curl_convert_to_network iconv call failed with errno %i: %s",
919 error, strerror(error));
920 return CURLE_CONV_FAILED;
923 failf(data, "CURLOPT_CONV_TO_NETWORK_FUNCTION callback required");
924 return CURLE_CONV_REQD;
925 #endif /* HAVE_ICONV */
932 * Curl_convert_from_network() is an internal function
933 * for performing ASCII conversions on non-ASCII platforms.
935 CURLcode Curl_convert_from_network(struct SessionHandle *data,
936 char *buffer, size_t length)
940 if(data->set.convfromnetwork) {
941 /* use translation callback */
942 rc = data->set.convfromnetwork(buffer, length);
945 "CURLOPT_CONV_FROM_NETWORK_FUNCTION callback returned %i: %s",
946 rc, curl_easy_strerror(rc));
952 /* do the translation ourselves */
953 char *input_ptr, *output_ptr;
954 size_t in_bytes, out_bytes, rc;
957 /* open an iconv conversion descriptor if necessary */
958 if(data->inbound_cd == (iconv_t)-1) {
959 data->inbound_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
960 CURL_ICONV_CODESET_OF_NETWORK);
961 if(data->inbound_cd == (iconv_t)-1) {
964 "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s",
965 CURL_ICONV_CODESET_OF_HOST,
966 CURL_ICONV_CODESET_OF_NETWORK,
967 error, strerror(error));
968 return CURLE_CONV_FAILED;
972 input_ptr = output_ptr = buffer;
973 in_bytes = out_bytes = length;
974 rc = iconv(data->inbound_cd, (const char **)&input_ptr, &in_bytes,
975 &output_ptr, &out_bytes);
976 if((rc == ICONV_ERROR) || (in_bytes != 0)) {
979 "The Curl_convert_from_network iconv call failed with errno %i: %s",
980 error, strerror(error));
981 return CURLE_CONV_FAILED;
984 failf(data, "CURLOPT_CONV_FROM_NETWORK_FUNCTION callback required");
985 return CURLE_CONV_REQD;
986 #endif /* HAVE_ICONV */
993 * Curl_convert_from_utf8() is an internal function
994 * for performing UTF-8 conversions on non-ASCII platforms.
996 CURLcode Curl_convert_from_utf8(struct SessionHandle *data,
997 char *buffer, size_t length)
1001 if(data->set.convfromutf8) {
1002 /* use translation callback */
1003 rc = data->set.convfromutf8(buffer, length);
1004 if(rc != CURLE_OK) {
1006 "CURLOPT_CONV_FROM_UTF8_FUNCTION callback returned %i: %s",
1007 rc, curl_easy_strerror(rc));
1012 /* do the translation ourselves */
1013 const char *input_ptr;
1015 size_t in_bytes, out_bytes, rc;
1018 /* open an iconv conversion descriptor if necessary */
1019 if(data->utf8_cd == (iconv_t)-1) {
1020 data->utf8_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
1021 CURL_ICONV_CODESET_FOR_UTF8);
1022 if(data->utf8_cd == (iconv_t)-1) {
1025 "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s",
1026 CURL_ICONV_CODESET_OF_HOST,
1027 CURL_ICONV_CODESET_FOR_UTF8,
1028 error, strerror(error));
1029 return CURLE_CONV_FAILED;
1033 input_ptr = output_ptr = buffer;
1034 in_bytes = out_bytes = length;
1035 rc = iconv(data->utf8_cd, &input_ptr, &in_bytes,
1036 &output_ptr, &out_bytes);
1037 if((rc == ICONV_ERROR) || (in_bytes != 0)) {
1040 "The Curl_convert_from_utf8 iconv call failed with errno %i: %s",
1041 error, strerror(error));
1042 return CURLE_CONV_FAILED;
1044 if(output_ptr < input_ptr) {
1045 /* null terminate the now shorter output string */
1049 failf(data, "CURLOPT_CONV_FROM_UTF8_FUNCTION callback required");
1050 return CURLE_CONV_REQD;
1051 #endif /* HAVE_ICONV */
1057 #endif /* CURL_DOES_CONVERSIONS */
1059 static CURLcode easy_connection(struct SessionHandle *data,
1061 struct connectdata **connp)
1067 return CURLE_BAD_FUNCTION_ARGUMENT;
1069 /* only allow these to be called on handles with CURLOPT_CONNECT_ONLY */
1070 if(!data->set.connect_only) {
1071 failf(data, "CONNECT_ONLY is required!");
1072 return CURLE_UNSUPPORTED_PROTOCOL;
1075 ret = Curl_getconnectinfo(data, &sockfd, connp);
1080 failf(data, "Failed to get recent socket");
1081 return CURLE_UNSUPPORTED_PROTOCOL;
1084 *sfd = (curl_socket_t)sockfd; /* we know that this is actually a socket
1085 descriptor so the typecast is fine here */
1091 * Receives data from the connected socket. Use after successful
1092 * curl_easy_perform() with CURLOPT_CONNECT_ONLY option.
1093 * Returns CURLE_OK on success, error code on error.
1095 CURLcode curl_easy_recv(CURL *curl, void *buffer, size_t buflen, size_t *n)
1101 struct connectdata *c;
1102 struct SessionHandle *data = (struct SessionHandle *)curl;
1104 ret = easy_connection(data, &sfd, &c);
1109 ret1 = Curl_read(c, sfd, buffer, buflen, &n1);
1114 if(ret1 != CURLE_OK)
1115 return (CURLcode)ret1;
1123 * Sends data over the connected socket. Use after successful
1124 * curl_easy_perform() with CURLOPT_CONNECT_ONLY option.
1126 CURLcode curl_easy_send(CURL *curl, const void *buffer, size_t buflen,
1132 struct connectdata *c = NULL;
1133 struct SessionHandle *data = (struct SessionHandle *)curl;
1135 ret = easy_connection(data, &sfd, &c);
1140 ret = Curl_write(c, sfd, buffer, buflen, &n1);
1143 return CURLE_SEND_ERROR;
1146 if((CURLE_OK == ret) && (0 == n1))