mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-07-18 11:31:00 -05:00
Rename most of the platform source files.
This gets rid of all those annoying 'win', 'ux' and 'gtk' prefixes which made filenames annoying to type and to tab-complete. Also, as with my other recent renaming sprees, I've taken the opportunity to expand and clarify some of the names so that they're not such cryptic abbreviations.
This commit is contained in:
236
windows/named-pipe-server.c
Normal file
236
windows/named-pipe-server.c
Normal file
@ -0,0 +1,236 @@
|
||||
/*
|
||||
* Windows support module which deals with being a named-pipe server.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "tree234.h"
|
||||
#include "putty.h"
|
||||
#include "network.h"
|
||||
#include "proxy.h"
|
||||
#include "ssh.h"
|
||||
|
||||
#include "security-api.h"
|
||||
|
||||
typedef struct NamedPipeServerSocket {
|
||||
/* Parameters for (repeated) creation of named pipe objects */
|
||||
PSECURITY_DESCRIPTOR psd;
|
||||
PACL acl;
|
||||
char *pipename;
|
||||
|
||||
/* The current named pipe object + attempt to connect to it */
|
||||
HANDLE pipehandle;
|
||||
OVERLAPPED connect_ovl;
|
||||
struct handle *callback_handle; /* winhandl.c's reference */
|
||||
|
||||
/* PuTTY Socket machinery */
|
||||
Plug *plug;
|
||||
char *error;
|
||||
|
||||
Socket sock;
|
||||
} NamedPipeServerSocket;
|
||||
|
||||
static Plug *sk_namedpipeserver_plug(Socket *s, Plug *p)
|
||||
{
|
||||
NamedPipeServerSocket *ps = container_of(s, NamedPipeServerSocket, sock);
|
||||
Plug *ret = ps->plug;
|
||||
if (p)
|
||||
ps->plug = p;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void sk_namedpipeserver_close(Socket *s)
|
||||
{
|
||||
NamedPipeServerSocket *ps = container_of(s, NamedPipeServerSocket, sock);
|
||||
|
||||
if (ps->callback_handle)
|
||||
handle_free(ps->callback_handle);
|
||||
CloseHandle(ps->pipehandle);
|
||||
CloseHandle(ps->connect_ovl.hEvent);
|
||||
sfree(ps->error);
|
||||
sfree(ps->pipename);
|
||||
if (ps->acl)
|
||||
LocalFree(ps->acl);
|
||||
if (ps->psd)
|
||||
LocalFree(ps->psd);
|
||||
sfree(ps);
|
||||
}
|
||||
|
||||
static const char *sk_namedpipeserver_socket_error(Socket *s)
|
||||
{
|
||||
NamedPipeServerSocket *ps = container_of(s, NamedPipeServerSocket, sock);
|
||||
return ps->error;
|
||||
}
|
||||
|
||||
static SocketPeerInfo *sk_namedpipeserver_peer_info(Socket *s)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool create_named_pipe(NamedPipeServerSocket *ps, bool first_instance)
|
||||
{
|
||||
SECURITY_ATTRIBUTES sa;
|
||||
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sa.nLength = sizeof(sa);
|
||||
sa.lpSecurityDescriptor = ps->psd;
|
||||
sa.bInheritHandle = false;
|
||||
|
||||
ps->pipehandle = CreateNamedPipe
|
||||
(/* lpName */
|
||||
ps->pipename,
|
||||
|
||||
/* dwOpenMode */
|
||||
PIPE_ACCESS_DUPLEX |
|
||||
FILE_FLAG_OVERLAPPED |
|
||||
(first_instance ? FILE_FLAG_FIRST_PIPE_INSTANCE : 0),
|
||||
|
||||
/* dwPipeMode */
|
||||
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT
|
||||
#ifdef PIPE_REJECT_REMOTE_CLIENTS
|
||||
| PIPE_REJECT_REMOTE_CLIENTS
|
||||
#endif
|
||||
,
|
||||
|
||||
/* nMaxInstances */
|
||||
PIPE_UNLIMITED_INSTANCES,
|
||||
|
||||
/* nOutBufferSize, nInBufferSize */
|
||||
4096, 4096, /* FIXME: think harder about buffer sizes? */
|
||||
|
||||
/* nDefaultTimeOut */
|
||||
0 /* default timeout */,
|
||||
|
||||
/* lpSecurityAttributes */
|
||||
&sa);
|
||||
|
||||
return ps->pipehandle != INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
static Socket *named_pipe_accept(accept_ctx_t ctx, Plug *plug)
|
||||
{
|
||||
HANDLE conn = (HANDLE)ctx.p;
|
||||
|
||||
return make_handle_socket(conn, conn, NULL, plug, true);
|
||||
}
|
||||
|
||||
static void named_pipe_accept_loop(NamedPipeServerSocket *ps,
|
||||
bool got_one_already)
|
||||
{
|
||||
while (1) {
|
||||
int error;
|
||||
char *errmsg;
|
||||
|
||||
if (got_one_already) {
|
||||
/* If we were called with a connection already waiting,
|
||||
* skip this step. */
|
||||
got_one_already = false;
|
||||
error = 0;
|
||||
} else {
|
||||
/*
|
||||
* Call ConnectNamedPipe, which might succeed or might
|
||||
* tell us that an overlapped operation is in progress and
|
||||
* we should wait for our event object.
|
||||
*/
|
||||
if (ConnectNamedPipe(ps->pipehandle, &ps->connect_ovl))
|
||||
error = 0;
|
||||
else
|
||||
error = GetLastError();
|
||||
|
||||
if (error == ERROR_IO_PENDING)
|
||||
return;
|
||||
}
|
||||
|
||||
if (error == 0 || error == ERROR_PIPE_CONNECTED) {
|
||||
/*
|
||||
* We've successfully retrieved an incoming connection, so
|
||||
* ps->pipehandle now refers to that connection. So
|
||||
* convert that handle into a separate connection-type
|
||||
* Socket, and create a fresh one to be the new listening
|
||||
* pipe.
|
||||
*/
|
||||
HANDLE conn = ps->pipehandle;
|
||||
accept_ctx_t actx;
|
||||
|
||||
actx.p = (void *)conn;
|
||||
if (plug_accepting(ps->plug, named_pipe_accept, actx)) {
|
||||
/*
|
||||
* If the plug didn't want the connection, might as
|
||||
* well close this handle.
|
||||
*/
|
||||
CloseHandle(conn);
|
||||
}
|
||||
|
||||
if (!create_named_pipe(ps, false)) {
|
||||
error = GetLastError();
|
||||
} else {
|
||||
/*
|
||||
* Go round again to see if more connections can be
|
||||
* got, or to begin waiting on the event object.
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
errmsg = dupprintf("Error while listening to named pipe: %s",
|
||||
win_strerror(error));
|
||||
plug_log(ps->plug, 1, sk_namedpipe_addr(ps->pipename), 0,
|
||||
errmsg, error);
|
||||
sfree(errmsg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void named_pipe_connect_callback(void *vps)
|
||||
{
|
||||
NamedPipeServerSocket *ps = (NamedPipeServerSocket *)vps;
|
||||
named_pipe_accept_loop(ps, true);
|
||||
}
|
||||
|
||||
/*
|
||||
* This socket type is only used for listening, so it should never
|
||||
* be asked to write or set_frozen.
|
||||
*/
|
||||
static const SocketVtable NamedPipeServerSocket_sockvt = {
|
||||
.plug = sk_namedpipeserver_plug,
|
||||
.close = sk_namedpipeserver_close,
|
||||
.socket_error = sk_namedpipeserver_socket_error,
|
||||
.peer_info = sk_namedpipeserver_peer_info,
|
||||
};
|
||||
|
||||
Socket *new_named_pipe_listener(const char *pipename, Plug *plug)
|
||||
{
|
||||
NamedPipeServerSocket *ret = snew(NamedPipeServerSocket);
|
||||
ret->sock.vt = &NamedPipeServerSocket_sockvt;
|
||||
ret->plug = plug;
|
||||
ret->error = NULL;
|
||||
ret->psd = NULL;
|
||||
ret->pipename = dupstr(pipename);
|
||||
ret->acl = NULL;
|
||||
ret->callback_handle = NULL;
|
||||
|
||||
assert(strncmp(pipename, "\\\\.\\pipe\\", 9) == 0);
|
||||
assert(strchr(pipename + 9, '\\') == NULL);
|
||||
|
||||
if (!make_private_security_descriptor(GENERIC_READ | GENERIC_WRITE,
|
||||
&ret->psd, &ret->acl, &ret->error)) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (!create_named_pipe(ret, true)) {
|
||||
ret->error = dupprintf("unable to create named pipe '%s': %s",
|
||||
pipename, win_strerror(GetLastError()));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
memset(&ret->connect_ovl, 0, sizeof(ret->connect_ovl));
|
||||
ret->connect_ovl.hEvent = CreateEvent(NULL, true, false, NULL);
|
||||
ret->callback_handle =
|
||||
handle_add_foreign_event(ret->connect_ovl.hEvent,
|
||||
named_pipe_connect_callback, ret);
|
||||
named_pipe_accept_loop(ret, false);
|
||||
|
||||
cleanup:
|
||||
return &ret->sock;
|
||||
}
|
Reference in New Issue
Block a user