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