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>
84 #include "sendf.h" /* for failf function prototype */
85 #include "http_ntlm.h"
86 #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_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)
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);
509 data->dns.hostcachetype = HCACHE_NONE;
510 data->dns.hostcache = NULL;
513 ptr = Curl_global_host_cache_init();
515 /* only do this if the global cache init works */
516 data->dns.hostcache = ptr;
517 data->dns.hostcachetype = HCACHE_GLOBAL;
521 if(!data->dns.hostcache) {
522 data->dns.hostcachetype = HCACHE_PRIVATE;
523 data->dns.hostcache = Curl_mk_dnscache();
525 if(!data->dns.hostcache)
526 /* While we possibly could survive and do good without a host cache,
527 the fact that creating it failed indicates that things are truly
528 screwed up and we should bail out! */
529 return CURLE_OUT_OF_MEMORY;
534 if(!data->state.connc) {
535 /* oops, no connection cache, make one up */
536 data->state.connc = Curl_mk_connc(CONNCACHE_PRIVATE, -1);
537 if(!data->state.connc)
538 return CURLE_OUT_OF_MEMORY;
541 return Curl_perform(data);
546 * curl_easy_cleanup() is the external interface to cleaning/freeing the given
549 void curl_easy_cleanup(CURL *curl)
551 struct SessionHandle *data = (struct SessionHandle *)curl;
560 * Store a pointed to the multi handle within the easy handle's data struct.
562 void Curl_easy_addmulti(struct SessionHandle *data,
567 /* the association is cleared, mark the easy handle as not used by an
569 data->state.used_interface = Curl_if_none;
572 void Curl_easy_initHandleData(struct SessionHandle *data)
574 memset(&data->req, 0, sizeof(struct SingleRequest));
576 data->req.maxdownload = -1;
580 * curl_easy_getinfo() is an external interface that allows an app to retrieve
581 * information from a performed transfer and similar.
583 #undef curl_easy_getinfo
584 CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ...)
588 struct SessionHandle *data = (struct SessionHandle *)curl;
591 paramp = va_arg(arg, void *);
593 return Curl_getinfo(data, info, paramp);
597 * curl_easy_duphandle() is an external interface to allow duplication of a
598 * given input easy handle. The returned handle will be a new working handle
599 * with all options set exactly as the input source handle.
601 CURL *curl_easy_duphandle(CURL *incurl)
604 struct SessionHandle *data=(struct SessionHandle *)incurl;
606 struct SessionHandle *outcurl = calloc(sizeof(struct SessionHandle), 1);
609 return NULL; /* failure */
614 * We setup a few buffers we need. We should probably make them
615 * get setup on-demand in the code, as that would probably decrease
616 * the likeliness of us forgetting to init a buffer here in the future.
618 outcurl->state.headerbuff = malloc(HEADERSIZE);
619 if(!outcurl->state.headerbuff) {
622 outcurl->state.headersize=HEADERSIZE;
624 /* copy all userdefined values */
625 if(Curl_dupset(outcurl, data) != CURLE_OK)
628 /* the connection cache is setup on demand */
629 outcurl->state.connc = NULL;
631 outcurl->state.lastconnect = -1;
633 outcurl->progress.flags = data->progress.flags;
634 outcurl->progress.callback = data->progress.callback;
636 #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
638 /* If cookies are enabled in the parent handle, we enable them
639 in the clone as well! */
640 outcurl->cookies = Curl_cookie_init(data,
641 data->cookies->filename,
643 data->set.cookiesession);
644 if(!outcurl->cookies) {
648 #endif /* CURL_DISABLE_HTTP */
650 /* duplicate all values in 'change' */
652 #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
653 if(data->change.cookielist) {
654 outcurl->change.cookielist =
655 Curl_slist_duplicate(data->change.cookielist);
657 if (!outcurl->change.cookielist)
660 #endif /* CURL_DISABLE_HTTP */
662 if(data->change.url) {
663 outcurl->change.url = strdup(data->change.url);
664 if(!outcurl->change.url)
666 outcurl->change.url_alloc = TRUE;
669 if(data->change.referer) {
670 outcurl->change.referer = strdup(data->change.referer);
671 if(!outcurl->change.referer)
673 outcurl->change.referer_alloc = TRUE;
677 /* If we use ares, we setup a new ares channel for the new handle */
678 if(ARES_SUCCESS != ares_init(&outcurl->state.areschannel))
682 #if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV)
683 outcurl->inbound_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
684 CURL_ICONV_CODESET_OF_NETWORK);
685 outcurl->outbound_cd = iconv_open(CURL_ICONV_CODESET_OF_NETWORK,
686 CURL_ICONV_CODESET_OF_HOST);
687 outcurl->utf8_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
688 CURL_ICONV_CODESET_FOR_UTF8);
691 Curl_easy_initHandleData(outcurl);
693 outcurl->magic = CURLEASY_MAGIC_NUMBER;
695 fail = FALSE; /* we reach this point and thus we are OK */
701 if(outcurl->state.connc &&
702 (outcurl->state.connc->type == CONNCACHE_PRIVATE))
703 Curl_rm_connc(outcurl->state.connc);
704 if(outcurl->state.headerbuff)
705 free(outcurl->state.headerbuff);
706 #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
707 if(outcurl->change.cookielist)
708 curl_slist_free_all(outcurl->change.cookielist);
710 if(outcurl->change.url)
711 free(outcurl->change.url);
712 if(outcurl->change.referer)
713 free(outcurl->change.referer);
714 Curl_freeset(outcurl);
715 free(outcurl); /* free the memory again */
724 * curl_easy_reset() is an external interface that allows an app to re-
725 * initialize a session handle to the default values.
727 void curl_easy_reset(CURL *curl)
729 struct SessionHandle *data = (struct SessionHandle *)curl;
731 Curl_safefree(data->state.pathbuffer);
732 data->state.pathbuffer=NULL;
734 Curl_safefree(data->state.proto.generic);
735 data->state.proto.generic=NULL;
737 /* zero out UserDefined data: */
739 memset(&data->set, 0, sizeof(struct UserDefined));
740 (void)Curl_init_userdefined(&data->set);
742 /* zero out Progress data: */
743 memset(&data->progress, 0, sizeof(struct Progress));
745 /* init Handle data */
746 Curl_easy_initHandleData(data);
748 data->progress.flags |= PGRS_HIDE;
749 data->state.current_speed = -1; /* init to negative == impossible */
753 * curl_easy_pause() allows an application to pause or unpause a specific
754 * transfer and direction. This function sets the full new state for the
755 * current connection this easy handle operates on.
757 * NOTE: if you have the receiving paused and you call this function to remove
758 * the pausing, you may get your write callback called at this point.
760 * Action is a bitmask consisting of CURLPAUSE_* bits in curl/curl.h
762 CURLcode curl_easy_pause(CURL *curl, int action)
764 struct SessionHandle *data = (struct SessionHandle *)curl;
765 struct SingleRequest *k = &data->req;
766 CURLcode result = CURLE_OK;
768 /* first switch off both pause bits */
769 int newstate = k->keepon &~ (KEEP_READ_PAUSE| KEEP_WRITE_PAUSE);
771 /* set the new desired pause bits */
772 newstate |= ((action & CURLPAUSE_RECV)?KEEP_READ_PAUSE:0) |
773 ((action & CURLPAUSE_SEND)?KEEP_WRITE_PAUSE:0);
775 /* put it back in the keepon */
776 k->keepon = newstate;
778 if(!(newstate & KEEP_READ_PAUSE) && data->state.tempwrite) {
779 /* we have a buffer for writing that we now seem to be able to deliver since
780 the receive pausing is lifted! */
782 /* get the pointer, type and length in local copies since the function may
783 return PAUSE again and then we'll get a new copy allocted and stored in
784 the tempwrite variables */
785 char *tempwrite = data->state.tempwrite;
786 char *freewrite = tempwrite; /* store this pointer to free it later */
787 size_t tempsize = data->state.tempwritesize;
788 int temptype = data->state.tempwritetype;
791 /* clear tempwrite here just to make sure it gets cleared if there's no
792 further use of it, and make sure we don't clear it after the function
793 invoke as it may have been set to a new value by then */
794 data->state.tempwrite = NULL;
796 /* since the write callback API is define to never exceed
797 CURL_MAX_WRITE_SIZE bytes in a single call, and since we may in fact
798 have more data than that in our buffer here, we must loop sending the
799 data in multiple calls until there's no data left or we get another
802 A tricky part is that the function we call will "buffer" the data
803 itself when it pauses on a particular buffer, so we may need to do some
804 extra trickery if we get a pause return here.
807 chunklen = (tempsize > CURL_MAX_WRITE_SIZE)?CURL_MAX_WRITE_SIZE:tempsize;
809 result = Curl_client_write(data->state.current_conn,
810 temptype, tempwrite, chunklen);
812 /* failures abort the loop at once */
815 if(data->state.tempwrite && (tempsize - chunklen)) {
816 /* Ouch, the reading is again paused and the block we send is now
817 "cached". If this is the final chunk we can leave it like this, but
818 if we have more chunks that are cached after this, we need to free
819 the newly cached one and put back a version that is truly the entire
820 contents that is saved for later
824 /* note that tempsize is still the size as before the callback was
825 used, and thus the whole piece of data to keep */
826 newptr = realloc(data->state.tempwrite, tempsize);
829 free(data->state.tempwrite); /* free old area */
830 data->state.tempwrite = NULL;
831 result = CURLE_OUT_OF_MEMORY;
832 /* tempwrite will be freed further down */
835 data->state.tempwrite = newptr; /* store new pointer */
836 memcpy(newptr, tempwrite, tempsize);
837 data->state.tempwritesize = tempsize; /* store new size */
838 /* tempwrite will be freed further down */
839 break; /* go back to pausing until further notice */
842 tempsize -= chunklen; /* left after the call above */
843 tempwrite += chunklen; /* advance the pointer */
846 } while((result == CURLE_OK) && tempsize);
848 free(freewrite); /* this is unconditionally no longer used */
854 #ifdef CURL_DOES_CONVERSIONS
856 * Curl_convert_to_network() is an internal function
857 * for performing ASCII conversions on non-ASCII platforms.
859 CURLcode Curl_convert_to_network(struct SessionHandle *data,
860 char *buffer, size_t length)
864 if(data->set.convtonetwork) {
865 /* use translation callback */
866 rc = data->set.convtonetwork(buffer, length);
869 "CURLOPT_CONV_TO_NETWORK_FUNCTION callback returned %i: %s",
870 rc, curl_easy_strerror(rc));
875 /* do the translation ourselves */
876 char *input_ptr, *output_ptr;
877 size_t in_bytes, out_bytes, rc;
880 /* open an iconv conversion descriptor if necessary */
881 if(data->outbound_cd == (iconv_t)-1) {
882 data->outbound_cd = iconv_open(CURL_ICONV_CODESET_OF_NETWORK,
883 CURL_ICONV_CODESET_OF_HOST);
884 if(data->outbound_cd == (iconv_t)-1) {
887 "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s",
888 CURL_ICONV_CODESET_OF_NETWORK,
889 CURL_ICONV_CODESET_OF_HOST,
890 error, strerror(error));
891 return CURLE_CONV_FAILED;
895 input_ptr = output_ptr = buffer;
896 in_bytes = out_bytes = length;
897 rc = iconv(data->outbound_cd, (const char**)&input_ptr, &in_bytes,
898 &output_ptr, &out_bytes);
899 if((rc == ICONV_ERROR) || (in_bytes != 0)) {
902 "The Curl_convert_to_network iconv call failed with errno %i: %s",
903 error, strerror(error));
904 return CURLE_CONV_FAILED;
907 failf(data, "CURLOPT_CONV_TO_NETWORK_FUNCTION callback required");
908 return CURLE_CONV_REQD;
909 #endif /* HAVE_ICONV */
916 * Curl_convert_from_network() is an internal function
917 * for performing ASCII conversions on non-ASCII platforms.
919 CURLcode Curl_convert_from_network(struct SessionHandle *data,
920 char *buffer, size_t length)
924 if(data->set.convfromnetwork) {
925 /* use translation callback */
926 rc = data->set.convfromnetwork(buffer, length);
929 "CURLOPT_CONV_FROM_NETWORK_FUNCTION callback returned %i: %s",
930 rc, curl_easy_strerror(rc));
936 /* do the translation ourselves */
937 char *input_ptr, *output_ptr;
938 size_t in_bytes, out_bytes, rc;
941 /* open an iconv conversion descriptor if necessary */
942 if(data->inbound_cd == (iconv_t)-1) {
943 data->inbound_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
944 CURL_ICONV_CODESET_OF_NETWORK);
945 if(data->inbound_cd == (iconv_t)-1) {
948 "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s",
949 CURL_ICONV_CODESET_OF_HOST,
950 CURL_ICONV_CODESET_OF_NETWORK,
951 error, strerror(error));
952 return CURLE_CONV_FAILED;
956 input_ptr = output_ptr = buffer;
957 in_bytes = out_bytes = length;
958 rc = iconv(data->inbound_cd, (const char **)&input_ptr, &in_bytes,
959 &output_ptr, &out_bytes);
960 if((rc == ICONV_ERROR) || (in_bytes != 0)) {
963 "The Curl_convert_from_network iconv call failed with errno %i: %s",
964 error, strerror(error));
965 return CURLE_CONV_FAILED;
968 failf(data, "CURLOPT_CONV_FROM_NETWORK_FUNCTION callback required");
969 return CURLE_CONV_REQD;
970 #endif /* HAVE_ICONV */
977 * Curl_convert_from_utf8() is an internal function
978 * for performing UTF-8 conversions on non-ASCII platforms.
980 CURLcode Curl_convert_from_utf8(struct SessionHandle *data,
981 char *buffer, size_t length)
985 if(data->set.convfromutf8) {
986 /* use translation callback */
987 rc = data->set.convfromutf8(buffer, length);
990 "CURLOPT_CONV_FROM_UTF8_FUNCTION callback returned %i: %s",
991 rc, curl_easy_strerror(rc));
996 /* do the translation ourselves */
997 const char *input_ptr;
999 size_t in_bytes, out_bytes, rc;
1002 /* open an iconv conversion descriptor if necessary */
1003 if(data->utf8_cd == (iconv_t)-1) {
1004 data->utf8_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
1005 CURL_ICONV_CODESET_FOR_UTF8);
1006 if(data->utf8_cd == (iconv_t)-1) {
1009 "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s",
1010 CURL_ICONV_CODESET_OF_HOST,
1011 CURL_ICONV_CODESET_FOR_UTF8,
1012 error, strerror(error));
1013 return CURLE_CONV_FAILED;
1017 input_ptr = output_ptr = buffer;
1018 in_bytes = out_bytes = length;
1019 rc = iconv(data->utf8_cd, &input_ptr, &in_bytes,
1020 &output_ptr, &out_bytes);
1021 if((rc == ICONV_ERROR) || (in_bytes != 0)) {
1024 "The Curl_convert_from_utf8 iconv call failed with errno %i: %s",
1025 error, strerror(error));
1026 return CURLE_CONV_FAILED;
1028 if(output_ptr < input_ptr) {
1029 /* null terminate the now shorter output string */
1033 failf(data, "CURLOPT_CONV_FROM_UTF8_FUNCTION callback required");
1034 return CURLE_CONV_REQD;
1035 #endif /* HAVE_ICONV */
1041 #endif /* CURL_DOES_CONVERSIONS */
1043 static CURLcode easy_connection(struct SessionHandle *data,
1045 struct connectdata **connp)
1051 return CURLE_BAD_FUNCTION_ARGUMENT;
1053 /* only allow these to be called on handles with CURLOPT_CONNECT_ONLY */
1054 if(!data->set.connect_only) {
1055 failf(data, "CONNECT_ONLY is required!");
1056 return CURLE_UNSUPPORTED_PROTOCOL;
1059 ret = Curl_getconnectinfo(data, &sockfd, connp);
1064 failf(data, "Failed to get recent socket");
1065 return CURLE_UNSUPPORTED_PROTOCOL;
1068 *sfd = (curl_socket_t)sockfd; /* we know that this is actually a socket
1069 descriptor so the typecast is fine here */
1075 * Receives data from the connected socket. Use after successful
1076 * curl_easy_perform() with CURLOPT_CONNECT_ONLY option.
1077 * Returns CURLE_OK on success, error code on error.
1079 CURLcode curl_easy_recv(CURL *curl, void *buffer, size_t buflen, size_t *n)
1085 struct connectdata *c;
1086 struct SessionHandle *data = (struct SessionHandle *)curl;
1088 ret = easy_connection(data, &sfd, &c);
1093 ret1 = Curl_read(c, sfd, buffer, buflen, &n1);
1099 return CURLE_RECV_ERROR;
1107 * Sends data over the connected socket. Use after successful
1108 * curl_easy_perform() with CURLOPT_CONNECT_ONLY option.
1110 CURLcode curl_easy_send(CURL *curl, const void *buffer, size_t buflen,
1116 struct connectdata *c = NULL;
1117 struct SessionHandle *data = (struct SessionHandle *)curl;
1119 ret = easy_connection(data, &sfd, &c);
1124 ret = Curl_write(c, sfd, buffer, buflen, &n1);
1127 return CURLE_SEND_ERROR;
1130 if((CURLE_OK == ret) && (0 == n1))