- Introducing curl_easy_send() and curl_easy_recv(). They can be used to send
and receive data over a connection previously setup with curl_easy_perform() and its CURLOPT_CONNECT_ONLY option. The sendrecv.c example was added to show how they can be used.
This commit is contained in:
@@ -92,6 +92,7 @@
|
||||
#include "sockaddr.h" /* required for Curl_sockaddr_storage */
|
||||
#include "inet_ntop.h"
|
||||
#include "inet_pton.h"
|
||||
#include "sslgen.h" /* for Curl_ssl_check_cxn() */
|
||||
|
||||
/* The last #include file should be: */
|
||||
#include "memdebug.h"
|
||||
@@ -977,3 +978,46 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Used to extract socket and connectdata struct for the most recent
|
||||
* transfer on the given SessionHandle.
|
||||
*
|
||||
* The socket 'long' will be -1 in case of failure!
|
||||
*/
|
||||
CURLcode Curl_getconnectinfo(struct SessionHandle *data,
|
||||
long *param_longp,
|
||||
struct connectdata **connp)
|
||||
{
|
||||
if((data->state.lastconnect != -1) &&
|
||||
(data->state.connc->connects[data->state.lastconnect] != NULL)) {
|
||||
struct connectdata *c =
|
||||
data->state.connc->connects[data->state.lastconnect];
|
||||
if(connp)
|
||||
/* only store this if the caller cares for it */
|
||||
*connp = c;
|
||||
*param_longp = c->sock[FIRSTSOCKET];
|
||||
/* we have a socket connected, let's determine if the server shut down */
|
||||
/* determine if ssl */
|
||||
if(c->ssl[FIRSTSOCKET].use) {
|
||||
/* use the SSL context */
|
||||
if(!Curl_ssl_check_cxn(c))
|
||||
*param_longp = -1; /* FIN received */
|
||||
}
|
||||
/* Minix 3.1 doesn't support any flags on recv; just assume socket is OK */
|
||||
#ifdef MSG_PEEK
|
||||
else {
|
||||
/* use the socket */
|
||||
char buf;
|
||||
if(recv((RECV_TYPE_ARG1)c->sock[FIRSTSOCKET], (RECV_TYPE_ARG2)&buf,
|
||||
(RECV_TYPE_ARG3)1, (RECV_TYPE_ARG4)MSG_PEEK) == 0) {
|
||||
*param_longp = -1; /* FIN received */
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
*param_longp = -1;
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
@@ -47,4 +47,13 @@ long Curl_timeleft(struct connectdata *conn,
|
||||
|
||||
#define DEFAULT_CONNECT_TIMEOUT 300000 /* milliseconds == five minutes */
|
||||
|
||||
/*
|
||||
* Used to extract socket and connectdata struct for the most recent
|
||||
* transfer on the given SessionHandle.
|
||||
*
|
||||
* The socket 'long' will be -1 in case of failure!
|
||||
*/
|
||||
CURLcode Curl_getconnectinfo(struct SessionHandle *data,
|
||||
long *param_longp,
|
||||
struct connectdata **connp);
|
||||
#endif
|
||||
|
||||
96
lib/easy.c
96
lib/easy.c
@@ -83,6 +83,7 @@
|
||||
#include "easyif.h"
|
||||
#include "select.h"
|
||||
#include "sendf.h" /* for failf function prototype */
|
||||
#include "connect.h" /* for Curl_getconnectinfo */
|
||||
|
||||
#define _MPRINTF_REPLACE /* use our functions only */
|
||||
#include <curl/mprintf.h>
|
||||
@@ -1056,3 +1057,98 @@ CURLcode Curl_convert_from_utf8(struct SessionHandle *data,
|
||||
}
|
||||
|
||||
#endif /* CURL_DOES_CONVERSIONS */
|
||||
|
||||
static CURLcode easy_connection(struct SessionHandle *data,
|
||||
curl_socket_t *sfd,
|
||||
struct connectdata **connp)
|
||||
{
|
||||
CURLcode ret;
|
||||
long sockfd;
|
||||
|
||||
if(data == NULL)
|
||||
return CURLE_BAD_FUNCTION_ARGUMENT;
|
||||
|
||||
/* only allow these to be called on handles with CURLOPT_CONNECT_ONLY */
|
||||
if(!data->set.connect_only) {
|
||||
failf(data, "CONNECT_ONLY is required!");
|
||||
return CURLE_UNSUPPORTED_PROTOCOL;
|
||||
}
|
||||
|
||||
ret = Curl_getconnectinfo(data, &sockfd, connp);
|
||||
if(ret != CURLE_OK)
|
||||
return ret;
|
||||
|
||||
if(sockfd == -1) {
|
||||
failf(data, "Failed to get recent socket");
|
||||
return CURLE_UNSUPPORTED_PROTOCOL;
|
||||
}
|
||||
|
||||
*sfd = (curl_socket_t)sockfd; /* we know that this is actually a socket
|
||||
descriptor so the typecast is fine here */
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Receives data from the connected socket. Use after successful
|
||||
* curl_easy_perform() with CURLOPT_CONNECT_ONLY option.
|
||||
* Returns CURLE_OK on success, error code on error.
|
||||
*/
|
||||
CURLcode curl_easy_recv(CURL *curl, void *buffer, size_t buflen, size_t *n)
|
||||
{
|
||||
curl_socket_t sfd;
|
||||
CURLcode ret;
|
||||
int ret1;
|
||||
ssize_t n1;
|
||||
struct connectdata *c;
|
||||
struct SessionHandle *data = (struct SessionHandle *)curl;
|
||||
|
||||
ret = easy_connection(data, &sfd, &c);
|
||||
if(ret)
|
||||
return ret;
|
||||
|
||||
*n = 0;
|
||||
ret1 = Curl_read(c, sfd, buffer, buflen, &n1);
|
||||
|
||||
if(ret1 == -1)
|
||||
return CURLE_AGAIN;
|
||||
|
||||
if(n1 == -1)
|
||||
return CURLE_RECV_ERROR;
|
||||
|
||||
*n = (size_t)n1;
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sends data over the connected socket. Use after successful
|
||||
* curl_easy_perform() with CURLOPT_CONNECT_ONLY option.
|
||||
*/
|
||||
CURLcode curl_easy_send(CURL *curl, const void *buffer, size_t buflen,
|
||||
size_t *n)
|
||||
{
|
||||
curl_socket_t sfd;
|
||||
CURLcode ret;
|
||||
ssize_t n1;
|
||||
struct connectdata *c = NULL;
|
||||
struct SessionHandle *data = (struct SessionHandle *)curl;
|
||||
|
||||
ret = easy_connection(data, &sfd, &c);
|
||||
if(ret)
|
||||
return ret;
|
||||
|
||||
*n = 0;
|
||||
ret = Curl_write(c, sfd, buffer, buflen, &n1);
|
||||
|
||||
if(n1 == -1)
|
||||
return CURLE_SEND_ERROR;
|
||||
|
||||
/* detect EAGAIN */
|
||||
if((CURLE_OK == ret) && (0 == n1))
|
||||
return CURLE_AGAIN;
|
||||
|
||||
*n = (size_t)n1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#include <stdlib.h>
|
||||
#include "memory.h"
|
||||
#include "sslgen.h"
|
||||
#include "connect.h" /* Curl_getconnectinfo() */
|
||||
|
||||
/* Make this the last #include */
|
||||
#include "memdebug.h"
|
||||
@@ -75,9 +76,6 @@ CURLcode Curl_getinfo(struct SessionHandle *data, CURLINFO info, ...)
|
||||
double *param_doublep=NULL;
|
||||
char **param_charp=NULL;
|
||||
struct curl_slist **param_slistp=NULL;
|
||||
#ifdef MSG_PEEK
|
||||
char buf;
|
||||
#endif
|
||||
int type;
|
||||
|
||||
if(!data)
|
||||
@@ -205,31 +203,7 @@ CURLcode Curl_getinfo(struct SessionHandle *data, CURLINFO info, ...)
|
||||
*param_charp = data->state.most_recent_ftp_entrypath;
|
||||
break;
|
||||
case CURLINFO_LASTSOCKET:
|
||||
if((data->state.lastconnect != -1) &&
|
||||
(data->state.connc->connects[data->state.lastconnect] != NULL)) {
|
||||
struct connectdata *c = data->state.connc->connects
|
||||
[data->state.lastconnect];
|
||||
*param_longp = c->sock[FIRSTSOCKET];
|
||||
/* we have a socket connected, let's determine if the server shut down */
|
||||
/* determine if ssl */
|
||||
if(c->ssl[FIRSTSOCKET].use) {
|
||||
/* use the SSL context */
|
||||
if(!Curl_ssl_check_cxn(c))
|
||||
*param_longp = -1; /* FIN received */
|
||||
}
|
||||
/* Minix 3.1 doesn't support any flags on recv; just assume socket is OK */
|
||||
#ifdef MSG_PEEK
|
||||
else {
|
||||
/* use the socket */
|
||||
if(recv((RECV_TYPE_ARG1)c->sock[FIRSTSOCKET], (RECV_TYPE_ARG2)&buf,
|
||||
(RECV_TYPE_ARG3)1, (RECV_TYPE_ARG4)MSG_PEEK) == 0) {
|
||||
*param_longp = -1; /* FIN received */
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
*param_longp = -1;
|
||||
(void)Curl_getconnectinfo(data, param_longp, NULL);
|
||||
break;
|
||||
case CURLINFO_REDIRECT_URL:
|
||||
/* Return the URL this request would have been redirected to if that
|
||||
|
||||
@@ -261,6 +261,9 @@ curl_easy_strerror(CURLcode error)
|
||||
case CURLE_SSH:
|
||||
return "Error in the SSH layer";
|
||||
|
||||
case CURLE_AGAIN:
|
||||
return "Socket not ready for send/recv";
|
||||
|
||||
/* error codes not used by current libcurl */
|
||||
case CURLE_OBSOLETE4:
|
||||
case CURLE_OBSOLETE10:
|
||||
|
||||
Reference in New Issue
Block a user