/*********************************************************/ /* ptycon: a pty-console bridge */ /* Copyright (C) 2016--2017 SysDeer Technologies, LLC */ /* Released under GPLv2 and GPLv3; see COPYING.PTYCON. */ /*********************************************************/ #include #include #include #include #include #include "ptycon_driver_impl.h" #include "ptycon_status_impl.h" int __stdcall ptyc_console_ctrl(uint32_t); int __stdcall ptyc_console_reader(void *); int __stdcall ptyc_console_writer(void *);; int __stdcall ptyc_console_poller(void *); int __stdcall ptyc_dbg_cat(struct ptyc_driver_ctx *); int __stdcall ptyc_dbg_event(void *); int __stdcall ptyc_dbg_oven(void *); int __stdcall ptyc_dbg_raw(void *); struct ptyc_loop_thread_ctx { nt_thread_start_routine * entry; struct ptyc_driver_ctx_impl * ictx; }; static int __stdcall ptyc_loop_thread_entry(void * ctx) { struct ptyc_loop_thread_ctx * xctx; xctx = (struct ptyc_loop_thread_ctx *)ctx; return ntapi->zw_terminate_thread( NT_CURRENT_THREAD_HANDLE, xctx->entry(xctx->ictx)); } static int ptyc_create_loop_thread( nt_thread_params * params, struct ptyc_driver_ctx_impl * ictx, nt_thread_start_routine * entry) { struct ptyc_loop_thread_ctx xctx; xctx.entry = entry; xctx.ictx = ictx; /* rapunzel rapunzel */ params->hprocess = NT_CURRENT_PROCESS_HANDLE; params->start = ptyc_loop_thread_entry; params->ext_ctx = &xctx; params->ext_ctx_size = sizeof(xctx); params->stack_size_commit = 64 * 1024; params->stack_size_reserve = 64 * 1024; params->creation_flags = NT_CREATE_LOCAL_THREAD; return ntapi->tt_create_thread( params); } static int ptyc_free_console_impl( struct ptyc_driver_ctx_impl * ictx, int32_t status) { struct ptyc_term_ctx * tctx; struct ptyc_loop_ctx * lctx; tctx = &ictx->tctx; lctx = &ictx->lctx; if (tctx->hin) ntcon->free_console(); if (lctx->treader.hthread) ntapi->zw_close(lctx->treader.hthread); if (lctx->twriter.hthread) ntapi->zw_close(lctx->twriter.hthread); if (lctx->tpoller.hthread) ntapi->zw_close(lctx->tpoller.hthread); if (lctx->tdbgevent.hthread) ntapi->zw_close(lctx->tdbgevent.hthread); if (lctx->tdbgoven.hthread) ntapi->zw_close(lctx->tdbgoven.hthread); if (lctx->tdbgraw.hthread) ntapi->zw_close(lctx->tdbgraw.hthread); return status; } static int ptyc_init_console(struct ptyc_term_ctx * tctx) { /* console input buffer) */ if (!(tctx->hin = ntcon->get_std_handle(NT_STD_INPUT_HANDLE))) return NT_STATUS_UNSUCCESSFUL; /* console screen buffer */ if (!(tctx->hout = ntcon->create_console_screen_buffer( NT_GENERIC_READ | NT_GENERIC_WRITE, 0,0,NT_CONSOLE_TEXTMODE_BUFFER,0))) return NT_STATUS_UNSUCCESSFUL; if (!(ntcon->set_console_screen_buffer_size( tctx->hout, tctx->screen_size))) return NT_STATUS_UNSUCCESSFUL; if (!(ntcon->set_console_active_screen_buffer(tctx->hout))) return NT_STATUS_UNSUCCESSFUL; /* console text attributes: default colors */ if (!(ntcon->set_console_text_attribute( tctx->hout, NT_BACKGROUND_BLACK | NT_FOREGROUND_WHITE))) return NT_STATUS_UNSUCCESSFUL; /* console code page: utf-8 */ if (!(ntcon->set_console_code_page(65001))) return NT_STATUS_NOT_SUPPORTED; if (!(ntcon->set_console_output_code_page(65001))) return NT_STATUS_NOT_SUPPORTED; /* input events */ if (!(ntcon->set_console_mode( tctx->hin, NT_ENABLE_MOUSE_INPUT | NT_ENABLE_WINDOW_INPUT))) return NT_STATUS_UNSUCCESSFUL; /* ctrl events */ if (!(ntcon->set_console_ctrl_handler( ptyc_console_ctrl, true))) return NT_STATUS_UNSUCCESSFUL; /* cursor info */ if (!(ntcon->get_console_cursor_info( tctx->hout, &tctx->cursor_info))) return NT_STATUS_UNSUCCESSFUL; return NT_STATUS_SUCCESS; } int ptyc_alloc_console(struct ptyc_driver_ctx * dctx) { int32_t status; struct ptyc_driver_ctx_impl * ictx; struct ptyc_term_ctx * tctx; struct ptyc_loop_ctx * lctx; if (!(ictx = ptyc_get_driver_ictx(dctx))) return NT_STATUS_INVALID_HANDLE; tctx = &ictx->tctx; lctx = &ictx->lctx; tctx->screen_size.x = 512; tctx->screen_size.y = 4096; tctx->drvflags = ictx->cctx.drvflags; if (!(ntcon->alloc_console())) return NT_STATUS_UNSUCCESSFUL; if ((status = ptyc_init_console(tctx))) return ptyc_set_status(dctx,status); if ((status = ptyc_create_loop_thread( &lctx->treader, ictx,ptyc_console_reader))) return ptyc_set_status(dctx,status); if ((status = ptyc_create_loop_thread( &lctx->twriter, ictx,ptyc_console_writer))) return ptyc_set_status(dctx,status); if ((status = ptyc_create_loop_thread( &lctx->tpoller, ictx,ptyc_console_poller))) return ptyc_set_status(dctx,status); if (dctx->cctx->drvflags & PTYC_DRIVER_DBG_EVENT) if ((status = ptyc_create_loop_thread( &lctx->tdbgevent, ictx,ptyc_dbg_event))) return ptyc_set_status(dctx,status); if (dctx->cctx->drvflags & PTYC_DRIVER_DBG_OVEN) if ((status = ptyc_create_loop_thread( &lctx->tdbgoven, ictx,ptyc_dbg_oven))) return ptyc_set_status(dctx,status); if (dctx->cctx->drvflags & PTYC_DRIVER_DBG_RAW) if ((status = ptyc_create_loop_thread( &lctx->tdbgraw, ictx,ptyc_dbg_raw))) return ptyc_set_status(dctx,status); if ((status = ptyc_dbg_cat(dctx))) return ptyc_set_status(dctx,status); return ptyc_set_status(dctx,NT_STATUS_SUCCESS); } int ptyc_wait_for_console(struct ptyc_driver_ctx * dctx) { struct ptyc_driver_ctx_impl * ictx; if (!(ictx = ptyc_get_driver_ictx(dctx))) return NT_STATUS_INVALID_HANDLE; return ntapi->zw_wait_for_single_object( ictx->lctx.tpoller.hthread, NT_SYNC_ALERTABLE,0); } void ptyc_free_console(struct ptyc_driver_ctx * dctx) { struct ptyc_driver_ctx_impl * ictx; if (!(ictx = ptyc_get_driver_ictx(dctx))) return; ptyc_free_console_impl(ictx,NT_STATUS_SUCCESS); }