1/*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. 9 * 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. 13 * 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. 17 * 18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 19 * KIND, either express or implied. 20 * 21 ***************************************************************************/ 22 23#include "setup.h" 24 25/* -- WIN32 approved -- */ 26#include <stdio.h> 27#include <string.h> 28#include <stdarg.h> 29#include <stdlib.h> 30#include <ctype.h> 31#include <errno.h> 32 33#include "strequal.h" 34 35#ifdef WIN32 36#include <time.h> 37#include <io.h> 38#else 39#ifdef HAVE_SYS_SOCKET_H 40#include <sys/socket.h> 41#endif 42#ifdef HAVE_NETINET_IN_H 43#include <netinet/in.h> 44#endif 45#ifdef HAVE_SYS_TIME_H 46#include <sys/time.h> 47#endif 48#ifdef HAVE_UNISTD_H 49#include <unistd.h> 50#endif 51#ifdef HAVE_NETDB_H 52#include <netdb.h> 53#endif 54#ifdef HAVE_ARPA_INET_H 55#include <arpa/inet.h> 56#endif 57#ifdef HAVE_NET_IF_H 58#include <net/if.h> 59#endif 60#ifdef HAVE_SYS_IOCTL_H 61#include <sys/ioctl.h> 62#endif 63 64#ifdef HAVE_SYS_PARAM_H 65#include <sys/param.h> 66#endif 67 68#endif /* WIN32 ... */ 69 70#include "urldata.h" 71#include <curl/curl.h> 72#include "transfer.h" 73#include "sslgen.h" 74#include "url.h" 75#include "getinfo.h" 76#include "hostip.h" 77#include "share.h" 78#include "strdup.h" 79#include "curl_memory.h" 80#include "progress.h" 81#include "easyif.h" 82#include "select.h" 83#include "sendf.h" /* for failf function prototype */ 84#include "http_ntlm.h" 85#include "connect.h" /* for Curl_getconnectinfo */ 86#include "slist.h" 87#include "curl_rand.h" 88#include "non-ascii.h" 89#include "warnless.h" 90 91#define _MPRINTF_REPLACE /* use our functions only */ 92#include <curl/mprintf.h> 93 94/* The last #include file should be: */ 95#include "memdebug.h" 96 97/* win32_cleanup() is for win32 socket cleanup functionality, the opposite 98 of win32_init() */ 99static void win32_cleanup(void) 100{ 101#ifdef USE_WINSOCK 102 WSACleanup(); 103#endif 104#ifdef USE_WINDOWS_SSPI 105 Curl_sspi_global_cleanup(); 106#endif 107} 108 109/* win32_init() performs win32 socket initialization to properly setup the 110 stack to allow networking */ 111static CURLcode win32_init(void) 112{ 113#ifdef USE_WINSOCK 114 WORD wVersionRequested; 115 WSADATA wsaData; 116 int res; 117 118#if defined(ENABLE_IPV6) && (USE_WINSOCK < 2) 119 Error IPV6_requires_winsock2 120#endif 121 122 wVersionRequested = MAKEWORD(USE_WINSOCK, USE_WINSOCK); 123 124 res = WSAStartup(wVersionRequested, &wsaData); 125 126 if(res != 0) 127 /* Tell the user that we couldn't find a useable */ 128 /* winsock.dll. */ 129 return CURLE_FAILED_INIT; 130 131 /* Confirm that the Windows Sockets DLL supports what we need.*/ 132 /* Note that if the DLL supports versions greater */ 133 /* than wVersionRequested, it will still return */ 134 /* wVersionRequested in wVersion. wHighVersion contains the */ 135 /* highest supported version. */ 136 137 if(LOBYTE( wsaData.wVersion ) != LOBYTE(wVersionRequested) || 138 HIBYTE( wsaData.wVersion ) != HIBYTE(wVersionRequested) ) { 139 /* Tell the user that we couldn't find a useable */ 140 141 /* winsock.dll. */ 142 WSACleanup(); 143 return CURLE_FAILED_INIT; 144 } 145 /* The Windows Sockets DLL is acceptable. Proceed. */ 146#endif 147 148#ifdef USE_WINDOWS_SSPI 149 { 150 CURLcode err = Curl_sspi_global_init(); 151 if(err != CURLE_OK) 152 return err; 153 } 154#endif 155 156 return CURLE_OK; 157} 158 159#ifdef USE_LIBIDN 160/* 161 * Initialise use of IDNA library. 162 * It falls back to ASCII if $CHARSET isn't defined. This doesn't work for 163 * idna_to_ascii_lz(). 164 */ 165static void idna_init (void) 166{ 167#ifdef WIN32 168 char buf[60]; 169 UINT cp = GetACP(); 170 171 if(!getenv("CHARSET") && cp > 0) { 172 snprintf(buf, sizeof(buf), "CHARSET=cp%u", cp); 173 putenv(buf); 174 } 175#else 176 /* to do? */ 177#endif 178} 179#endif /* USE_LIBIDN */ 180 181/* true globals -- for curl_global_init() and curl_global_cleanup() */ 182static unsigned int initialized; 183static long init_flags; 184 185/* 186 * strdup (and other memory functions) is redefined in complicated 187 * ways, but at this point it must be defined as the system-supplied strdup 188 * so the callback pointer is initialized correctly. 189 */ 190#if defined(_WIN32_WCE) 191#define system_strdup _strdup 192#elif !defined(HAVE_STRDUP) 193#define system_strdup curlx_strdup 194#else 195#define system_strdup strdup 196#endif 197 198#if defined(_MSC_VER) && defined(_DLL) && !defined(__POCC__) 199# pragma warning(disable:4232) /* MSVC extension, dllimport identity */ 200#endif 201 202#ifndef __SYMBIAN32__ 203/* 204 * If a memory-using function (like curl_getenv) is used before 205 * curl_global_init() is called, we need to have these pointers set already. 206 */ 207curl_malloc_callback Curl_cmalloc = (curl_malloc_callback)malloc; 208curl_free_callback Curl_cfree = (curl_free_callback)free; 209curl_realloc_callback Curl_crealloc = (curl_realloc_callback)realloc; 210curl_strdup_callback Curl_cstrdup = (curl_strdup_callback)system_strdup; 211curl_calloc_callback Curl_ccalloc = (curl_calloc_callback)calloc; 212#else 213/* 214 * Symbian OS doesn't support initialization to code in writeable static data. 215 * Initialization will occur in the curl_global_init() call. 216 */ 217curl_malloc_callback Curl_cmalloc; 218curl_free_callback Curl_cfree; 219curl_realloc_callback Curl_crealloc; 220curl_strdup_callback Curl_cstrdup; 221curl_calloc_callback Curl_ccalloc; 222#endif 223 224#if defined(_MSC_VER) && defined(_DLL) && !defined(__POCC__) 225# pragma warning(default:4232) /* MSVC extension, dllimport identity */ 226#endif 227 228/** 229 * curl_global_init() globally initializes cURL given a bitwise set of the 230 * different features of what to initialize. 231 */ 232CURLcode curl_global_init(long flags) 233{ 234 if(initialized++) 235 return CURLE_OK; 236 237 /* Setup the default memory functions here (again) */ 238 Curl_cmalloc = (curl_malloc_callback)malloc; 239 Curl_cfree = (curl_free_callback)free; 240 Curl_crealloc = (curl_realloc_callback)realloc; 241 Curl_cstrdup = (curl_strdup_callback)system_strdup; 242 Curl_ccalloc = (curl_calloc_callback)calloc; 243 244 if(flags & CURL_GLOBAL_SSL) 245 if(!Curl_ssl_init()) { 246 DEBUGF(fprintf(stderr, "Error: Curl_ssl_init failed\n")); 247 return CURLE_FAILED_INIT; 248 } 249 250 if(flags & CURL_GLOBAL_WIN32) 251 if(win32_init() != CURLE_OK) { 252 DEBUGF(fprintf(stderr, "Error: win32_init failed\n")); 253 return CURLE_FAILED_INIT; 254 } 255 256#ifdef __AMIGA__ 257 if(!amiga_init()) { 258 DEBUGF(fprintf(stderr, "Error: amiga_init failed\n")); 259 return CURLE_FAILED_INIT; 260 } 261#endif 262 263#ifdef NETWARE 264 if(netware_init()) { 265 DEBUGF(fprintf(stderr, "Warning: LONG namespace not available\n")); 266 } 267#endif 268 269#ifdef USE_LIBIDN 270 idna_init(); 271#endif 272 273 if(Curl_resolver_global_init() != CURLE_OK) { 274 DEBUGF(fprintf(stderr, "Error: resolver_global_init failed\n")); 275 return CURLE_FAILED_INIT; 276 } 277 278#if defined(USE_LIBSSH2) && defined(HAVE_LIBSSH2_INIT) 279 if(libssh2_init(0)) { 280 DEBUGF(fprintf(stderr, "Error: libssh2_init failed\n")); 281 return CURLE_FAILED_INIT; 282 } 283#endif 284 285 init_flags = flags; 286 287 /* Preset pseudo-random number sequence. */ 288 289 Curl_srand(); 290 291 return CURLE_OK; 292} 293 294/* 295 * curl_global_init_mem() globally initializes cURL and also registers the 296 * user provided callback routines. 297 */ 298CURLcode curl_global_init_mem(long flags, curl_malloc_callback m, 299 curl_free_callback f, curl_realloc_callback r, 300 curl_strdup_callback s, curl_calloc_callback c) 301{ 302 CURLcode code = CURLE_OK; 303 304 /* Invalid input, return immediately */ 305 if(!m || !f || !r || !s || !c) 306 return CURLE_FAILED_INIT; 307 308 /* Already initialized, don't do it again */ 309 if(initialized) 310 return CURLE_OK; 311 312 /* Call the actual init function first */ 313 code = curl_global_init(flags); 314 if(code == CURLE_OK) { 315 Curl_cmalloc = m; 316 Curl_cfree = f; 317 Curl_cstrdup = s; 318 Curl_crealloc = r; 319 Curl_ccalloc = c; 320 } 321 322 return code; 323} 324 325/** 326 * curl_global_cleanup() globally cleanups cURL, uses the value of 327 * "init_flags" to determine what needs to be cleaned up and what doesn't. 328 */ 329void curl_global_cleanup(void) 330{ 331 if(!initialized) 332 return; 333 334 if(--initialized) 335 return; 336 337 Curl_global_host_cache_dtor(); 338 339 if(init_flags & CURL_GLOBAL_SSL) 340 Curl_ssl_cleanup(); 341 342 Curl_resolver_global_cleanup(); 343 344 if(init_flags & CURL_GLOBAL_WIN32) 345 win32_cleanup(); 346 347#ifdef __AMIGA__ 348 amiga_cleanup(); 349#endif 350 351#if defined(USE_LIBSSH2) && defined(HAVE_LIBSSH2_EXIT) 352 (void)libssh2_exit(); 353#endif 354 355 init_flags = 0; 356} 357 358/* 359 * curl_easy_init() is the external interface to alloc, setup and init an 360 * easy handle that is returned. If anything goes wrong, NULL is returned. 361 */ 362CURL *curl_easy_init(void) 363{ 364 CURLcode res; 365 struct SessionHandle *data; 366 367 /* Make sure we inited the global SSL stuff */ 368 if(!initialized) { 369 res = curl_global_init(CURL_GLOBAL_DEFAULT); 370 if(res) { 371 /* something in the global init failed, return nothing */ 372 DEBUGF(fprintf(stderr, "Error: curl_global_init failed\n")); 373 return NULL; 374 } 375 } 376 377 /* We use curl_open() with undefined URL so far */ 378 res = Curl_open(&data); 379 if(res != CURLE_OK) { 380 DEBUGF(fprintf(stderr, "Error: Curl_open failed\n")); 381 return NULL; 382 } 383 384 return data; 385} 386 387/* 388 * curl_easy_setopt() is the external interface for setting options on an 389 * easy handle. 390 */ 391 392#undef curl_easy_setopt 393CURLcode curl_easy_setopt(CURL *curl, CURLoption tag, ...) 394{ 395 va_list arg; 396 struct SessionHandle *data = curl; 397 CURLcode ret; 398 399 if(!curl) 400 return CURLE_BAD_FUNCTION_ARGUMENT; 401 402 va_start(arg, tag); 403 404 ret = Curl_setopt(data, tag, arg); 405 406 va_end(arg); 407 return ret; 408} 409 410#ifdef CURL_MULTIEASY 411/*************************************************************************** 412 * This function is still only for testing purposes. It makes a great way 413 * to run the full test suite on the multi interface instead of the easy one. 414 *************************************************************************** 415 * 416 * The *new* curl_easy_perform() is the external interface that performs a 417 * transfer previously setup. 418 * 419 * Wrapper-function that: creates a multi handle, adds the easy handle to it, 420 * runs curl_multi_perform() until the transfer is done, then detaches the 421 * easy handle, destroys the multi handle and returns the easy handle's return 422 * code. This will make everything internally use and assume multi interface. 423 */ 424CURLcode curl_easy_perform(CURL *easy) 425{ 426 CURLM *multi; 427 CURLMcode mcode; 428 CURLcode code = CURLE_OK; 429 int still_running; 430 struct timeval timeout; 431 int rc; 432 CURLMsg *msg; 433 fd_set fdread; 434 fd_set fdwrite; 435 fd_set fdexcep; 436 int maxfd; 437 438 if(!easy) 439 return CURLE_BAD_FUNCTION_ARGUMENT; 440 441 multi = curl_multi_init(); 442 if(!multi) 443 return CURLE_OUT_OF_MEMORY; 444 445 mcode = curl_multi_add_handle(multi, easy); 446 if(mcode) { 447 curl_multi_cleanup(multi); 448 if(mcode == CURLM_OUT_OF_MEMORY) 449 return CURLE_OUT_OF_MEMORY; 450 else 451 return CURLE_FAILED_INIT; 452 } 453 454 /* we start some action by calling perform right away */ 455 456 do { 457 while(CURLM_CALL_MULTI_PERFORM == 458 curl_multi_perform(multi, &still_running)); 459 460 if(!still_running) 461 break; 462 463 FD_ZERO(&fdread); 464 FD_ZERO(&fdwrite); 465 FD_ZERO(&fdexcep); 466 467 /* timeout once per second */ 468 timeout.tv_sec = 1; 469 timeout.tv_usec = 0; 470 471 /* Old deprecated style: get file descriptors from the transfers */ 472 curl_multi_fdset(multi, &fdread, &fdwrite, &fdexcep, &maxfd); 473 rc = Curl_select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout); 474 475 /* The way is to extract the sockets and wait for them without using 476 select. This whole alternative version should probably rather use the 477 curl_multi_socket() approach. */ 478 479 if(rc == -1) 480 /* select error */ 481 break; 482 483 /* timeout or data to send/receive => loop! */ 484 } while(still_running); 485 486 msg = curl_multi_info_read(multi, &rc); 487 if(msg) 488 code = msg->data.result; 489 490 mcode = curl_multi_remove_handle(multi, easy); 491 /* what to do if it fails? */ 492 493 mcode = curl_multi_cleanup(multi); 494 /* what to do if it fails? */ 495 496 return code; 497} 498#else 499/* 500 * curl_easy_perform() is the external interface that performs a transfer 501 * previously setup. 502 */ 503CURLcode curl_easy_perform(CURL *curl) 504{ 505 struct SessionHandle *data = (struct SessionHandle *)curl; 506 507 if(!data) 508 return CURLE_BAD_FUNCTION_ARGUMENT; 509 510 if(! (data->share && data->share->hostcache)) { 511 /* this handle is not using a shared dns cache */ 512 513 if(data->set.global_dns_cache && 514 (data->dns.hostcachetype != HCACHE_GLOBAL)) { 515 /* global dns cache was requested but still isn't */ 516 struct curl_hash *ptr; 517 518 if(data->dns.hostcachetype == HCACHE_PRIVATE) { 519 /* if the current cache is private, kill it first */ 520 Curl_hash_destroy(data->dns.hostcache); 521 data->dns.hostcachetype = HCACHE_NONE; 522 data->dns.hostcache = NULL; 523 } 524 525 ptr = Curl_global_host_cache_init(); 526 if(ptr) { 527 /* only do this if the global cache init works */ 528 data->dns.hostcache = ptr; 529 data->dns.hostcachetype = HCACHE_GLOBAL; 530 } 531 } 532 533 if(!data->dns.hostcache) { 534 data->dns.hostcachetype = HCACHE_PRIVATE; 535 data->dns.hostcache = Curl_mk_dnscache(); 536 537 if(!data->dns.hostcache) 538 /* While we possibly could survive and do good without a host cache, 539 the fact that creating it failed indicates that things are truly 540 screwed up and we should bail out! */ 541 return CURLE_OUT_OF_MEMORY; 542 } 543 544 } 545 546 if(!data->state.connc) { 547 /* oops, no connection cache, make one up */ 548 data->state.connc = Curl_mk_connc(CONNCACHE_PRIVATE, -1L); 549 if(!data->state.connc) 550 return CURLE_OUT_OF_MEMORY; 551 } 552 553 return Curl_perform(data); 554} 555#endif 556 557/* 558 * curl_easy_cleanup() is the external interface to cleaning/freeing the given 559 * easy handle. 560 */ 561void curl_easy_cleanup(CURL *curl) 562{ 563 struct SessionHandle *data = (struct SessionHandle *)curl; 564 565 if(!data) 566 return; 567 568 Curl_close(data); 569} 570 571/* 572 * Store a pointed to the multi handle within the easy handle's data struct. 573 */ 574void Curl_easy_addmulti(struct SessionHandle *data, 575 void *multi) 576{ 577 data->multi = multi; 578 if(multi == NULL) 579 /* the association is cleared, mark the easy handle as not used by an 580 interface */ 581 data->state.used_interface = Curl_if_none; 582} 583 584void Curl_easy_initHandleData(struct SessionHandle *data) 585{ 586 memset(&data->req, 0, sizeof(struct SingleRequest)); 587 588 data->req.maxdownload = -1; 589} 590 591/* 592 * curl_easy_getinfo() is an external interface that allows an app to retrieve 593 * information from a performed transfer and similar. 594 */ 595#undef curl_easy_getinfo 596CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ...) 597{ 598 va_list arg; 599 void *paramp; 600 struct SessionHandle *data = (struct SessionHandle *)curl; 601 602 va_start(arg, info); 603 paramp = va_arg(arg, void *); 604 605 return Curl_getinfo(data, info, paramp); 606} 607 608/* 609 * curl_easy_duphandle() is an external interface to allow duplication of a 610 * given input easy handle. The returned handle will be a new working handle 611 * with all options set exactly as the input source handle. 612 */ 613CURL *curl_easy_duphandle(CURL *incurl) 614{ 615 struct SessionHandle *data=(struct SessionHandle *)incurl; 616 617 struct SessionHandle *outcurl = calloc(1, sizeof(struct SessionHandle)); 618 if(NULL == outcurl) 619 goto fail; 620 621 /* 622 * We setup a few buffers we need. We should probably make them 623 * get setup on-demand in the code, as that would probably decrease 624 * the likeliness of us forgetting to init a buffer here in the future. 625 */ 626 outcurl->state.headerbuff = malloc(HEADERSIZE); 627 if(!outcurl->state.headerbuff) 628 goto fail; 629 outcurl->state.headersize = HEADERSIZE; 630 631 /* copy all userdefined values */ 632 if(Curl_dupset(outcurl, data) != CURLE_OK) 633 goto fail; 634 635 /* the connection cache is setup on demand */ 636 outcurl->state.connc = NULL; 637 638 outcurl->state.lastconnect = -1; 639 640 outcurl->progress.flags = data->progress.flags; 641 outcurl->progress.callback = data->progress.callback; 642 643 if(data->cookies) { 644 /* If cookies are enabled in the parent handle, we enable them 645 in the clone as well! */ 646 outcurl->cookies = Curl_cookie_init(data, 647 data->cookies->filename, 648 outcurl->cookies, 649 data->set.cookiesession); 650 if(!outcurl->cookies) 651 goto fail; 652 } 653 654 /* duplicate all values in 'change' */ 655 if(data->change.cookielist) { 656 outcurl->change.cookielist = 657 Curl_slist_duplicate(data->change.cookielist); 658 if(!outcurl->change.cookielist) 659 goto fail; 660 } 661 662 if(data->change.url) { 663 outcurl->change.url = strdup(data->change.url); 664 if(!outcurl->change.url) 665 goto fail; 666 outcurl->change.url_alloc = TRUE; 667 } 668 669 if(data->change.referer) { 670 outcurl->change.referer = strdup(data->change.referer); 671 if(!outcurl->change.referer) 672 goto fail; 673 outcurl->change.referer_alloc = TRUE; 674 } 675 676 /* Clone the resolver handle, if present, for the new handle */ 677 if(Curl_resolver_duphandle(&outcurl->state.resolver, 678 data->state.resolver) != CURLE_OK) 679 goto fail; 680 681 Curl_convert_setup(outcurl); 682 683 Curl_easy_initHandleData(outcurl); 684 685 outcurl->magic = CURLEASY_MAGIC_NUMBER; 686 687 /* we reach this point and thus we are OK */ 688 689 return outcurl; 690 691 fail: 692 693 if(outcurl) { 694 if(outcurl->state.connc && 695 (outcurl->state.connc->type == CONNCACHE_PRIVATE)) 696 Curl_rm_connc(outcurl->state.connc); 697 if(outcurl->state.headerbuff) 698 free(outcurl->state.headerbuff); 699 if(outcurl->change.cookielist) 700 curl_slist_free_all(outcurl->change.cookielist); 701 if(outcurl->change.url) 702 free(outcurl->change.url); 703 if(outcurl->change.referer) 704 free(outcurl->change.referer); 705 Curl_freeset(outcurl); 706 free(outcurl); 707 } 708 709 return NULL; 710} 711 712/* 713 * curl_easy_reset() is an external interface that allows an app to re- 714 * initialize a session handle to the default values. 715 */ 716void curl_easy_reset(CURL *curl) 717{ 718 struct SessionHandle *data = (struct SessionHandle *)curl; 719 720 Curl_safefree(data->state.pathbuffer); 721 data->state.pathbuffer=NULL; 722 723 Curl_safefree(data->state.proto.generic); 724 data->state.proto.generic=NULL; 725 726 /* zero out UserDefined data: */ 727 Curl_freeset(data); 728 memset(&data->set, 0, sizeof(struct UserDefined)); 729 (void)Curl_init_userdefined(&data->set); 730 731 /* zero out Progress data: */ 732 memset(&data->progress, 0, sizeof(struct Progress)); 733 734 /* init Handle data */ 735 Curl_easy_initHandleData(data); 736 737 data->progress.flags |= PGRS_HIDE; 738 data->state.current_speed = -1; /* init to negative == impossible */ 739} 740 741/* 742 * curl_easy_pause() allows an application to pause or unpause a specific 743 * transfer and direction. This function sets the full new state for the 744 * current connection this easy handle operates on. 745 * 746 * NOTE: if you have the receiving paused and you call this function to remove 747 * the pausing, you may get your write callback called at this point. 748 * 749 * Action is a bitmask consisting of CURLPAUSE_* bits in curl/curl.h 750 */ 751CURLcode curl_easy_pause(CURL *curl, int action) 752{ 753 struct SessionHandle *data = (struct SessionHandle *)curl; 754 struct SingleRequest *k = &data->req; 755 CURLcode result = CURLE_OK; 756 757 /* first switch off both pause bits */ 758 int newstate = k->keepon &~ (KEEP_RECV_PAUSE| KEEP_SEND_PAUSE); 759 760 /* set the new desired pause bits */ 761 newstate |= ((action & CURLPAUSE_RECV)?KEEP_RECV_PAUSE:0) | 762 ((action & CURLPAUSE_SEND)?KEEP_SEND_PAUSE:0); 763 764 /* put it back in the keepon */ 765 k->keepon = newstate; 766 767 if(!(newstate & KEEP_RECV_PAUSE) && data->state.tempwrite) { 768 /* we have a buffer for sending that we now seem to be able to deliver 769 since the receive pausing is lifted! */ 770 771 /* get the pointer, type and length in local copies since the function may 772 return PAUSE again and then we'll get a new copy allocted and stored in 773 the tempwrite variables */ 774 char *tempwrite = data->state.tempwrite; 775 char *freewrite = tempwrite; /* store this pointer to free it later */ 776 size_t tempsize = data->state.tempwritesize; 777 int temptype = data->state.tempwritetype; 778 size_t chunklen; 779 780 /* clear tempwrite here just to make sure it gets cleared if there's no 781 further use of it, and make sure we don't clear it after the function 782 invoke as it may have been set to a new value by then */ 783 data->state.tempwrite = NULL; 784 785 /* since the write callback API is define to never exceed 786 CURL_MAX_WRITE_SIZE bytes in a single call, and since we may in fact 787 have more data than that in our buffer here, we must loop sending the 788 data in multiple calls until there's no data left or we get another 789 pause returned. 790 791 A tricky part is that the function we call will "buffer" the data 792 itself when it pauses on a particular buffer, so we may need to do some 793 extra trickery if we get a pause return here. 794 */ 795 do { 796 chunklen = (tempsize > CURL_MAX_WRITE_SIZE)?CURL_MAX_WRITE_SIZE:tempsize; 797 798 result = Curl_client_write(data->state.current_conn, 799 temptype, tempwrite, chunklen); 800 if(result) 801 /* failures abort the loop at once */ 802 break; 803 804 if(data->state.tempwrite && (tempsize - chunklen)) { 805 /* Ouch, the reading is again paused and the block we send is now 806 "cached". If this is the final chunk we can leave it like this, but 807 if we have more chunks that are cached after this, we need to free 808 the newly cached one and put back a version that is truly the entire 809 contents that is saved for later 810 */ 811 char *newptr; 812 813 /* note that tempsize is still the size as before the callback was 814 used, and thus the whole piece of data to keep */ 815 newptr = realloc(data->state.tempwrite, tempsize); 816 817 if(!newptr) { 818 free(data->state.tempwrite); /* free old area */ 819 data->state.tempwrite = NULL; 820 result = CURLE_OUT_OF_MEMORY; 821 /* tempwrite will be freed further down */ 822 break; 823 } 824 data->state.tempwrite = newptr; /* store new pointer */ 825 memcpy(newptr, tempwrite, tempsize); 826 data->state.tempwritesize = tempsize; /* store new size */ 827 /* tempwrite will be freed further down */ 828 break; /* go back to pausing until further notice */ 829 } 830 else { 831 tempsize -= chunklen; /* left after the call above */ 832 tempwrite += chunklen; /* advance the pointer */ 833 } 834 835 } while((result == CURLE_OK) && tempsize); 836 837 free(freewrite); /* this is unconditionally no longer used */ 838 } 839 840 return result; 841} 842 843 844static CURLcode easy_connection(struct SessionHandle *data, 845 curl_socket_t *sfd, 846 struct connectdata **connp) 847{ 848 if(data == NULL) 849 return CURLE_BAD_FUNCTION_ARGUMENT; 850 851 /* only allow these to be called on handles with CURLOPT_CONNECT_ONLY */ 852 if(!data->set.connect_only) { 853 failf(data, "CONNECT_ONLY is required!"); 854 return CURLE_UNSUPPORTED_PROTOCOL; 855 } 856 857 *sfd = Curl_getconnectinfo(data, connp); 858 859 if(*sfd == CURL_SOCKET_BAD) { 860 failf(data, "Failed to get recent socket"); 861 return CURLE_UNSUPPORTED_PROTOCOL; 862 } 863 864 return CURLE_OK; 865} 866 867/* 868 * Receives data from the connected socket. Use after successful 869 * curl_easy_perform() with CURLOPT_CONNECT_ONLY option. 870 * Returns CURLE_OK on success, error code on error. 871 */ 872CURLcode curl_easy_recv(CURL *curl, void *buffer, size_t buflen, size_t *n) 873{ 874 curl_socket_t sfd; 875 CURLcode ret; 876 ssize_t n1; 877 struct connectdata *c; 878 struct SessionHandle *data = (struct SessionHandle *)curl; 879 880 ret = easy_connection(data, &sfd, &c); 881 if(ret) 882 return ret; 883 884 *n = 0; 885 ret = Curl_read(c, sfd, buffer, buflen, &n1); 886 887 if(ret != CURLE_OK) 888 return ret; 889 890 *n = (size_t)n1; 891 892 return CURLE_OK; 893} 894 895/* 896 * Sends data over the connected socket. Use after successful 897 * curl_easy_perform() with CURLOPT_CONNECT_ONLY option. 898 */ 899CURLcode curl_easy_send(CURL *curl, const void *buffer, size_t buflen, 900 size_t *n) 901{ 902 curl_socket_t sfd; 903 CURLcode ret; 904 ssize_t n1; 905 struct connectdata *c = NULL; 906 struct SessionHandle *data = (struct SessionHandle *)curl; 907 908 ret = easy_connection(data, &sfd, &c); 909 if(ret) 910 return ret; 911 912 *n = 0; 913 ret = Curl_write(c, sfd, buffer, buflen, &n1); 914 915 if(n1 == -1) 916 return CURLE_SEND_ERROR; 917 918 /* detect EAGAIN */ 919 if((CURLE_OK == ret) && (0 == n1)) 920 return CURLE_AGAIN; 921 922 *n = (size_t)n1; 923 924 return ret; 925} 926