On 04/04/2010 02:14 PM, Daniel Stenberg wrote:
As long as when _not_ using any set callbacks it would behave closely to
how it worked before I'm fine with it.
Turns out, telnet on original curl didn't always flush stdout, so there
were still issues when using it interactively. Here's a patch that flushes
stdout when needed, and uses flags based on users setting read or write
callback instead of comparing function pointers or requiring a new
setopt.
Seems to pass make-test as well as handle custom read/write callbacks
set by my program.
Let me know what you think...I'll send an official git patch
if you concur with these changes.
Thanks,
Ben
--
Ben Greear <[email protected]>
Candela Technologies Inc http://www.candelatech.com
diff --git a/lib/telnet.c b/lib/telnet.c
index 9409f49..f599472 100644
--- a/lib/telnet.c
+++ b/lib/telnet.c
@@ -67,6 +67,7 @@
#include "sendf.h"
#include "telnet.h"
#include "connect.h"
+#include "progress.h"
#define _MPRINTF_REPLACE /* use our functions only */
#include <curl/mprintf.h>
@@ -962,16 +963,19 @@ CURLcode telrcv(struct connectdata *conn,
struct SessionHandle *data = conn->data;
struct TELNET *tn = (struct TELNET *)data->state.proto.telnet;
-#define startskipping() \
- if(startwrite >= 0) { \
- result = Curl_client_write(conn, \
- CLIENTWRITE_BODY, \
- (char *)&inbuf[startwrite], \
- in-startwrite); \
- if(result != CURLE_OK) \
- return result; \
- } \
- startwrite = -1
+#define startskipping() \
+ if(startwrite >= 0) { \
+ result = Curl_client_write(conn, \
+ CLIENTWRITE_BODY, \
+ (char *)&inbuf[startwrite], \
+ in-startwrite); \
+ if(result != CURLE_OK) \
+ return result; \
+ /* We may be writing to stdout..flush if so. */ \
+ if (!data->set.is_fwrite_set) \
+ fflush(stdout); \
+ } \
+ startwrite = -1
#define writebyte() \
if(startwrite < 0) \
@@ -1206,6 +1210,7 @@ static CURLcode telnet_do(struct connectdata *conn, bool
*done)
#else
int interval_ms;
struct pollfd pfd[2];
+ int poll_cnt;
#endif
int ret;
ssize_t nread;
@@ -1213,6 +1218,8 @@ static CURLcode telnet_do(struct connectdata *conn, bool
*done)
bool keepon = TRUE;
char *buf = data->state.buffer;
struct TELNET *tn;
+ unsigned long total_dl = 0;
+ unsigned long total_ul = 0;
*done = TRUE; /* unconditionally */
@@ -1402,7 +1409,8 @@ static CURLcode telnet_do(struct connectdata *conn, bool
*done)
break;
}
- fflush(stdout);
+ if (!data->set.is_fwrite_set)
+ fflush(stdout);
/* Negotiate if the peer has started negotiating,
otherwise don't. We don't want to speak telnet with
@@ -1446,27 +1454,28 @@ static CURLcode telnet_do(struct connectdata *conn,
bool *done)
#else
pfd[0].fd = sockfd;
pfd[0].events = POLLIN;
- pfd[1].fd = 0;
- pfd[1].events = POLLIN;
- interval_ms = 1 * 1000;
+
+ if (data->set.is_fread_set) {
+ poll_cnt = 1;
+ interval_ms = 100; /* poll user-supplied read function */
+ }
+ else {
+ pfd[1].fd = 0;
+ pfd[1].events = POLLIN;
+ poll_cnt = 2;
+ interval_ms = 1 * 1000;
+ }
while(keepon) {
- switch (Curl_poll(pfd, 2, interval_ms)) {
+ switch (Curl_poll(pfd, poll_cnt, interval_ms)) {
case -1: /* error, stop reading */
keepon = FALSE;
continue;
case 0: /* timeout */
- break;
+ pfd[0].revents = 0;
+ pfd[1].revents = 0;
+ /* fall through */
default: /* read! */
- if(pfd[1].revents & POLLIN) { /* read from stdin */
- nread = read(0, buf, 255);
- code = send_telnet_data(conn, buf, nread);
- if(code) {
- keepon = FALSE;
- break;
- }
- }
-
if(pfd[0].revents & POLLIN) {
/* read data from network */
ret = Curl_read(conn, sockfd, buf, BUFSIZE - 1, &nread);
@@ -1486,6 +1495,8 @@ static CURLcode telnet_do(struct connectdata *conn, bool
*done)
break;
}
+ total_dl += nread;
+ Curl_pgrsSetDownloadCounter(data, total_dl);
code = telrcv(conn, (unsigned char *)buf, nread);
if(code) {
keepon = FALSE;
@@ -1500,7 +1511,39 @@ static CURLcode telnet_do(struct connectdata *conn, bool
*done)
tn->already_negotiated = 1;
}
}
- }
+
+ nread = 0;
+ if (poll_cnt == 2) {
+ if(pfd[1].revents & POLLIN) { /* read from stdin */
+ nread = read(0, buf, BUFSIZE - 1);
+ }
+ }
+ else {
+ /* read from user-supplied method */
+ nread = (int)conn->fread_func(buf, 1, BUFSIZE - 1, conn->fread_in);
+ if (nread == CURL_READFUNC_ABORT) {
+ keepon = FALSE;
+ break;
+ }
+ if (nread == CURL_READFUNC_PAUSE)
+ break;
+ }
+
+ if (nread > 0) {
+ code = send_telnet_data(conn, buf, nread);
+ if(code) {
+ keepon = FALSE;
+ break;
+ }
+ total_ul += nread;
+ Curl_pgrsSetUploadCounter(data, total_ul);
+ }
+ else if (nread < 0) {
+ keepon = FALSE;
+ }
+ break;
+ }/* poll switch statement */
+
if(data->set.timeout) {
now = Curl_tvnow();
if(Curl_tvdiff(now, conn->created) >= data->set.timeout) {
@@ -1509,6 +1552,11 @@ static CURLcode telnet_do(struct connectdata *conn, bool
*done)
keepon = FALSE;
}
}
+
+ if(Curl_pgrsUpdate(conn)) {
+ code = CURLE_ABORTED_BY_CALLBACK;
+ break;
+ }
}
#endif
/* mark this as "no further transfer wanted" */
diff --git a/lib/url.c b/lib/url.c
index 357f213..e3d4747 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -690,6 +690,8 @@ CURLcode Curl_init_userdefined(struct UserDefined *set)
/* use fread as default function to read input */
set->fread_func = (curl_read_callback)fread;
+ set->is_fread_set = 0;
+ set->is_fwrite_set = 0;
set->seek_func = ZERO_NULL;
set->seek_client = ZERO_NULL;
@@ -1825,18 +1827,26 @@ CURLcode Curl_setopt(struct SessionHandle *data,
CURLoption option,
* Set data write callback
*/
data->set.fwrite_func = va_arg(param, curl_write_callback);
- if(!data->set.fwrite_func)
+ if(!data->set.fwrite_func) {
+ data->set.is_fwrite_set = 0;
/* When set to NULL, reset to our internal default function */
data->set.fwrite_func = (curl_write_callback)fwrite;
+ }
+ else
+ data->set.is_fwrite_set = 0;
break;
case CURLOPT_READFUNCTION:
/*
* Read data callback
*/
data->set.fread_func = va_arg(param, curl_read_callback);
- if(!data->set.fread_func)
+ if(!data->set.fread_func) {
+ data->set.is_fread_set = 0;
/* When set to NULL, reset to our internal default function */
data->set.fread_func = (curl_read_callback)fread;
+ }
+ else
+ data->set.is_fread_set = 1;
break;
case CURLOPT_SEEKFUNCTION:
/*
diff --git a/lib/urldata.h b/lib/urldata.h
index ad172d6..aab5d23 100644
--- a/lib/urldata.h
+++ b/lib/urldata.h
@@ -1234,6 +1234,8 @@ struct UserDefined {
curl_write_callback fwrite_header; /* function that stores headers */
curl_write_callback fwrite_rtp; /* function that stores interleaved RTP */
curl_read_callback fread_func; /* function that reads the input */
+ int is_fread_set; /* boolean, has read callback been set to non-NULL? */
+ int is_fwrite_set; /* boolean, has write callback been set to non-NULL? */
curl_progress_callback fprogress; /* function for progress information */
curl_debug_callback fdebug; /* function that write informational data */
curl_ioctl_callback ioctl_func; /* function for I/O control */
diff --git a/src/main.c b/src/main.c
index 6e3ef3d..ef53769 100644
--- a/src/main.c
+++ b/src/main.c
@@ -4844,8 +4844,10 @@ operate(struct Configurable *config, int argc,
argv_item_t argv[])
input.config = config;
my_setopt(curl, CURLOPT_READDATA, &input);
/* what call to read */
- my_setopt(curl, CURLOPT_READFUNCTION, my_fread);
-
+ if ((outfile && !curlx_strequal("-", outfile)) ||
+ !curlx_strnequal(url, "telnet:", 7))
+ my_setopt(curl, CURLOPT_READFUNCTION, my_fread);
+
/* in 7.18.0, the CURLOPT_SEEKFUNCTION/DATA pair is taking over what
CURLOPT_IOCTLFUNCTION/DATA pair previously provided for seeking */
my_setopt(curl, CURLOPT_SEEKDATA, &input);
-------------------------------------------------------------------
List admin: http://cool.haxx.se/list/listinfo/curl-library
Etiquette: http://curl.haxx.se/mail/etiquette.html