a serial port backend:
- In order to do simultaneous reading and writing on the same
HANDLE, you must enable overlapped access and pass an OVERLAPPED
structure to each ReadFile and WriteFile call. This would make
sense if it were an optional thing I could do if I wanted to do
the reading and writing in the same thread, but making it
mandatory even if I'm doing them in _different_ threads is just
annoying and arbitrary.
- Serial ports occasionally return length 0 from ReadFile, for no
particularly good reason. Fortunately serial ports also don't
have a real EOF condition to speak of, so ignoring EOFs is
actually a viable response in spite of sounding utterly gross.
Hence, handle_{input,output}_new() now accept a flags parameter,
which includes a flag to enable the OVERLAPPED bureaucracy and a
flag to cause EOFs to be ignored on input handles. The current
clients of winhandl.c do not use either of these.
git-svn-id: svn://svn.tartarus.org/sgt/putty@6813
cda61777-01e9-0310-a592-
d414129be87e
void *privdata; /* for client to remember who they are */
/*
void *privdata; /* for client to remember who they are */
/*
+ * Data set at initialisation and then read-only.
+ */
+ int flags;
+
+ /*
* Data set by the input thread before signalling ev_to_main,
* and read by the main thread after receiving that signal.
*/
* Data set by the input thread before signalling ev_to_main,
* and read by the main thread after receiving that signal.
*/
static DWORD WINAPI handle_input_threadfunc(void *param)
{
struct handle_input *ctx = (struct handle_input *) param;
static DWORD WINAPI handle_input_threadfunc(void *param)
{
struct handle_input *ctx = (struct handle_input *) param;
+ OVERLAPPED ovl, *povl;
+
+ if (ctx->flags & HANDLE_FLAG_OVERLAPPED)
+ povl = &ovl;
+ else
+ povl = NULL;
+ if (povl)
+ memset(povl, 0, sizeof(OVERLAPPED));
ctx->readret = ReadFile(ctx->h, ctx->buffer, sizeof(ctx->buffer),
ctx->readret = ReadFile(ctx->h, ctx->buffer, sizeof(ctx->buffer),
+ &ctx->len, povl);
+ if (povl && !ctx->readret && GetLastError() == ERROR_IO_PENDING)
+ ctx->readret = GetOverlappedResult(ctx->h, povl, &ctx->len, TRUE);
+
if (!ctx->readret)
ctx->len = 0;
if (!ctx->readret)
ctx->len = 0;
+ if (ctx->readret && ctx->len == 0 &&
+ (ctx->flags & HANDLE_FLAG_IGNOREEOF))
+ continue;
+
SetEvent(ctx->ev_to_main);
if (!ctx->len)
SetEvent(ctx->ev_to_main);
if (!ctx->len)
void *privdata; /* for client to remember who they are */
/*
void *privdata; /* for client to remember who they are */
/*
+ * Data set at initialisation and then read-only.
+ */
+ int flags;
+
+ /*
* Data set by the main thread before signalling ev_from_main,
* and read by the input thread after receiving that signal.
*/
* Data set by the main thread before signalling ev_from_main,
* and read by the input thread after receiving that signal.
*/
static DWORD WINAPI handle_output_threadfunc(void *param)
{
struct handle_output *ctx = (struct handle_output *) param;
static DWORD WINAPI handle_output_threadfunc(void *param)
{
struct handle_output *ctx = (struct handle_output *) param;
+ OVERLAPPED ovl, *povl;
+
+ if (ctx->flags & HANDLE_FLAG_OVERLAPPED)
+ povl = &ovl;
+ else
+ povl = NULL;
while (1) {
WaitForSingleObject(ctx->ev_from_main, INFINITE);
while (1) {
WaitForSingleObject(ctx->ev_from_main, INFINITE);
SetEvent(ctx->ev_to_main);
break;
}
SetEvent(ctx->ev_to_main);
break;
}
+ if (povl)
+ memset(povl, 0, sizeof(OVERLAPPED));
ctx->writeret = WriteFile(ctx->h, ctx->buffer, ctx->len,
ctx->writeret = WriteFile(ctx->h, ctx->buffer, ctx->len,
- &ctx->lenwritten, NULL);
+ &ctx->lenwritten, povl);
+ if (povl && !ctx->writeret && GetLastError() == ERROR_IO_PENDING)
+ ctx->writeret = GetOverlappedResult(ctx->h, povl,
+ &ctx->lenwritten, TRUE);
+
SetEvent(ctx->ev_to_main);
if (!ctx->writeret)
break;
SetEvent(ctx->ev_to_main);
if (!ctx->writeret)
break;
}
struct handle *handle_input_new(HANDLE handle, handle_inputfn_t gotdata,
}
struct handle *handle_input_new(HANDLE handle, handle_inputfn_t gotdata,
+ void *privdata, int flags)
{
struct handle *h = snew(struct handle);
{
struct handle *h = snew(struct handle);
h->u.i.moribund = FALSE;
h->u.i.done = FALSE;
h->u.i.privdata = privdata;
h->u.i.moribund = FALSE;
h->u.i.done = FALSE;
h->u.i.privdata = privdata;
if (!handles_by_evtomain)
handles_by_evtomain = newtree234(handle_cmp_evtomain);
if (!handles_by_evtomain)
handles_by_evtomain = newtree234(handle_cmp_evtomain);
}
struct handle *handle_output_new(HANDLE handle, handle_outputfn_t sentdata,
}
struct handle *handle_output_new(HANDLE handle, handle_outputfn_t sentdata,
+ void *privdata, int flags)
{
struct handle *h = snew(struct handle);
{
struct handle *h = snew(struct handle);
h->u.o.privdata = privdata;
bufchain_init(&h->u.o.queued_data);
h->u.o.sentdata = sentdata;
h->u.o.privdata = privdata;
bufchain_init(&h->u.o.queued_data);
h->u.o.sentdata = sentdata;
if (!handles_by_evtomain)
handles_by_evtomain = newtree234(handle_cmp_evtomain);
if (!handles_by_evtomain)
handles_by_evtomain = newtree234(handle_cmp_evtomain);
* (The input one we leave until we're through the
* authentication process.)
*/
* (The input one we leave until we're through the
* authentication process.)
*/
- stdout_handle = handle_output_new(outhandle, stdouterr_sent, NULL);
- stderr_handle = handle_output_new(errhandle, stdouterr_sent, NULL);
+ stdout_handle = handle_output_new(outhandle, stdouterr_sent, NULL, 0);
+ stderr_handle = handle_output_new(errhandle, stdouterr_sent, NULL, 0);
main_thread_id = GetCurrentThreadId();
main_thread_id = GetCurrentThreadId();
DWORD ticks;
if (!sending && back->sendok(backhandle)) {
DWORD ticks;
if (!sending && back->sendok(backhandle)) {
- stdin_handle = handle_input_new(inhandle, stdin_gotdata, NULL);
+ stdin_handle = handle_input_new(inhandle, stdin_gotdata, NULL,
+ 0);
ret->to_cmd_H = us_to_cmd;\r
ret->from_cmd_H = us_from_cmd;\r
\r
ret->to_cmd_H = us_to_cmd;\r
ret->from_cmd_H = us_from_cmd;\r
\r
- ret->from_cmd_h = handle_input_new(ret->from_cmd_H, localproxy_gotdata, ret);\r
- ret->to_cmd_h = handle_output_new(ret->to_cmd_H,\r
- localproxy_sentdata, ret);\r
+ ret->from_cmd_h = handle_input_new(ret->from_cmd_H, localproxy_gotdata,\r
+ ret, 0);\r
+ ret->to_cmd_h = handle_output_new(ret->to_cmd_H, localproxy_sentdata,\r
+ ret, 0);\r
\r
/* We are responsible for this and don't need it any more */\r
sk_addr_free(addr);\r
\r
/* We are responsible for this and don't need it any more */\r
sk_addr_free(addr);\r
/*
* Exports from winhandl.c.
*/
/*
* Exports from winhandl.c.
*/
+#define HANDLE_FLAG_OVERLAPPED 1
+#define HANDLE_FLAG_IGNOREEOF 2
struct handle;
typedef int (*handle_inputfn_t)(struct handle *h, void *data, int len);
typedef void (*handle_outputfn_t)(struct handle *h, int new_backlog);
struct handle *handle_input_new(HANDLE handle, handle_inputfn_t gotdata,
struct handle;
typedef int (*handle_inputfn_t)(struct handle *h, void *data, int len);
typedef void (*handle_outputfn_t)(struct handle *h, int new_backlog);
struct handle *handle_input_new(HANDLE handle, handle_inputfn_t gotdata,
+ void *privdata, int flags);
struct handle *handle_output_new(HANDLE handle, handle_outputfn_t sentdata,
struct handle *handle_output_new(HANDLE handle, handle_outputfn_t sentdata,
+ void *privdata, int flags);
int handle_write(struct handle *h, const void *data, int len);
HANDLE *handle_get_events(int *nevents);
void handle_free(struct handle *h);
int handle_write(struct handle *h, const void *data, int len);
HANDLE *handle_get_events(int *nevents);
void handle_free(struct handle *h);