2013-08-17 20:06:08 +04:00
|
|
|
/*
|
|
|
|
* Facility for queueing callback functions to be run from the
|
|
|
|
* top-level event loop after the current top-level activity finishes.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stddef.h>
|
|
|
|
|
|
|
|
#include "putty.h"
|
|
|
|
|
|
|
|
struct callback {
|
|
|
|
struct callback *next;
|
|
|
|
|
|
|
|
toplevel_callback_fn_t fn;
|
|
|
|
void *ctx;
|
|
|
|
};
|
|
|
|
|
2017-11-25 20:17:21 +03:00
|
|
|
struct callback *cbcurr = NULL, *cbhead = NULL, *cbtail = NULL;
|
2013-08-17 20:06:08 +04:00
|
|
|
|
|
|
|
toplevel_callback_notify_fn_t notify_frontend = NULL;
|
2018-09-12 11:10:51 +03:00
|
|
|
void *notify_ctx = NULL;
|
2013-08-17 20:06:08 +04:00
|
|
|
|
|
|
|
void request_callback_notifications(toplevel_callback_notify_fn_t fn,
|
2018-09-12 11:10:51 +03:00
|
|
|
void *ctx)
|
2013-08-17 20:06:08 +04:00
|
|
|
{
|
|
|
|
notify_frontend = fn;
|
2018-09-12 11:10:51 +03:00
|
|
|
notify_ctx = ctx;
|
2013-08-17 20:06:08 +04:00
|
|
|
}
|
|
|
|
|
2018-05-18 09:22:57 +03:00
|
|
|
static void run_idempotent_callback(void *ctx)
|
|
|
|
{
|
|
|
|
struct IdempotentCallback *ic = (struct IdempotentCallback *)ctx;
|
2018-10-29 22:50:29 +03:00
|
|
|
ic->queued = false;
|
2018-05-18 09:22:57 +03:00
|
|
|
ic->fn(ic->ctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
void queue_idempotent_callback(struct IdempotentCallback *ic)
|
|
|
|
{
|
|
|
|
if (ic->queued)
|
|
|
|
return;
|
2018-10-29 22:50:29 +03:00
|
|
|
ic->queued = true;
|
2018-05-18 09:22:57 +03:00
|
|
|
queue_toplevel_callback(run_idempotent_callback, ic);
|
|
|
|
}
|
|
|
|
|
2017-11-25 20:17:21 +03:00
|
|
|
void delete_callbacks_for_context(void *ctx)
|
|
|
|
{
|
|
|
|
struct callback *newhead, *newtail;
|
|
|
|
|
|
|
|
newhead = newtail = NULL;
|
|
|
|
while (cbhead) {
|
|
|
|
struct callback *cb = cbhead;
|
|
|
|
cbhead = cbhead->next;
|
2018-05-18 09:22:57 +03:00
|
|
|
if (cb->ctx == ctx ||
|
|
|
|
(cb->fn == run_idempotent_callback &&
|
|
|
|
((struct IdempotentCallback *)cb->ctx)->ctx == ctx)) {
|
2017-11-25 20:17:21 +03:00
|
|
|
sfree(cb);
|
|
|
|
} else {
|
|
|
|
if (!newhead)
|
|
|
|
newhead = cb;
|
|
|
|
else
|
|
|
|
newtail->next = cb;
|
|
|
|
|
|
|
|
newtail = cb;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
cbhead = newhead;
|
|
|
|
cbtail = newtail;
|
2018-10-25 20:34:19 +03:00
|
|
|
if (newtail)
|
|
|
|
newtail->next = NULL;
|
2017-11-25 20:17:21 +03:00
|
|
|
}
|
|
|
|
|
2013-08-17 20:06:08 +04:00
|
|
|
void queue_toplevel_callback(toplevel_callback_fn_t fn, void *ctx)
|
|
|
|
{
|
|
|
|
struct callback *cb;
|
|
|
|
|
|
|
|
cb = snew(struct callback);
|
|
|
|
cb->fn = fn;
|
|
|
|
cb->ctx = ctx;
|
|
|
|
|
2017-11-25 20:17:21 +03:00
|
|
|
/*
|
|
|
|
* If the front end has requested notification of pending
|
2013-08-17 20:06:08 +04:00
|
|
|
* callbacks, and we didn't already have one queued, let it know
|
2017-11-25 20:17:21 +03:00
|
|
|
* we do have one now.
|
|
|
|
*
|
|
|
|
* If cbcurr is non-NULL, i.e. we are actually in the middle of
|
|
|
|
* executing a callback right now, then we count that as the queue
|
|
|
|
* already having been non-empty. That saves the front end getting
|
|
|
|
* a constant stream of needless re-notifications if the last
|
|
|
|
* callback keeps re-scheduling itself.
|
|
|
|
*/
|
|
|
|
if (notify_frontend && !cbhead && !cbcurr)
|
2018-09-12 11:10:51 +03:00
|
|
|
notify_frontend(notify_ctx);
|
2013-08-17 20:06:08 +04:00
|
|
|
|
|
|
|
if (cbtail)
|
|
|
|
cbtail->next = cb;
|
|
|
|
else
|
|
|
|
cbhead = cb;
|
|
|
|
cbtail = cb;
|
|
|
|
cb->next = NULL;
|
|
|
|
}
|
|
|
|
|
Convert a lot of 'int' variables to 'bool'.
My normal habit these days, in new code, is to treat int and bool as
_almost_ completely separate types. I'm still willing to use C's
implicit test for zero on an integer (e.g. 'if (!blob.len)' is fine,
no need to spell it out as blob.len != 0), but generally, if a
variable is going to be conceptually a boolean, I like to declare it
bool and assign to it using 'true' or 'false' rather than 0 or 1.
PuTTY is an exception, because it predates the C99 bool, and I've
stuck to its existing coding style even when adding new code to it.
But it's been annoying me more and more, so now that I've decided C99
bool is an acceptable thing to require from our toolchain in the first
place, here's a quite thorough trawl through the source doing
'boolification'. Many variables and function parameters are now typed
as bool rather than int; many assignments of 0 or 1 to those variables
are now spelled 'true' or 'false'.
I managed this thorough conversion with the help of a custom clang
plugin that I wrote to trawl the AST and apply heuristics to point out
where things might want changing. So I've even managed to do a decent
job on parts of the code I haven't looked at in years!
To make the plugin's work easier, I pushed platform front ends
generally in the direction of using standard 'bool' in preference to
platform-specific boolean types like Windows BOOL or GTK's gboolean;
I've left the platform booleans in places they _have_ to be for the
platform APIs to work right, but variables only used by my own code
have been converted wherever I found them.
In a few places there are int values that look very like booleans in
_most_ of the places they're used, but have a rarely-used third value,
or a distinction between different nonzero values that most users
don't care about. In these cases, I've _removed_ uses of 'true' and
'false' for the return values, to emphasise that there's something
more subtle going on than a simple boolean answer:
- the 'multisel' field in dialog.h's list box structure, for which
the GTK front end in particular recognises a difference between 1
and 2 but nearly everything else treats as boolean
- the 'urgent' parameter to plug_receive, where 1 vs 2 tells you
something about the specific location of the urgent pointer, but
most clients only care about 0 vs 'something nonzero'
- the return value of wc_match, where -1 indicates a syntax error in
the wildcard.
- the return values from SSH-1 RSA-key loading functions, which use
-1 for 'wrong passphrase' and 0 for all other failures (so any
caller which already knows it's not loading an _encrypted private_
key can treat them as boolean)
- term->esc_query, and the 'query' parameter in toggle_mode in
terminal.c, which _usually_ hold 0 for ESC[123h or 1 for ESC[?123h,
but can also hold -1 for some other intervening character that we
don't support.
In a few places there's an integer that I haven't turned into a bool
even though it really _can_ only take values 0 or 1 (and, as above,
tried to make the call sites consistent in not calling those values
true and false), on the grounds that I thought it would make it more
confusing to imply that the 0 value was in some sense 'negative' or
bad and the 1 positive or good:
- the return value of plug_accepting uses the POSIXish convention of
0=success and nonzero=error; I think if I made it bool then I'd
also want to reverse its sense, and that's a job for a separate
piece of work.
- the 'screen' parameter to lineptr() in terminal.c, where 0 and 1
represent the default and alternate screens. There's no obvious
reason why one of those should be considered 'true' or 'positive'
or 'success' - they're just indices - so I've left it as int.
ssh_scp_recv had particularly confusing semantics for its previous int
return value: its call sites used '<= 0' to check for error, but it
never actually returned a negative number, just 0 or 1. Now the
function and its call sites agree that it's a bool.
In a couple of places I've renamed variables called 'ret', because I
don't like that name any more - it's unclear whether it means the
return value (in preparation) for the _containing_ function or the
return value received from a subroutine call, and occasionally I've
accidentally used the same variable for both and introduced a bug. So
where one of those got in my way, I've renamed it to 'toret' or 'retd'
(the latter short for 'returned') in line with my usual modern
practice, but I haven't done a thorough job of finding all of them.
Finally, one amusing side effect of doing this is that I've had to
separate quite a few chained assignments. It used to be perfectly fine
to write 'a = b = c = TRUE' when a,b,c were int and TRUE was just a
the 'true' defined by stdbool.h, that idiom provokes a warning from
gcc: 'suggest parentheses around assignment used as truth value'!
2018-11-02 22:23:19 +03:00
|
|
|
bool run_toplevel_callbacks(void)
|
2013-08-17 20:06:08 +04:00
|
|
|
{
|
Convert a lot of 'int' variables to 'bool'.
My normal habit these days, in new code, is to treat int and bool as
_almost_ completely separate types. I'm still willing to use C's
implicit test for zero on an integer (e.g. 'if (!blob.len)' is fine,
no need to spell it out as blob.len != 0), but generally, if a
variable is going to be conceptually a boolean, I like to declare it
bool and assign to it using 'true' or 'false' rather than 0 or 1.
PuTTY is an exception, because it predates the C99 bool, and I've
stuck to its existing coding style even when adding new code to it.
But it's been annoying me more and more, so now that I've decided C99
bool is an acceptable thing to require from our toolchain in the first
place, here's a quite thorough trawl through the source doing
'boolification'. Many variables and function parameters are now typed
as bool rather than int; many assignments of 0 or 1 to those variables
are now spelled 'true' or 'false'.
I managed this thorough conversion with the help of a custom clang
plugin that I wrote to trawl the AST and apply heuristics to point out
where things might want changing. So I've even managed to do a decent
job on parts of the code I haven't looked at in years!
To make the plugin's work easier, I pushed platform front ends
generally in the direction of using standard 'bool' in preference to
platform-specific boolean types like Windows BOOL or GTK's gboolean;
I've left the platform booleans in places they _have_ to be for the
platform APIs to work right, but variables only used by my own code
have been converted wherever I found them.
In a few places there are int values that look very like booleans in
_most_ of the places they're used, but have a rarely-used third value,
or a distinction between different nonzero values that most users
don't care about. In these cases, I've _removed_ uses of 'true' and
'false' for the return values, to emphasise that there's something
more subtle going on than a simple boolean answer:
- the 'multisel' field in dialog.h's list box structure, for which
the GTK front end in particular recognises a difference between 1
and 2 but nearly everything else treats as boolean
- the 'urgent' parameter to plug_receive, where 1 vs 2 tells you
something about the specific location of the urgent pointer, but
most clients only care about 0 vs 'something nonzero'
- the return value of wc_match, where -1 indicates a syntax error in
the wildcard.
- the return values from SSH-1 RSA-key loading functions, which use
-1 for 'wrong passphrase' and 0 for all other failures (so any
caller which already knows it's not loading an _encrypted private_
key can treat them as boolean)
- term->esc_query, and the 'query' parameter in toggle_mode in
terminal.c, which _usually_ hold 0 for ESC[123h or 1 for ESC[?123h,
but can also hold -1 for some other intervening character that we
don't support.
In a few places there's an integer that I haven't turned into a bool
even though it really _can_ only take values 0 or 1 (and, as above,
tried to make the call sites consistent in not calling those values
true and false), on the grounds that I thought it would make it more
confusing to imply that the 0 value was in some sense 'negative' or
bad and the 1 positive or good:
- the return value of plug_accepting uses the POSIXish convention of
0=success and nonzero=error; I think if I made it bool then I'd
also want to reverse its sense, and that's a job for a separate
piece of work.
- the 'screen' parameter to lineptr() in terminal.c, where 0 and 1
represent the default and alternate screens. There's no obvious
reason why one of those should be considered 'true' or 'positive'
or 'success' - they're just indices - so I've left it as int.
ssh_scp_recv had particularly confusing semantics for its previous int
return value: its call sites used '<= 0' to check for error, but it
never actually returned a negative number, just 0 or 1. Now the
function and its call sites agree that it's a bool.
In a couple of places I've renamed variables called 'ret', because I
don't like that name any more - it's unclear whether it means the
return value (in preparation) for the _containing_ function or the
return value received from a subroutine call, and occasionally I've
accidentally used the same variable for both and introduced a bug. So
where one of those got in my way, I've renamed it to 'toret' or 'retd'
(the latter short for 'returned') in line with my usual modern
practice, but I haven't done a thorough job of finding all of them.
Finally, one amusing side effect of doing this is that I've had to
separate quite a few chained assignments. It used to be perfectly fine
to write 'a = b = c = TRUE' when a,b,c were int and TRUE was just a
the 'true' defined by stdbool.h, that idiom provokes a warning from
gcc: 'suggest parentheses around assignment used as truth value'!
2018-11-02 22:23:19 +03:00
|
|
|
bool done_something = false;
|
Fix startup hang in Unix file transfer tools.
This seems to be a knock-on effect of my recent reworking of the SSH
code to be based around queues and callbacks. The loop iteration
function in uxsftp.c (ssh_sftp_do_select) would keep going round its
select loop until something had happened on one of its file
descriptors, and then return to the caller in the assumption that the
resulting data might have triggered whatever condition the caller was
waiting for - and if not, then the caller checks, finds nothing
interesting has happened, and resumes looping with no harm done.
But now, when something happens on an fd, it doesn't _synchronously_
trigger the follow-up condition PSFTP was waiting for (which, at
startup time, happens to be back->sendok() starting to return TRUE).
Instead, it schedules a callback, which will schedule a callback,
which ... ends up setting that flag. But by that time, the loop
function has already returned, the caller has found nothing
interesting and resumed looping, and _now_ the interesting thing
happens but it's too late because ssh_sftp_do_select will wait until
the next file descriptor activity before it next returns.
Solution: give run_toplevel_callbacks a return value which says
whether it's actually done something, and if so, return immediately in
case that was the droid the caller was looking for. As it were.
2018-05-24 18:54:16 +03:00
|
|
|
|
2013-09-15 18:05:31 +04:00
|
|
|
if (cbhead) {
|
2013-08-17 20:06:08 +04:00
|
|
|
/*
|
2017-11-25 20:17:21 +03:00
|
|
|
* Transfer the head callback into cbcurr to indicate that
|
|
|
|
* it's being executed. Then operations which transform the
|
|
|
|
* queue, like delete_callbacks_for_context, can proceed as if
|
|
|
|
* it's not there.
|
2013-08-17 20:06:08 +04:00
|
|
|
*/
|
2017-11-25 20:17:21 +03:00
|
|
|
cbcurr = cbhead;
|
|
|
|
cbhead = cbhead->next;
|
2013-09-15 18:05:31 +04:00
|
|
|
if (!cbhead)
|
|
|
|
cbtail = NULL;
|
2017-11-25 20:17:21 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Now run the callback, and then clear it out of cbcurr.
|
|
|
|
*/
|
|
|
|
cbcurr->fn(cbcurr->ctx);
|
|
|
|
sfree(cbcurr);
|
|
|
|
cbcurr = NULL;
|
Fix startup hang in Unix file transfer tools.
This seems to be a knock-on effect of my recent reworking of the SSH
code to be based around queues and callbacks. The loop iteration
function in uxsftp.c (ssh_sftp_do_select) would keep going round its
select loop until something had happened on one of its file
descriptors, and then return to the caller in the assumption that the
resulting data might have triggered whatever condition the caller was
waiting for - and if not, then the caller checks, finds nothing
interesting has happened, and resumes looping with no harm done.
But now, when something happens on an fd, it doesn't _synchronously_
trigger the follow-up condition PSFTP was waiting for (which, at
startup time, happens to be back->sendok() starting to return TRUE).
Instead, it schedules a callback, which will schedule a callback,
which ... ends up setting that flag. But by that time, the loop
function has already returned, the caller has found nothing
interesting and resumed looping, and _now_ the interesting thing
happens but it's too late because ssh_sftp_do_select will wait until
the next file descriptor activity before it next returns.
Solution: give run_toplevel_callbacks a return value which says
whether it's actually done something, and if so, return immediately in
case that was the droid the caller was looking for. As it were.
2018-05-24 18:54:16 +03:00
|
|
|
|
2018-10-29 22:50:29 +03:00
|
|
|
done_something = true;
|
2013-08-17 20:06:08 +04:00
|
|
|
}
|
Fix startup hang in Unix file transfer tools.
This seems to be a knock-on effect of my recent reworking of the SSH
code to be based around queues and callbacks. The loop iteration
function in uxsftp.c (ssh_sftp_do_select) would keep going round its
select loop until something had happened on one of its file
descriptors, and then return to the caller in the assumption that the
resulting data might have triggered whatever condition the caller was
waiting for - and if not, then the caller checks, finds nothing
interesting has happened, and resumes looping with no harm done.
But now, when something happens on an fd, it doesn't _synchronously_
trigger the follow-up condition PSFTP was waiting for (which, at
startup time, happens to be back->sendok() starting to return TRUE).
Instead, it schedules a callback, which will schedule a callback,
which ... ends up setting that flag. But by that time, the loop
function has already returned, the caller has found nothing
interesting and resumed looping, and _now_ the interesting thing
happens but it's too late because ssh_sftp_do_select will wait until
the next file descriptor activity before it next returns.
Solution: give run_toplevel_callbacks a return value which says
whether it's actually done something, and if so, return immediately in
case that was the droid the caller was looking for. As it were.
2018-05-24 18:54:16 +03:00
|
|
|
return done_something;
|
2013-09-15 18:05:31 +04:00
|
|
|
}
|
|
|
|
|
Convert a lot of 'int' variables to 'bool'.
My normal habit these days, in new code, is to treat int and bool as
_almost_ completely separate types. I'm still willing to use C's
implicit test for zero on an integer (e.g. 'if (!blob.len)' is fine,
no need to spell it out as blob.len != 0), but generally, if a
variable is going to be conceptually a boolean, I like to declare it
bool and assign to it using 'true' or 'false' rather than 0 or 1.
PuTTY is an exception, because it predates the C99 bool, and I've
stuck to its existing coding style even when adding new code to it.
But it's been annoying me more and more, so now that I've decided C99
bool is an acceptable thing to require from our toolchain in the first
place, here's a quite thorough trawl through the source doing
'boolification'. Many variables and function parameters are now typed
as bool rather than int; many assignments of 0 or 1 to those variables
are now spelled 'true' or 'false'.
I managed this thorough conversion with the help of a custom clang
plugin that I wrote to trawl the AST and apply heuristics to point out
where things might want changing. So I've even managed to do a decent
job on parts of the code I haven't looked at in years!
To make the plugin's work easier, I pushed platform front ends
generally in the direction of using standard 'bool' in preference to
platform-specific boolean types like Windows BOOL or GTK's gboolean;
I've left the platform booleans in places they _have_ to be for the
platform APIs to work right, but variables only used by my own code
have been converted wherever I found them.
In a few places there are int values that look very like booleans in
_most_ of the places they're used, but have a rarely-used third value,
or a distinction between different nonzero values that most users
don't care about. In these cases, I've _removed_ uses of 'true' and
'false' for the return values, to emphasise that there's something
more subtle going on than a simple boolean answer:
- the 'multisel' field in dialog.h's list box structure, for which
the GTK front end in particular recognises a difference between 1
and 2 but nearly everything else treats as boolean
- the 'urgent' parameter to plug_receive, where 1 vs 2 tells you
something about the specific location of the urgent pointer, but
most clients only care about 0 vs 'something nonzero'
- the return value of wc_match, where -1 indicates a syntax error in
the wildcard.
- the return values from SSH-1 RSA-key loading functions, which use
-1 for 'wrong passphrase' and 0 for all other failures (so any
caller which already knows it's not loading an _encrypted private_
key can treat them as boolean)
- term->esc_query, and the 'query' parameter in toggle_mode in
terminal.c, which _usually_ hold 0 for ESC[123h or 1 for ESC[?123h,
but can also hold -1 for some other intervening character that we
don't support.
In a few places there's an integer that I haven't turned into a bool
even though it really _can_ only take values 0 or 1 (and, as above,
tried to make the call sites consistent in not calling those values
true and false), on the grounds that I thought it would make it more
confusing to imply that the 0 value was in some sense 'negative' or
bad and the 1 positive or good:
- the return value of plug_accepting uses the POSIXish convention of
0=success and nonzero=error; I think if I made it bool then I'd
also want to reverse its sense, and that's a job for a separate
piece of work.
- the 'screen' parameter to lineptr() in terminal.c, where 0 and 1
represent the default and alternate screens. There's no obvious
reason why one of those should be considered 'true' or 'positive'
or 'success' - they're just indices - so I've left it as int.
ssh_scp_recv had particularly confusing semantics for its previous int
return value: its call sites used '<= 0' to check for error, but it
never actually returned a negative number, just 0 or 1. Now the
function and its call sites agree that it's a bool.
In a couple of places I've renamed variables called 'ret', because I
don't like that name any more - it's unclear whether it means the
return value (in preparation) for the _containing_ function or the
return value received from a subroutine call, and occasionally I've
accidentally used the same variable for both and introduced a bug. So
where one of those got in my way, I've renamed it to 'toret' or 'retd'
(the latter short for 'returned') in line with my usual modern
practice, but I haven't done a thorough job of finding all of them.
Finally, one amusing side effect of doing this is that I've had to
separate quite a few chained assignments. It used to be perfectly fine
to write 'a = b = c = TRUE' when a,b,c were int and TRUE was just a
the 'true' defined by stdbool.h, that idiom provokes a warning from
gcc: 'suggest parentheses around assignment used as truth value'!
2018-11-02 22:23:19 +03:00
|
|
|
bool toplevel_callback_pending(void)
|
2013-09-15 18:05:31 +04:00
|
|
|
{
|
2017-11-25 20:17:21 +03:00
|
|
|
return cbcurr != NULL || cbhead != NULL;
|
2013-08-17 20:06:08 +04:00
|
|
|
}
|