mirror of
https://github.com/PowerShell/Win32-OpenSSH.git
synced 2025-09-21 17:18:40 +02:00
Term IO implemented to support Vista and Win7
This commit is contained in:
parent
fb93bb95e2
commit
a8fcb8d673
@ -43,6 +43,9 @@
|
||||
#define WRITE_BUFFER_SIZE 100*1024
|
||||
#define errno_from_Win32LastError() errno_from_Win32Error(GetLastError())
|
||||
|
||||
int termio_initiate_read(struct w32_io* pio);
|
||||
int termio_initiate_write(struct w32_io* pio, DWORD num_bytes);
|
||||
|
||||
/* maps Win32 error to errno */
|
||||
int
|
||||
errno_from_Win32Error(int win32_error)
|
||||
@ -344,6 +347,11 @@ fileio_read(struct w32_io* pio, void *dst, unsigned int max) {
|
||||
}
|
||||
|
||||
if (fileio_is_io_available(pio, TRUE) == FALSE) {
|
||||
if (FILETYPE(pio) == FILE_TYPE_CHAR) {
|
||||
if (-1 == termio_initiate_read(pio))
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
if (-1 == fileio_ReadFileEx(pio)) {
|
||||
if ((FILETYPE(pio) == FILE_TYPE_PIPE)
|
||||
&& (errno == ERROR_NEGATIVE_SEEK)) {
|
||||
@ -354,6 +362,7 @@ fileio_read(struct w32_io* pio, void *dst, unsigned int max) {
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* pick up APC if IO has completed */
|
||||
if (-1 == wait_for_any_event(NULL, 0, 0))
|
||||
@ -461,6 +470,15 @@ fileio_write(struct w32_io* pio, const void *buf, unsigned int max) {
|
||||
bytes_copied = min(max, pio->write_details.buf_size);
|
||||
memcpy(pio->write_details.buf, buf, bytes_copied);
|
||||
|
||||
if (FILETYPE(pio) == FILE_TYPE_CHAR) {
|
||||
if (termio_initiate_write(pio, bytes_copied) == 0) {
|
||||
pio->write_details.pending = TRUE;
|
||||
pio->write_details.remaining = bytes_copied;
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
if (WriteFileEx(WINHANDLE(pio), pio->write_details.buf, bytes_copied,
|
||||
&pio->write_overlapped, &WriteCompletionRoutine)) {
|
||||
pio->write_details.pending = TRUE;
|
||||
@ -468,6 +486,18 @@ fileio_write(struct w32_io* pio, const void *buf, unsigned int max) {
|
||||
/* execute APC if write has completed */
|
||||
if (wait_for_any_event(NULL, 0, 0) == -1)
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
errno = errno_from_Win32LastError();
|
||||
/* read end of the pipe closed ? */
|
||||
if ((FILETYPE(pio) == FILE_TYPE_PIPE) && (errno == ERROR_NEGATIVE_SEEK)) {
|
||||
debug("write - ERROR:read end of the pipe closed, io:%p", pio);
|
||||
errno = EPIPE;
|
||||
}
|
||||
debug("write ERROR from cb(2):%d, io:%p", errno, pio);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (w32_io_is_blocking(pio)) {
|
||||
while (pio->write_details.pending) {
|
||||
@ -483,17 +513,6 @@ fileio_write(struct w32_io* pio, const void *buf, unsigned int max) {
|
||||
}
|
||||
debug2("write - reporting %d bytes written, io:%p", bytes_copied, pio);
|
||||
return bytes_copied;
|
||||
}
|
||||
else {
|
||||
errno = errno_from_Win32LastError();
|
||||
/* read end of the pipe closed ? */
|
||||
if ((FILETYPE(pio) == FILE_TYPE_PIPE) && (errno == ERROR_NEGATIVE_SEEK)) {
|
||||
debug("write - ERROR:read end of the pipe closed, io:%p", pio);
|
||||
errno = EPIPE;
|
||||
}
|
||||
debug("write ERROR from cb(2):%d, io:%p", errno, pio);
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -577,6 +596,9 @@ fileio_on_select(struct w32_io* pio, BOOL rd) {
|
||||
return 0;
|
||||
|
||||
if (!pio->read_details.pending && !fileio_is_io_available(pio, rd))
|
||||
if (FILETYPE(pio) == FILE_TYPE_CHAR)
|
||||
return termio_initiate_read(pio);
|
||||
else
|
||||
return fileio_ReadFileEx(pio);
|
||||
|
||||
return 0;
|
||||
|
@ -3,10 +3,9 @@
|
||||
#include "inc/defs.h"
|
||||
|
||||
#define TERM_IO_BUF_SIZE 2048
|
||||
int errno_from_Win32Error(int win32_error);
|
||||
|
||||
struct io_status {
|
||||
char* buf[TERM_IO_BUF_SIZE];
|
||||
DWORD to_transfer;
|
||||
DWORD transferred;
|
||||
DWORD error;
|
||||
};
|
||||
@ -17,79 +16,137 @@ 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);
|
||||
pio->read_details.error = read_status.error;
|
||||
pio->read_details.remaining = read_status.transferred;
|
||||
pio->read_details.completed = 0;
|
||||
pio->read_details.pending = FALSE;
|
||||
WaitForSingleObject(pio->read_overlapped.hEvent, INFINITE);
|
||||
CloseHandle(pio->read_overlapped.hEvent);
|
||||
pio->read_overlapped.hEvent = 0;
|
||||
}
|
||||
|
||||
static DWORD WINAPI ReadThread(
|
||||
_In_ LPVOID lpParameter
|
||||
) {
|
||||
struct w32_io* pio = (struct w32_io*)lpParameter;
|
||||
debug3("TermRead thread, io:%p", pio);
|
||||
memset(&read_status, 0, sizeof(read_status));
|
||||
if (!ReadFile(WINHANDLE(pio), read_status.buf, TERM_IO_BUF_SIZE, &read_status.transferred, NULL)) {
|
||||
if (!ReadFile(WINHANDLE(pio), pio->read_details.buf,
|
||||
pio->read_details.buf_size, &read_status.transferred, NULL)) {
|
||||
read_status.error = GetLastError();
|
||||
debug("TermRead thread - ReadFile failed %d, io:%p", GetLastError(), pio);
|
||||
}
|
||||
|
||||
if (0 == QueueUserAPC(ReadAPCProc, main_thread, pio))
|
||||
if (0 == QueueUserAPC(ReadAPCProc, main_thread, (ULONG_PTR)pio)) {
|
||||
debug("TermRead thread - ERROR QueueUserAPC failed %d, io:%p", GetLastError(), pio);
|
||||
DebugBreak();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
int
|
||||
termio_initiate_read(struct w32_io* pio) {
|
||||
HANDLE read_thread = CreateThread(NULL, 0, ReadThread, pio, 0, NULL);
|
||||
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) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
pio->read_details.buf_size = TERM_IO_BUF_SIZE;
|
||||
}
|
||||
|
||||
read_thread = CreateThread(NULL, 0, ReadThread, pio, 0, NULL);
|
||||
if (read_thread == NULL) {
|
||||
errno = errno_from_Win32Error(GetLastError());
|
||||
debug("TermRead initiate - ERROR CreateThread %d, io:%p", GetLastError(), pio);
|
||||
return -1;
|
||||
}
|
||||
|
||||
pio->read_overlapped.hEvent = read_thread;
|
||||
pio->read_details.pending = TRUE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
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*/
|
||||
pio->write_details.completed = 0;
|
||||
pio->write_details.pending = FALSE;
|
||||
WaitForSingleObject(pio->write_overlapped.hEvent, INFINITE);
|
||||
CloseHandle(pio->write_overlapped.hEvent);
|
||||
pio->write_overlapped.hEvent = 0;
|
||||
}
|
||||
|
||||
static DWORD WINAPI WriteThread(
|
||||
_In_ LPVOID lpParameter
|
||||
) {
|
||||
struct w32_io* pio = (struct w32_io*)lpParameter;
|
||||
debug3("TermWrite thread, io:%p", pio);
|
||||
if (!WriteFile(WINHANDLE(pio), pio->write_details.buf, write_status.to_transfer,
|
||||
&write_status.transferred, NULL)) {
|
||||
write_status.error = GetLastError();
|
||||
debug("TermWrite thread - ReadFile failed %d, io:%p", GetLastError(), pio);
|
||||
}
|
||||
|
||||
if (0 == QueueUserAPC(WriteAPCProc, main_thread, (ULONG_PTR)pio)) {
|
||||
debug("TermWrite thread - ERROR QueueUserAPC failed %d, io:%p", GetLastError(), pio);
|
||||
DebugBreak();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
termio_on_select(struct w32_io* pio, BOOL rd) {
|
||||
if (!rd)
|
||||
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;
|
||||
write_thread = CreateThread(NULL, 0, WriteThread, pio, 0, NULL);
|
||||
if (write_thread == NULL) {
|
||||
errno = errno_from_Win32Error(GetLastError());
|
||||
debug("TermWrite initiate - ERROR CreateThread %d, io:%p", GetLastError(), pio);
|
||||
return -1;
|
||||
}
|
||||
|
||||
pio->write_overlapped.hEvent = write_thread;
|
||||
return 0;
|
||||
|
||||
if ((!fileio_is_io_available(pio, rd)) && (!pio->read_details.pending))
|
||||
return termio_initiate_read(pio);
|
||||
}
|
||||
|
||||
int
|
||||
termio_read(struct w32_io* pio, void *dst, unsigned int max) {
|
||||
return fileio_read(pio, dst, max);
|
||||
}
|
||||
|
||||
int
|
||||
termio_write(struct w32_io* pio, const void *buf, unsigned int max) {
|
||||
//{
|
||||
// /* assert that io is in blocking mode */
|
||||
// if (w32_io_is_blocking(pio) == FALSE) {
|
||||
// debug("write - ERROR, nonblocking write to term is not supported");
|
||||
// errno = ENOTSUP;
|
||||
// return -1;
|
||||
// }
|
||||
// pio->write_details.remaining = bytes_copied;
|
||||
// if (!WriteFile(h, buf, bytes_copied, &pio->write_details.completed, NULL))
|
||||
// pio->write_details.error = GetLastError();
|
||||
// else if (bytes_copied != pio->write_details.completed)
|
||||
// pio->write_details.error = ERROR_INTERNAL_ERROR;
|
||||
|
||||
// if (pio->write_details.error != 0) {
|
||||
// debug("write - ERROR writing to term %d", pio->write_details.error);
|
||||
// errno = errno_from_Win32Error(pio->write_details.error);
|
||||
// return -1;
|
||||
// }
|
||||
// else {
|
||||
// pio->write_details.completed = 0;
|
||||
// return bytes_copied;
|
||||
// }
|
||||
|
||||
//}
|
||||
return fileio_write(pio, buf, max);
|
||||
}
|
||||
|
||||
int termio_close(struct w32_io* pio) {
|
||||
return fileio_close(pio);
|
||||
debug2("termio_close - pio:%p", pio);
|
||||
|
||||
CancelIoEx(WINHANDLE(pio), NULL);
|
||||
/* If io is pending, let worker threads exit*/
|
||||
if (pio->read_details.pending)
|
||||
WaitForSingleObject(pio->read_overlapped.hEvent, INFINITE);
|
||||
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
|
||||
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;
|
||||
}
|
@ -123,7 +123,7 @@ w32posix_initialize() {
|
||||
if ((fd_table_initialize() != 0)
|
||||
|| (socketio_initialize() != 0))
|
||||
DebugBreak();
|
||||
main_thread = GetCurrentThread();
|
||||
main_thread = OpenThread(THREAD_SET_CONTEXT, FALSE, GetCurrentThreadId());
|
||||
signalio_initialize();
|
||||
}
|
||||
|
||||
@ -156,14 +156,9 @@ w32_io_on_select(struct w32_io* pio, BOOL rd)
|
||||
{
|
||||
if ((pio->type == SOCK_FD))
|
||||
return socketio_on_select(pio, rd);
|
||||
else
|
||||
switch (FILETYPE(pio)) {
|
||||
case FILE_TYPE_CHAR:
|
||||
return termio_on_select(pio, rd);
|
||||
default:
|
||||
|
||||
return fileio_on_select(pio, rd);
|
||||
}
|
||||
}
|
||||
|
||||
#define CHECK_FD(fd) do { \
|
||||
debug3("%s fd:%d", __FUNCTION__, fd); \
|
||||
@ -371,14 +366,9 @@ w32_read(int fd, void *dst, unsigned int max) {
|
||||
|
||||
if (fd_table.w32_ios[fd]->type == SOCK_FD)
|
||||
return socketio_recv(fd_table.w32_ios[fd], dst, max, 0);
|
||||
else
|
||||
switch (FILETYPE(fd_table.w32_ios[fd])) {
|
||||
case FILE_TYPE_CHAR:
|
||||
return termio_read(fd_table.w32_ios[fd], dst, max);
|
||||
default:
|
||||
|
||||
return fileio_read(fd_table.w32_ios[fd], dst, max);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
w32_write(int fd, const void *buf, unsigned int max) {
|
||||
@ -386,14 +376,9 @@ w32_write(int fd, const void *buf, unsigned int max) {
|
||||
|
||||
if (fd_table.w32_ios[fd]->type == SOCK_FD)
|
||||
return socketio_send(fd_table.w32_ios[fd], buf, max, 0);
|
||||
else
|
||||
switch (FILETYPE(fd_table.w32_ios[fd])) {
|
||||
case FILE_TYPE_CHAR:
|
||||
return termio_write(fd_table.w32_ios[fd], buf, max);
|
||||
default:
|
||||
|
||||
return fileio_write(fd_table.w32_ios[fd], buf, max);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
w32_fstat(int fd, struct w32_stat *buf) {
|
||||
|
@ -119,9 +119,6 @@ long fileio_lseek(struct w32_io* pio, long offset, int origin);
|
||||
FILE* fileio_fdopen(struct w32_io* pio, const char *mode);
|
||||
|
||||
/* terminal io specific versions */
|
||||
int termio_on_select(struct w32_io* pio, BOOL rd);
|
||||
int termio_read(struct w32_io* pio, void *dst, unsigned int max);
|
||||
int termio_write(struct w32_io* pio, const void *buf, unsigned int max);
|
||||
int termio_close(struct w32_io* pio);
|
||||
|
||||
/* signal related APIs*/
|
||||
|
Loading…
x
Reference in New Issue
Block a user