void console_init() { _consoleInitialised = true; console_writeline(OPENRCT2_NAME " " OPENRCT2_VERSION); console_writeline(""); console_write_prompt(); }
/* * Process a request to print one or more strings */ DWORD remote_request_core_console_write(Remote *remote, Packet *packet) { DWORD res = ERROR_NOT_FOUND; DWORD index; Tlv tlv; console_write_output("\n"); do { for (index = 0; packet_enum_tlv(packet, index, TLV_TYPE_STRING, &tlv) == ERROR_SUCCESS; index++) console_write_output("%s", (PCHAR)tlv.buffer); res = ERROR_SUCCESS; } while (0); fflush(stdout); console_write_prompt(); return res; }
/* * File upload open completion handler for when a channel for a given file has * been opened */ DWORD file_upload_open_complete(Remote *remote, Channel *channel, LPVOID context, DWORD result) { FileUploadContext *ctx = (FileUploadContext *)context; DWORD res = ERROR_SUCCESS; BOOL textPrinted = TRUE; do { // If the result was not successful, no sense in continuing if ((!channel) || (result != ERROR_SUCCESS)) { console_write_output( "\n" INBOUND_PREFIX " FS: file_upload_open failed, result %lu.\n", result); res = result; break; } // Try to open the local source file if (!(ctx->fd = fopen(ctx->source, "rb"))) { console_write_output( "\n" "Error: Local file '%s' could not be opened for reading.\n", ctx->source); res = ERROR_FILE_NOT_FOUND; break; } textPrinted = FALSE; res = file_upload_write_complete(remote, channel, context, result, 1); } while (0); // If the result was not successful, clean up the context here if (res != ERROR_SUCCESS) { // Close the channel if it's valid if (channel) channel_close(channel, remote, NULL, 0, NULL); // Deallocate the passed in context if (ctx->fd) fclose(ctx->fd); free(ctx); } if (textPrinted) console_write_prompt(); return res; }
/* * Extension callback for printing out notifications for channels opening */ DWORD ex_remote_response_core_channel_open(Remote *remote, Packet *packet) { DWORD channelId = packet_get_tlv_value_uint(packet, TLV_TYPE_CHANNEL_ID); if (channelId) { console_write_output( "\n" INBOUND_PREFIX " CHANNEL: New remote channel allocated: %lu.\n", channelId); console_write_prompt(); } return ERROR_SUCCESS; }
/* * Generic output of success/fail */ DWORD console_generic_response_output(Remote *remote, Packet *packet, LPCSTR subsys, LPCSTR cmd) { DWORD res = packet_get_result(packet); if (res == ERROR_SUCCESS) console_write_output( "\n" INBOUND_PREFIX " %s: %s succeeded.\n", subsys, cmd); else console_write_output( "\n" INBOUND_PREFIX " %s: %s failed, result %lu.\n", subsys, cmd, packet_get_result(packet)); console_write_prompt(); return res; }
/* * Process console commands in a loop * * I would use the scheduler but allowing the file descriptor to drop * into non-blocking mode makes things annoying. */ VOID console_process_commands(Remote *remote) { SOCKET fd = remote_get_fd(remote); struct timeval tv; fd_set fdread; LONG r; console_write_prompt(); // Execute the scheduler in a loop while (1) { FD_ZERO(&fdread); FD_SET(fd, &fdread); tv.tv_sec = 0; tv.tv_usec = 100; if ((r = select(fd + 1, &fdread, NULL, NULL, &tv)) > 0) { LONG bytes = 0; ioctlsocket(fd, FIONREAD, &bytes); if (bytes == 0) { console_write_output( "\n" "Connection reset by peer.\n"); break; } command_process_remote(remote, NULL); } else if (r < 0) break; scheduler_run(remote, 0); } }
void console_input(int c) { switch (c) { case SDL_SCANCODE_ESCAPE: console_clear_input(); console_refresh_caret(); break; case SDL_SCANCODE_RETURN: if (_consoleCurrentLine[0] != 0) { console_history_add(_consoleCurrentLine); console_execute(_consoleCurrentLine); console_write_prompt(); console_clear_input(); console_refresh_caret(); } break; case SDL_SCANCODE_UP: if (_consoleHistoryIndex > 0) { _consoleHistoryIndex--; memcpy(_consoleCurrentLine, _consoleHistory[_consoleHistoryIndex], 256); } gTextInputCursorPosition = strlen(_consoleCurrentLine); gTextInputLength = gTextInputCursorPosition; break; case SDL_SCANCODE_DOWN: if (_consoleHistoryIndex < _consoleHistoryCount - 1) { _consoleHistoryIndex++; memcpy(_consoleCurrentLine, _consoleHistory[_consoleHistoryIndex], 256); gTextInputCursorPosition = strlen(_consoleCurrentLine); gTextInputLength = gTextInputCursorPosition; } else { _consoleHistoryIndex = _consoleHistoryCount; console_clear_input(); } break; } }
/* * Channel write complete handler for writing data to the remote endpoint * during a file upload. */ DWORD file_upload_write_complete(Remote *remote, Channel *channel, LPVOID context, DWORD result, ULONG bytesWritten) { FileUploadContext *ctx = (FileUploadContext *)context; ChannelCompletionRoutine complete; DWORD res = ERROR_SUCCESS; BOOL textPrinted = TRUE; CHAR buffer[8192]; LONG bytesRead; do { // If the result was not successful, no sense in continuing if ((!channel) || (result != ERROR_SUCCESS)) { console_write_output( "\n" INBOUND_PREFIX " FS: file_upload_write failed, result %lu.\n", result); res = result; break; } // Try to read more data from the local file bytesRead = fread(buffer, 1, sizeof(buffer), ctx->fd); // If there are no more bytes in the file, send a channel close // notification. if (bytesRead <= 0) { console_write_output( "\n" INBOUND_PREFIX " FS: Upload to '%s' completed.\n", ctx->source); channel_close(channel, remote, NULL, 0, NULL); break; } textPrinted = FALSE; // Keep writing to the channel until it's done with memset(&complete, 0, sizeof(complete)); complete.context = (LPVOID)ctx; complete.routine.write = file_upload_write_complete; // Write the buffer to the wire res = channel_write(channel, remote, NULL, 0, (PUCHAR)buffer, bytesRead, &complete); } while (0); // If the result was not successful, clean up the context here if (result != ERROR_SUCCESS) { if (channel) channel_close(channel, remote, NULL, 0, NULL); // Deallocate the passed in context if (ctx->fd) fclose(ctx->fd); free(ctx); } if (textPrinted) console_write_prompt(); return res; }
/* * Download completion routine for a read request. */ DWORD file_download_read_complete(Remote *remote, Channel *channel, LPVOID context, DWORD result, PUCHAR buffer, ULONG bytesRead) { ChannelCompletionRoutine complete; FileDownloadContext *ctx = (FileDownloadContext *)context; DWORD bytesWritten; BOOL textPrinted = TRUE; DWORD res = ERROR_SUCCESS; BOOL cleanup = FALSE; do { // If the result was not successful, no sense in continuing if ((!channel) || (result != ERROR_SUCCESS)) { console_write_output( "\n" INBOUND_PREFIX " FS: file_download_read failed, result %lu.\n", result); res = result; break; } // Were no bytes read from the remote endpoint? if (!bytesRead) { console_write_output( "\n" INBOUND_PREFIX " FS: Download to '%s' completed.\n", ctx->target); cleanup = TRUE; break; } // Try to read more data from the local file if ((bytesWritten = fwrite(buffer, 1, bytesRead, ctx->fd)) <= 0) { res = GetLastError(); console_write_output( "\n" INBOUND_PREFIX " FS: fwrite failed, result %lu.\n", res); break; } textPrinted = FALSE; // Initialize the completion context for reading memset(&complete, 0, sizeof(complete)); complete.context = ctx; complete.routine.read = file_download_read_complete; // Read from the remote file res = channel_read(channel, remote, NULL, 0, 8192, &complete); } while (0); if (res != ERROR_SUCCESS) cleanup = TRUE; // If the clean up flag is set, close the channel and close the fd if (cleanup) { if (channel) channel_close(channel, remote, NULL, 0, NULL); // Free the context on error if (ctx->fd) fclose(ctx->fd); free(ctx); } // If text was displayed, show the console prompt if (textPrinted) console_write_prompt(); return res; }
/* * File download open completion handler for when a channel for a given file has * been opened and is ready to be read from. */ DWORD file_download_open_complete(Remote *remote, Channel *channel, LPVOID context, DWORD result) { ChannelCompletionRoutine complete; FileDownloadContext *ctx = (FileDownloadContext *)context; DWORD res = ERROR_SUCCESS; BOOL textPrinted = TRUE; do { // If the result was not successful, no sense in continuing if ((!channel) || (result != ERROR_SUCCESS)) { console_write_output( "\n" INBOUND_PREFIX " FS: file_download_open failed, result %lu.\n", result); res = result; break; } // Try to open the local target file for writing if (!(ctx->fd = fopen(ctx->target, "wb"))) { console_write_output( "\n" "Error: Local file '%s' could not be opened for writing.\n", ctx->target); res = ERROR_FILE_NOT_FOUND; break; } textPrinted = FALSE; // Initialize the completion context for reading memset(&complete, 0, sizeof(complete)); complete.context = ctx; complete.routine.read = file_download_read_complete; // Read from the remote file res = channel_read(channel, remote, NULL, 0, 8192, &complete); } while (0); // If the result was not successful, clean up the context here if (res != ERROR_SUCCESS) { // Close the channel if it's valid if (channel) channel_close(channel, remote, NULL, 0, NULL); // Free the context on error if (ctx->fd) fclose(ctx->fd); free(ctx); } if (textPrinted) console_write_prompt(); return res; }
/* * Reads in data from the input device, potentially calling the * command processing function if a complete command has been read. */ VOID console_read_buffer(Remote *remote) { DWORD newInputBufferLength, stringLength, offset; Channel *interactiveChannel; PCHAR newInputBuffer; BOOL process = FALSE; CHAR buf[4096]; PCHAR eoln, eolr; LONG bytesRead; // Ensure null termination buf[sizeof(buf) - 1] = 0; do { // Is there data available? if (WaitForSingleObject(GetStdHandle(STD_INPUT_HANDLE), INFINITE) != WAIT_OBJECT_0) break; // If a console escape character was sent and we're currently interactive, // break out of interactive mode if ((console_check_escape_sent()) && (console_get_interactive_channel())) { console_set_interactive_channel(remote, NULL); console_write_output( "\n" "\n" "Exiting interactive mode..\n"); console_write_prompt(); } // Read the command if ((!ReadConsole(GetStdHandle(STD_INPUT_HANDLE), buf, sizeof(buf) - 1, &bytesRead, NULL)) || (bytesRead <= 0)) break; buf[bytesRead] = 0; // If an interactive channel is in use, write directly to it. if ((interactiveChannel = console_get_interactive_channel())) { channel_write(interactiveChannel, remote, NULL, 0, buf, bytesRead, NULL); break; } if ((eoln = strchr(buf, '\n'))) { *eoln = 0; process = TRUE; } // Remove end of line characters if ((eolr = strchr(buf, '\r'))) *eolr = 0; // Calculate lengths stringLength = strlen(buf); newInputBufferLength = inputBufferLength + stringLength; if (inputBuffer) newInputBuffer = (PCHAR)realloc(inputBuffer, newInputBufferLength); else newInputBuffer = (PCHAR)malloc(++newInputBufferLength); // Allocation failure? if (!newInputBuffer) break; if ((offset = inputBufferLength)) offset--; // Copy the string memcpy(newInputBuffer + offset, buf, stringLength); // Update the input buffer inputBuffer = newInputBuffer; inputBufferLength = newInputBufferLength; // Process the full command line if it's completed if (process) { inputBuffer[inputBufferLength - 1] = 0; client_acquire_lock(); console_process_command(remote); client_release_lock(); free(inputBuffer); inputBuffer = NULL; inputBufferLength = 0; console_write_prompt(); } } while (0); }