?? plink.c
字號:
/*
* Three cases. Either (a) there's a nonzero
* length string followed by an @, in which
* case that's user and the remainder is host.
* Or (b) there's only one string, not counting
* a potential initial @, and it exists in the
* saved-sessions database. Or (c) only one
* string and it _doesn't_ exist in the
* database.
*/
r = strrchr(p, '@');
if (r == p)
p++, r = NULL; /* discount initial @ */
if (r == NULL) {
/*
* One string.
*/
Config cfg2;
do_defaults(p, &cfg2);
if (loaded_session || cfg2.host[0] == '\0') {
/* No settings for this host; use defaults */
/* (or session was already loaded with -load) */
strncpy(cfg.host, p, sizeof(cfg.host) - 1);
cfg.host[sizeof(cfg.host) - 1] = '\0';
cfg.port = default_port;
} else {
cfg = cfg2;
/* Ick: patch up internal pointer after copy */
cfg.remote_cmd_ptr = cfg.remote_cmd;
}
} else {
*r++ = '\0';
strncpy(cfg.username, p, sizeof(cfg.username) - 1);
cfg.username[sizeof(cfg.username) - 1] = '\0';
strncpy(cfg.host, r, sizeof(cfg.host) - 1);
cfg.host[sizeof(cfg.host) - 1] = '\0';
cfg.port = default_port;
}
}
} else {
char *command;
int cmdlen, cmdsize;
cmdlen = cmdsize = 0;
command = NULL;
while (argc) {
while (*p) {
if (cmdlen >= cmdsize) {
cmdsize = cmdlen + 512;
command = sresize(command, cmdsize, char);
}
command[cmdlen++]=*p++;
}
if (cmdlen >= cmdsize) {
cmdsize = cmdlen + 512;
command = sresize(command, cmdsize, char);
}
command[cmdlen++]=' '; /* always add trailing space */
if (--argc) p = *++argv;
}
if (cmdlen) command[--cmdlen]='\0';
/* change trailing blank to NUL */
cfg.remote_cmd_ptr = command;
cfg.remote_cmd_ptr2 = NULL;
cfg.nopty = TRUE; /* command => no terminal */
break; /* done with cmdline */
}
}
}
if (errors)
return 1;
if (!*cfg.host) {
usage();
}
/*
* Trim leading whitespace off the hostname if it's there.
*/
{
int space = strspn(cfg.host, " \t");
memmove(cfg.host, cfg.host+space, 1+strlen(cfg.host)-space);
}
/* See if host is of the form user@host */
if (cfg.host[0] != '\0') {
char *atsign = strchr(cfg.host, '@');
/* Make sure we're not overflowing the user field */
if (atsign) {
if (atsign - cfg.host < sizeof cfg.username) {
strncpy(cfg.username, cfg.host, atsign - cfg.host);
cfg.username[atsign - cfg.host] = '\0';
}
memmove(cfg.host, atsign + 1, 1 + strlen(atsign + 1));
}
}
/*
* Perform command-line overrides on session configuration.
*/
cmdline_run_saved(&cfg);
/*
* Apply subsystem status.
*/
if (use_subsystem)
cfg.ssh_subsys = TRUE;
/*
* Trim a colon suffix off the hostname if it's there.
*/
cfg.host[strcspn(cfg.host, ":")] = '\0';
/*
* Remove any remaining whitespace from the hostname.
*/
{
int p1 = 0, p2 = 0;
while (cfg.host[p2] != '\0') {
if (cfg.host[p2] != ' ' && cfg.host[p2] != '\t') {
cfg.host[p1] = cfg.host[p2];
p1++;
}
p2++;
}
cfg.host[p1] = '\0';
}
if (!*cfg.remote_cmd_ptr)
flags |= FLAG_INTERACTIVE;
/*
* Select protocol. This is farmed out into a table in a
* separate file to enable an ssh-free variant.
*/
{
int i;
back = NULL;
for (i = 0; backends[i].backend != NULL; i++)
if (backends[i].protocol == cfg.protocol) {
back = backends[i].backend;
break;
}
if (back == NULL) {
fprintf(stderr,
"Internal fault: Unsupported protocol found\n");
return 1;
}
}
/*
* Select port.
*/
if (portnumber != -1)
cfg.port = portnumber;
sk_init();
if (p_WSAEventSelect == NULL) {
fprintf(stderr, "Plink requires WinSock 2\n");
return 1;
}
/*
* Start up the connection.
*/
netevent = CreateEvent(NULL, FALSE, FALSE, NULL);
{
const char *error;
char *realhost;
/* nodelay is only useful if stdin is a character device (console) */
int nodelay = cfg.tcp_nodelay &&
(GetFileType(GetStdHandle(STD_INPUT_HANDLE)) == FILE_TYPE_CHAR);
error = back->init(NULL, &backhandle, &cfg, cfg.host, cfg.port,
&realhost, nodelay, cfg.tcp_keepalives);
if (error) {
fprintf(stderr, "Unable to open connection:\n%s", error);
return 1;
}
logctx = log_init(NULL, &cfg);
back->provide_logctx(backhandle, logctx);
console_provide_logctx(logctx);
sfree(realhost);
}
connopen = 1;
stdinevent = CreateEvent(NULL, FALSE, FALSE, NULL);
stdoutevent = CreateEvent(NULL, FALSE, FALSE, NULL);
stderrevent = CreateEvent(NULL, FALSE, FALSE, NULL);
inhandle = GetStdHandle(STD_INPUT_HANDLE);
outhandle = GetStdHandle(STD_OUTPUT_HANDLE);
errhandle = GetStdHandle(STD_ERROR_HANDLE);
GetConsoleMode(inhandle, &orig_console_mode);
SetConsoleMode(inhandle, ENABLE_PROCESSED_INPUT);
main_thread_id = GetCurrentThreadId();
/*
* Turn off ECHO and LINE input modes. We don't care if this
* call fails, because we know we aren't necessarily running in
* a console.
*/
handles[0] = netevent;
handles[1] = stdinevent;
handles[2] = stdoutevent;
handles[3] = stderrevent;
sending = FALSE;
/*
* Create spare threads to write to stdout and stderr, so we
* can arrange asynchronous writes.
*/
odata.event = stdoutevent;
odata.eventback = CreateEvent(NULL, FALSE, FALSE, NULL);
odata.is_stderr = 0;
odata.busy = odata.done = 0;
if (!CreateThread(NULL, 0, stdout_write_thread,
&odata, 0, &out_threadid)) {
fprintf(stderr, "Unable to create output thread\n");
cleanup_exit(1);
}
edata.event = stderrevent;
edata.eventback = CreateEvent(NULL, FALSE, FALSE, NULL);
edata.is_stderr = 1;
edata.busy = edata.done = 0;
if (!CreateThread(NULL, 0, stdout_write_thread,
&edata, 0, &err_threadid)) {
fprintf(stderr, "Unable to create error output thread\n");
cleanup_exit(1);
}
while (1) {
int n;
if (!sending && back->sendok(backhandle)) {
/*
* Create a separate thread to read from stdin. This is
* a total pain, but I can't find another way to do it:
*
* - an overlapped ReadFile or ReadFileEx just doesn't
* happen; we get failure from ReadFileEx, and
* ReadFile blocks despite being given an OVERLAPPED
* structure. Perhaps we can't do overlapped reads
* on consoles. WHY THE HELL NOT?
*
* - WaitForMultipleObjects(netevent, console) doesn't
* work, because it signals the console when
* _anything_ happens, including mouse motions and
* other things that don't cause data to be readable
* - so we're back to ReadFile blocking.
*/
idata.event = stdinevent;
idata.eventback = CreateEvent(NULL, FALSE, FALSE, NULL);
if (!CreateThread(NULL, 0, stdin_read_thread,
&idata, 0, &in_threadid)) {
fprintf(stderr, "Unable to create input thread\n");
cleanup_exit(1);
}
sending = TRUE;
}
n = MsgWaitForMultipleObjects(4, handles, FALSE, INFINITE,
QS_POSTMESSAGE);
if (n == 0) {
WSANETWORKEVENTS things;
SOCKET socket;
extern SOCKET first_socket(int *), next_socket(int *);
extern int select_result(WPARAM, LPARAM);
int i, socketstate;
/*
* We must not call select_result() for any socket
* until we have finished enumerating within the tree.
* This is because select_result() may close the socket
* and modify the tree.
*/
/* Count the active sockets. */
i = 0;
for (socket = first_socket(&socketstate);
socket != INVALID_SOCKET;
socket = next_socket(&socketstate)) i++;
/* Expand the buffer if necessary. */
if (i > sksize) {
sksize = i + 16;
sklist = sresize(sklist, sksize, SOCKET);
}
/* Retrieve the sockets into sklist. */
skcount = 0;
for (socket = first_socket(&socketstate);
socket != INVALID_SOCKET;
socket = next_socket(&socketstate)) {
sklist[skcount++] = socket;
}
/* Now we're done enumerating; go through the list. */
for (i = 0; i < skcount; i++) {
WPARAM wp;
socket = sklist[i];
wp = (WPARAM) socket;
if (!p_WSAEnumNetworkEvents(socket, NULL, &things)) {
static const struct { int bit, mask; } eventtypes[] = {
{FD_CONNECT_BIT, FD_CONNECT},
{FD_READ_BIT, FD_READ},
{FD_CLOSE_BIT, FD_CLOSE},
{FD_OOB_BIT, FD_OOB},
{FD_WRITE_BIT, FD_WRITE},
{FD_ACCEPT_BIT, FD_ACCEPT},
};
int e;
noise_ultralight(socket);
noise_ultralight(things.lNetworkEvents);
for (e = 0; e < lenof(eventtypes); e++)
if (things.lNetworkEvents & eventtypes[e].mask) {
LPARAM lp;
int err = things.iErrorCode[eventtypes[e].bit];
lp = WSAMAKESELECTREPLY(eventtypes[e].mask, err);
connopen &= select_result(wp, lp);
}
}
}
} else if (n == 1) {
reading = 0;
noise_ultralight(idata.len);
if (connopen && back->socket(backhandle) != NULL) {
if (idata.len > 0) {
back->send(backhandle, idata.buffer, idata.len);
} else {
back->special(backhandle, TS_EOF);
}
}
} else if (n == 2) {
odata.busy = 0;
if (!odata.writeret) {
fprintf(stderr, "Unable to write to standard output\n");
cleanup_exit(0);
}
bufchain_consume(&stdout_data, odata.lenwritten);
if (bufchain_size(&stdout_data) > 0)
try_output(0);
if (connopen && back->socket(backhandle) != NULL) {
back->unthrottle(backhandle, bufchain_size(&stdout_data) +
bufchain_size(&stderr_data));
}
} else if (n == 3) {
edata.busy = 0;
if (!edata.writeret) {
fprintf(stderr, "Unable to write to standard output\n");
cleanup_exit(0);
}
bufchain_consume(&stderr_data, edata.lenwritten);
if (bufchain_size(&stderr_data) > 0)
try_output(1);
if (connopen && back->socket(backhandle) != NULL) {
back->unthrottle(backhandle, bufchain_size(&stdout_data) +
bufchain_size(&stderr_data));
}
} else if (n == 4) {
MSG msg;
while (PeekMessage(&msg, INVALID_HANDLE_VALUE,
WM_AGENT_CALLBACK, WM_AGENT_CALLBACK,
PM_REMOVE)) {
struct agent_callback *c = (struct agent_callback *)msg.lParam;
c->callback(c->callback_ctx, c->data, c->len);
sfree(c);
}
}
if (!reading && back->sendbuffer(backhandle) < MAX_STDIN_BACKLOG) {
SetEvent(idata.eventback);
reading = 1;
}
if ((!connopen || back->socket(backhandle) == NULL) &&
bufchain_size(&stdout_data) == 0 &&
bufchain_size(&stderr_data) == 0)
break; /* we closed the connection */
}
exitcode = back->exitcode(backhandle);
if (exitcode < 0) {
fprintf(stderr, "Remote process exit code unavailable\n");
exitcode = 1; /* this is an error condition */
}
cleanup_exit(exitcode);
return 0; /* placate compiler warning */
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -