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