Cleaned up shell-host.c, termio.c, tncon.c, tnnet.c

This commit is contained in:
bagajjal 2017-02-04 00:37:08 -08:00 committed by Manoj Ampalam
parent f83d286c82
commit 35ea56a9a7
4 changed files with 1498 additions and 1662 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1,3 +1,40 @@
/*
* Author: Manoj Ampalam <manojamp@microsoft.com>
* read() and write() on tty using worker threads to handle
* synchronous Windows Console IO
*
* Author: Ray Hayes <ray.hayes@microsoft.com>
* TTY/PTY support added by capturing all terminal input events
*
* Author: Balu <bagajjal@microsoft.com>
* Misc fixes and code cleanup
*
* Copyright (c) 2017 Microsoft Corp.
* All rights reserved
*
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <Windows.h>
#include "w32fd.h"
#include "tncon.h"
@ -12,12 +49,11 @@ struct io_status {
DWORD transferred;
DWORD error;
};
static struct io_status read_status, write_status;
static VOID CALLBACK ReadAPCProc(
_In_ ULONG_PTR dwParam
) {
/* APC that gets queued on main thread when a sync Read completes on worker thread */
static VOID CALLBACK
ReadAPCProc(_In_ ULONG_PTR dwParam) {
struct w32_io* pio = (struct w32_io*)dwParam;
debug3("TermRead CB - io:%p, bytes: %d, pending: %d, error: %d", pio, read_status.transferred,
pio->read_details.pending, read_status.error);
@ -30,39 +66,35 @@ static VOID CALLBACK ReadAPCProc(
pio->read_overlapped.hEvent = 0;
}
static DWORD WINAPI ReadConsoleThread(
_In_ LPVOID lpParameter
) {
int nBytesReturned = 0;
/* Read worker thread */
static DWORD WINAPI
ReadConsoleThread(_In_ LPVOID lpParameter) {
int nBytesReturned = 0;
struct w32_io* pio = (struct w32_io*)lpParameter;
struct w32_io* pio = (struct w32_io*)lpParameter;
debug3("TermRead thread, io:%p", pio);
memset(&read_status, 0, sizeof(read_status));
while (nBytesReturned == 0) {
nBytesReturned = ReadConsoleForTermEmul(WINHANDLE(pio),
pio->read_details.buf, pio->read_details.buf_size);
}
read_status.transferred = nBytesReturned;
if (0 == QueueUserAPC(ReadAPCProc, main_thread, (ULONG_PTR)pio)) {
debug("TermRead thread - ERROR QueueUserAPC failed %d, io:%p", GetLastError(), pio);
pio->read_details.pending = FALSE;
pio->read_details.error = GetLastError();
DebugBreak();
}
debug3("TermRead thread, io:%p", pio);
memset(&read_status, 0, sizeof(read_status));
while (nBytesReturned == 0) {
nBytesReturned = ReadConsoleForTermEmul(WINHANDLE(pio),
pio->read_details.buf, pio->read_details.buf_size);
}
read_status.transferred = nBytesReturned;
if (0 == QueueUserAPC(ReadAPCProc, main_thread, (ULONG_PTR)pio)) {
debug("TermRead thread - ERROR QueueUserAPC failed %d, io:%p", GetLastError(), pio);
pio->read_details.pending = FALSE;
pio->read_details.error = GetLastError();
DebugBreak();
}
return 0;
return 0;
}
/* Initiates read on tty */
int
termio_initiate_read(struct w32_io* pio) {
HANDLE read_thread;
debug3("TermRead initiate io:%p", pio);
if (pio->read_details.buf_size == 0) {
pio->read_details.buf = malloc(TERM_IO_BUF_SIZE);
if (pio->read_details.buf == NULL) {
@ -72,7 +104,7 @@ termio_initiate_read(struct w32_io* pio) {
pio->read_details.buf_size = TERM_IO_BUF_SIZE;
}
read_thread = CreateThread(NULL, 0, ReadConsoleThread, pio, 0, NULL);
read_thread = CreateThread(NULL, 0, ReadConsoleThread, pio, 0, NULL);
if (read_thread == NULL) {
errno = errno_from_Win32Error(GetLastError());
debug("TermRead initiate - ERROR CreateThread %d, io:%p", GetLastError(), pio);
@ -84,15 +116,15 @@ termio_initiate_read(struct w32_io* pio) {
return 0;
}
static VOID CALLBACK WriteAPCProc(
_In_ ULONG_PTR dwParam
) {
/* APC that gets queued on main thread when a sync Write completes on worker thread */
static VOID CALLBACK
WriteAPCProc(_In_ ULONG_PTR dwParam) {
struct w32_io* pio = (struct w32_io*)dwParam;
debug3("TermWrite CB - io:%p, bytes: %d, pending: %d, error: %d", pio, write_status.transferred,
pio->write_details.pending, write_status.error);
pio->write_details.error = write_status.error;
pio->write_details.remaining -= write_status.transferred;
/*TODO- assert that reamining is 0 by now*/
/* TODO- assert that reamining is 0 by now */
pio->write_details.completed = 0;
pio->write_details.pending = FALSE;
WaitForSingleObject(pio->write_overlapped.hEvent, INFINITE);
@ -100,28 +132,28 @@ static VOID CALLBACK WriteAPCProc(
pio->write_overlapped.hEvent = 0;
}
static DWORD WINAPI WriteThread(
_In_ LPVOID lpParameter
) {
/* Write worker thread */
static DWORD WINAPI
WriteThread(_In_ LPVOID lpParameter) {
struct w32_io* pio = (struct w32_io*)lpParameter;
char *respbuf = NULL;
size_t resplen = 0;
DWORD dwSavedAttributes = ENABLE_PROCESSED_INPUT;
char *respbuf = NULL;
size_t resplen = 0;
DWORD dwSavedAttributes = ENABLE_PROCESSED_INPUT;
debug3("TermWrite thread, io:%p", pio);
if (in_raw_mode == 0) {
if (in_raw_mode == 0) {
/* convert stream to utf16 and dump on console */
pio->write_details.buf[write_status.to_transfer] = '\0';
wchar_t* t = utf8_to_utf16(pio->write_details.buf);
WriteConsoleW(WINHANDLE(pio), t, wcslen(t), 0, 0);
free(t);
write_status.transferred = write_status.to_transfer;
} else {
/* console mode */
telProcessNetwork(pio->write_details.buf, write_status.to_transfer, &respbuf, &resplen);
/*TODO - respbuf is not null in some cases, this needs to be returned back via read stream*/
write_status.transferred = write_status.to_transfer;
}
} else {
/* console mode */
telProcessNetwork(pio->write_details.buf, write_status.to_transfer, &respbuf, &resplen);
/* TODO - respbuf is not null in some cases, this needs to be returned back via read stream */
write_status.transferred = write_status.to_transfer;
}
if (0 == QueueUserAPC(WriteAPCProc, main_thread, (ULONG_PTR)pio)) {
debug("TermWrite thread - ERROR QueueUserAPC failed %d, io:%p", GetLastError(), pio);
@ -132,10 +164,10 @@ static DWORD WINAPI WriteThread(
return 0;
}
/* Initiates write on tty */
int
termio_initiate_write(struct w32_io* pio, DWORD num_bytes) {
HANDLE write_thread;
debug3("TermWrite initiate io:%p", pio);
memset(&write_status, 0, sizeof(write_status));
write_status.to_transfer = num_bytes;
@ -151,28 +183,26 @@ termio_initiate_write(struct w32_io* pio, DWORD num_bytes) {
return 0;
}
int termio_close(struct w32_io* pio) {
/* tty close */
int
termio_close(struct w32_io* pio) {
debug2("termio_close - pio:%p", pio);
HANDLE h;
CancelIoEx(WINHANDLE(pio), NULL);
/* If io is pending, let write worker threads exit. The read thread is blocked so terminate it.*/
if (pio->read_details.pending)
TerminateThread(pio->read_overlapped.hEvent, 0);
if (pio->read_details.pending)
TerminateThread(pio->read_overlapped.hEvent, 0);
if (pio->write_details.pending)
WaitForSingleObject(pio->write_overlapped.hEvent, INFINITE);
/* drain queued APCs */
SleepEx(0, TRUE);
if (pio->type != STD_IO_FD) {//STD handles are never explicitly closed
if (pio->type != STD_IO_FD) {
/* STD handles are never explicitly closed */
CloseHandle(WINHANDLE(pio));
if (pio->read_details.buf)
free(pio->read_details.buf);
if (pio->write_details.buf)
free(pio->write_details.buf);
free(pio);
}
return 0;

File diff suppressed because it is too large Load Diff

View File

@ -1,10 +1,11 @@
/*
* Author: Microsoft Corp.
*
* Copyright (c) 2015 Microsoft Corp.
* Copyright (c) 2017 Microsoft Corp.
* All rights reserved
*
* Microsoft openssh win32 port
* This file is responsible for terminal emulation related network calls to
* invoke ANSI parsing engine.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -27,61 +28,51 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* tnnet.c
*
* Contains terminal emulation related network calls to invoke ANSI parsing engine
*
*/
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <windows.h>
#include "ansiprsr.h"
#define dwBuffer 4096
// Server will always be returning a sequence of ANSI control characters which the client
// protocol can either passthru directly to the console or transform based on an output terminal
// type. We're not using termcap so we're only supporting the ANSI (vt100) sequences that
// are hardcoded in the server and will be transformed to Windows Console commands.
size_t telProcessNetwork(char *buf, size_t len, unsigned char **respbuf, size_t *resplen)
{
/*
* Server will always be returning a sequence of ANSI control characters which the client
* protocol can either passthru directly to the console or transform based on an output terminal
* type. We're not using termcap so we're only supporting the ANSI (vt100) sequences that
* are hardcoded in the server and will be transformed to Windows Console commands.
*/
size_t
telProcessNetwork(char *buf, size_t len, unsigned char **respbuf, size_t *resplen) {
unsigned char szBuffer[dwBuffer + 8];
unsigned char* pszNewHead = NULL;
unsigned char* pszHead = NULL;
unsigned char* pszTail = NULL;
unsigned char* pszHead = NULL;
unsigned char* pszTail = NULL;
if (len == 0)
return len;
if (len == 0)
return len;
// Transform a single carriage return into a single linefeed before
// continuing.
/* Transform a single carriage return into a single linefeed before continuing */
if ((len == 1) && (buf[0] == 13))
buf[0] = 10;
pszTail = (unsigned char *)buf;
pszHead = (unsigned char *)buf;
pszTail += len;
pszNewHead = pszHead;
// Loop through the network buffer transforming characters as necessary.
// The buffer will be empty after the transformation
// process since the buffer will contain only commands that are handled by the console API.
/*
* Loop through the network buffer transforming characters as necessary.
* The buffer will be empty after the transformation
* process since the buffer will contain only commands that are handled by the console API.
*/
do {
pszHead = pszNewHead;
pszNewHead = ParseBuffer(pszHead, pszTail, respbuf, resplen);
} while ((pszNewHead != pszHead) && (pszNewHead < pszTail) && (resplen == NULL || (resplen != NULL && *resplen == 0)));
len = 0;
len = 0;
return len;
}