1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-10 09:58:01 +00:00
putty-source/pageantc.c
Simon Tatham 135abf2445 Asynchronous agent requests on Windows. Actually, I've kept the
ability to do synchronous ones as well, because PSCP and PSFTP don't
really need async ones and it would have been a serious pain to
implement them. Also, Pageant itself when run as a client of its
primary instance doesn't benefit noticeably from async agent
requests.

[originally from svn r3154]
2003-04-28 13:59:32 +00:00

135 lines
3.5 KiB
C

/*
* Pageant client code.
*/
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include "putty.h"
#define AGENT_COPYDATA_ID 0x804e50ba /* random goop */
#define AGENT_MAX_MSGLEN 8192
#define GET_32BIT(cp) \
(((unsigned long)(unsigned char)(cp)[0] << 24) | \
((unsigned long)(unsigned char)(cp)[1] << 16) | \
((unsigned long)(unsigned char)(cp)[2] << 8) | \
((unsigned long)(unsigned char)(cp)[3]))
int agent_exists(void)
{
HWND hwnd;
hwnd = FindWindow("Pageant", "Pageant");
if (!hwnd)
return FALSE;
else
return TRUE;
}
struct agent_query_data {
COPYDATASTRUCT cds;
unsigned char *mapping;
HANDLE handle;
char *mapname;
HWND hwnd;
void (*callback)(void *, void *, int);
void *callback_ctx;
};
DWORD WINAPI agent_query_thread(LPVOID param)
{
struct agent_query_data *data = (struct agent_query_data *)param;
unsigned char *ret;
int id, retlen;
id = SendMessage(data->hwnd, WM_COPYDATA, (WPARAM) NULL,
(LPARAM) &data->cds);
ret = NULL;
if (id > 0) {
retlen = 4 + GET_32BIT(data->mapping);
ret = snewn(retlen, unsigned char);
if (ret) {
memcpy(ret, data->mapping, retlen);
}
}
if (!ret)
retlen = 0;
UnmapViewOfFile(data->mapping);
CloseHandle(data->handle);
sfree(data->mapname);
agent_schedule_callback(data->callback, data->callback_ctx, ret, retlen);
return 0;
}
int agent_query(void *in, int inlen, void **out, int *outlen,
void (*callback)(void *, void *, int), void *callback_ctx)
{
HWND hwnd;
char *mapname;
HANDLE filemap;
unsigned char *p, *ret;
int id, retlen;
COPYDATASTRUCT cds;
*out = NULL;
*outlen = 0;
hwnd = FindWindow("Pageant", "Pageant");
if (!hwnd)
return 1; /* *out == NULL, so failure */
mapname = dupprintf("PageantRequest%08x", (unsigned)GetCurrentThreadId());
filemap = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,
0, AGENT_MAX_MSGLEN, mapname);
if (!filemap)
return 1; /* *out == NULL, so failure */
p = MapViewOfFile(filemap, FILE_MAP_WRITE, 0, 0, 0);
memcpy(p, in, inlen);
cds.dwData = AGENT_COPYDATA_ID;
cds.cbData = 1 + strlen(mapname);
cds.lpData = mapname;
if (callback != NULL && !(flags & FLAG_SYNCAGENT)) {
/*
* We need an asynchronous Pageant request. Since I know of
* no way to stop SendMessage from blocking the thread it's
* called in, I see no option but to start a fresh thread.
* When we're done we'll PostMessage the result back to our
* main window, so that the callback is done in the primary
* thread to avoid concurrency.
*/
struct agent_query_data *data = snew(struct agent_query_data);
DWORD threadid;
data->mapping = p;
data->handle = filemap;
data->mapname = mapname;
data->callback = callback;
data->callback_ctx = callback_ctx;
data->cds = cds; /* structure copy */
data->hwnd = hwnd;
if (CreateThread(NULL, 0, agent_query_thread, data, 0, &threadid))
return 0;
sfree(data);
}
/*
* The user either passed a null callback (indicating that the
* query is required to be synchronous) or CreateThread failed.
* Either way, we need a synchronous request.
*/
id = SendMessage(hwnd, WM_COPYDATA, (WPARAM) NULL, (LPARAM) & cds);
if (id > 0) {
retlen = 4 + GET_32BIT(p);
ret = snewn(retlen, unsigned char);
if (ret) {
memcpy(ret, p, retlen);
*out = ret;
*outlen = retlen;
}
}
UnmapViewOfFile(p);
CloseHandle(filemap);
return 1;
}