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