From 514592b89207e83d13b5a4e79bc247aa6f74c4b7 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 12 May 2008 21:43:24 +0000 Subject: - 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. --- lib/connect.c | 44 +++++++++++++++++++++++++++ lib/connect.h | 9 ++++++ lib/easy.c | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/getinfo.c | 30 ++---------------- lib/strerror.c | 3 ++ 5 files changed, 154 insertions(+), 28 deletions(-) (limited to 'lib') diff --git a/lib/connect.c b/lib/connect.c index 33e4e0777..74380da1e 100644 --- a/lib/connect.c +++ b/lib/connect.c @@ -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; +} diff --git a/lib/connect.h b/lib/connect.h index 78c0191ba..8e55cc941 100644 --- a/lib/connect.h +++ b/lib/connect.h @@ -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 diff --git a/lib/easy.c b/lib/easy.c index 1af575416..216dfe7bf 100644 --- a/lib/easy.c +++ b/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 @@ -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; +} diff --git a/lib/getinfo.c b/lib/getinfo.c index 145a71b22..078154246 100644 --- a/lib/getinfo.c +++ b/lib/getinfo.c @@ -34,6 +34,7 @@ #include #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 diff --git a/lib/strerror.c b/lib/strerror.c index d2d46a308..fe5a76df5 100644 --- a/lib/strerror.c +++ b/lib/strerror.c @@ -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: -- cgit v1.2.3