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)
630 struct SessionHandle *data=(struct SessionHandle *)incurl;
632 struct SessionHandle *outcurl = calloc(1, sizeof(struct SessionHandle));
635 return NULL; /* failure */
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.
644 outcurl->state.headerbuff = malloc(HEADERSIZE);
645 if(!outcurl->state.headerbuff) {
648 outcurl->state.headersize=HEADERSIZE;
650 /* copy all userdefined values */
651 if(Curl_dupset(outcurl, data) != CURLE_OK)
654 /* the connection cache is setup on demand */
655 outcurl->state.connc = NULL;
657 outcurl->state.lastconnect = -1;
659 outcurl->progress.flags = data->progress.flags;
660 outcurl->progress.callback = data->progress.callback;
662 #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_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,
669 data->set.cookiesession);
670 if(!outcurl->cookies) {
674 #endif /* CURL_DISABLE_HTTP */
676 /* duplicate all values in 'change' */
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);
683 if (!outcurl->change.cookielist)
686 #endif /* CURL_DISABLE_HTTP */
688 if(data->change.url) {
689 outcurl->change.url = strdup(data->change.url);
690 if(!outcurl->change.url)
692 outcurl->change.url_alloc = TRUE;
695 if(data->change.referer) {
696 outcurl->change.referer = strdup(data->change.referer);
697 if(!outcurl->change.referer)
699 outcurl->change.referer_alloc = TRUE;
703 /* If we use ares, we setup a new ares channel for the new handle */
704 if(ARES_SUCCESS != ares_init(&outcurl->state.areschannel))
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);
717 Curl_easy_initHandleData(outcurl);
719 outcurl->magic = CURLEASY_MAGIC_NUMBER;
721 fail = FALSE; /* we reach this point and thus we are OK */
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);
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 */
750 * curl_easy_reset() is an external interface that allows an app to re-
751 * initialize a session handle to the default values.
753 void curl_easy_reset(CURL *curl)
755 struct SessionHandle *data = (struct SessionHandle *)curl;
757 Curl_safefree(data->state.pathbuffer);
758 data->state.pathbuffer=NULL;
760 Curl_safefree(data->state.proto.generic);
761 data->state.proto.generic=NULL;
763 /* zero out UserDefined data: */
765 memset(&data->set, 0, sizeof(struct UserDefined));
766 (void)Curl_init_userdefined(&data->set);
768 /* zero out Progress data: */
769 memset(&data->progress, 0, sizeof(struct Progress));
771 /* init Handle data */
772 Curl_easy_initHandleData(data);
774 data->progress.flags |= PGRS_HIDE;
775 data->state.current_speed = -1; /* init to negative == impossible */
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.
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.
786 * Action is a bitmask consisting of CURLPAUSE_* bits in curl/curl.h
788 CURLcode curl_easy_pause(CURL *curl, int action)
790 struct SessionHandle *data = (struct SessionHandle *)curl;
791 struct SingleRequest *k = &data->req;
792 CURLcode result = CURLE_OK;
794 /* first switch off both pause bits */
795 int newstate = k->keepon &~ (KEEP_RECV_PAUSE| KEEP_SEND_PAUSE);
797 /* set the new desired pause bits */
798 newstate |= ((action & CURLPAUSE_RECV)?KEEP_RECV_PAUSE:0) |
799 ((action & CURLPAUSE_SEND)?KEEP_SEND_PAUSE:0);
801 /* put it back in the keepon */
802 k->keepon = newstate;
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! */
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;
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;
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
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.
833 chunklen = (tempsize > CURL_MAX_WRITE_SIZE)?CURL_MAX_WRITE_SIZE:tempsize;
835 result = Curl_client_write(data->state.current_conn,
836 temptype, tempwrite, chunklen);
838 /* failures abort the loop at once */
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
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);
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 */
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 */
868 tempsize -= chunklen; /* left after the call above */
869 tempwrite += chunklen; /* advance the pointer */
872 } while((result == CURLE_OK) && tempsize);
874 free(freewrite); /* this is unconditionally no longer used */
880 #ifdef CURL_DOES_CONVERSIONS
882 * Curl_convert_to_network() is an internal function
883 * for performing ASCII conversions on non-ASCII platforms.
885 CURLcode Curl_convert_to_network(struct SessionHandle *data,
886 char *buffer, size_t length)
890 if(data->set.convtonetwork) {
891 /* use translation callback */
892 rc = data->set.convtonetwork(buffer, length);
895 "CURLOPT_CONV_TO_NETWORK_FUNCTION callback returned %d: %s",
896 (int)rc, curl_easy_strerror(rc));
902 /* do the translation ourselves */
903 char *input_ptr, *output_ptr;
904 size_t in_bytes, out_bytes, rc;
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) {
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;
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)) {
929 "The Curl_convert_to_network iconv call failed with errno %i: %s",
930 error, strerror(error));
931 return CURLE_CONV_FAILED;
934 failf(data, "CURLOPT_CONV_TO_NETWORK_FUNCTION callback required");
935 return CURLE_CONV_REQD;
936 #endif /* HAVE_ICONV */
943 * Curl_convert_from_network() is an internal function
944 * for performing ASCII conversions on non-ASCII platforms.
946 CURLcode Curl_convert_from_network(struct SessionHandle *data,
947 char *buffer, size_t length)
951 if(data->set.convfromnetwork) {
952 /* use translation callback */
953 rc = data->set.convfromnetwork(buffer, length);
956 "CURLOPT_CONV_FROM_NETWORK_FUNCTION callback returned %d: %s",
957 (int)rc, curl_easy_strerror(rc));
963 /* do the translation ourselves */
964 char *input_ptr, *output_ptr;
965 size_t in_bytes, out_bytes, rc;
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) {
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;
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)) {
990 "The Curl_convert_from_network iconv call failed with errno %i: %s",
991 error, strerror(error));
992 return CURLE_CONV_FAILED;
995 failf(data, "CURLOPT_CONV_FROM_NETWORK_FUNCTION callback required");
996 return CURLE_CONV_REQD;
997 #endif /* HAVE_ICONV */
1004 * Curl_convert_from_utf8() is an internal function
1005 * for performing UTF-8 conversions on non-ASCII platforms.
1007 CURLcode Curl_convert_from_utf8(struct SessionHandle *data,
1008 char *buffer, size_t length)
1012 if(data->set.convfromutf8) {
1013 /* use translation callback */
1014 rc = data->set.convfromutf8(buffer, length);
1015 if(rc != CURLE_OK) {
1017 "CURLOPT_CONV_FROM_UTF8_FUNCTION callback returned %d: %s",
1018 (int)rc, curl_easy_strerror(rc));
1024 /* do the translation ourselves */
1025 const char *input_ptr;
1027 size_t in_bytes, out_bytes, rc;
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) {
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;
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)) {
1052 "The Curl_convert_from_utf8 iconv call failed with errno %i: %s",
1053 error, strerror(error));
1054 return CURLE_CONV_FAILED;
1056 if(output_ptr < input_ptr) {
1057 /* null terminate the now shorter output string */
1061 failf(data, "CURLOPT_CONV_FROM_UTF8_FUNCTION callback required");
1062 return CURLE_CONV_REQD;
1063 #endif /* HAVE_ICONV */
1069 #endif /* CURL_DOES_CONVERSIONS */
1071 static CURLcode easy_connection(struct SessionHandle *data,
1073 struct connectdata **connp)
1079 return CURLE_BAD_FUNCTION_ARGUMENT;
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;
1087 ret = Curl_getconnectinfo(data, &sockfd, connp);
1092 failf(data, "Failed to get recent socket");
1093 return CURLE_UNSUPPORTED_PROTOCOL;
1096 *sfd = (curl_socket_t)sockfd; /* we know that this is actually a socket
1097 descriptor so the typecast is fine here */
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.
1107 CURLcode curl_easy_recv(CURL *curl, void *buffer, size_t buflen, size_t *n)
1113 struct connectdata *c;
1114 struct SessionHandle *data = (struct SessionHandle *)curl;
1116 ret = easy_connection(data, &sfd, &c);
1121 ret1 = Curl_read(c, sfd, buffer, buflen, &n1);
1126 if(ret1 != CURLE_OK)
1127 return (CURLcode)ret1;
1135 * Sends data over the connected socket. Use after successful
1136 * curl_easy_perform() with CURLOPT_CONNECT_ONLY option.
1138 CURLcode curl_easy_send(CURL *curl, const void *buffer, size_t buflen,
1144 struct connectdata *c = NULL;
1145 struct SessionHandle *data = (struct SessionHandle *)curl;
1147 ret = easy_connection(data, &sfd, &c);
1152 ret = Curl_write(c, sfd, buffer, buflen, &n1);
1155 return CURLE_SEND_ERROR;
1158 if((CURLE_OK == ret) && (0 == n1))