agent.
* The code is based on that from AgentClient.cc, but without the Qt
dependency.
* The API currently uses blocking I/O. The intent is for users to use
a separate read thread and write thread.
The intent is to avoid a problem on Windows XP. On that OS, sending
a "Select All" command to freeze one console window also interrupts any
"window activity" (e.g. moving/closing/scrolling/right-clicking/...) on
all other console windows.
My hope is that putting the console into a special window station will
isolate it enough to avoid this problem. I noticed that the problem didn't
happen when I ran the TestNetServer as a service, which ran both the
TestNetServer and Agent processes with a special window station.
Note that even though the Agent runs in a special window station, the shell
and its children run in the normal window station.
has started a shell.
I thought this change would fix a problem with the Windows 8 Preview where
the connection shut down immediately after starting. It did not fix the
problem, which I still don't have an explanation for, but in any case, I
think the change is necessary.
* Add a note on how to use instsrv and srvany.
* First look for Agent.exe in the same directory as TestNetServer.exe
before looking for the executable in the build directory that Qt
Creator uses.
* Write a script that copies MinGW/Qt DLLs to a single directory.
The Mark command moves the cursor to the top-left, which interferes with
lynx, a full-screen Cygwin web browser, and probably other programs.
The Select All command also puts the console into selection mode, blocking
console output.
upward.
This commit gets the CMD/PowerShell CLS command working with the Agent.
Previously, the CLS command was broken in the following test case:
- User opens a window of height N and types CLS. The window now looks
like:
line0)
line1) D:\rprichard\Scrape\TestNetServer-build-desktop>
- User generates a bunch of output -- enough to scroll the window but not
enough to create a sync marker.
- User types CLS again.
- The window scrolls back to the top and is cleared.
- The agent thinks that lines [1..(N-1]] of the window (and screen buffer)
have changed. It omits line 0 because line 0 is blank before and after
the CLS. Therefore, it sends N-1 lines. The first line is at line 1.
We've already output a "remote line" larger than N, though, so we first
try to CursorUp by >>N lines.
- After moving the cursor up, we're actually on line 0 of the terminal
instead of line 1.
I think the general rule is that it's safe to "reset the terminal," but we
want to avoid resetting because it breaks history. For typical
command-line sessions that don't involve full-screen programs, (but which
*could* involve window resizing), I would like the history to be perfect.
and avoid sending lines in the window that aren't dirty yet.
The idea is that the bottom of the console screen commonly has blank lines
that do not need to be sent to the client, because nothing has been written
there yet. For example, when the console first appears, there is typically
a command-line prompt at the top of the window. When a console is expanded
vertically, blank lines commonly appear at the bottom.
Other misc changes to the output:
- When we send one later, also send all following lines.
- When we save a line into m_bufferData, fill in the rest of the line with
spaces. This way, it's possible to expand the console horizontally
without the agent resending all the lines.
- If nothing on the console has changed, then leave the cursor alone.
Don't hide, show, or move it.
* If the client was unable to write any data, write would return -1 with
errno==EAGAIN, and the client would assert fail.
* Apparently I thought that continue would jump to the start of the
do-while(0) loop. Replace the continue/do-while(0) with a
did_something flag.
While I'm at it, replace a few hard-coded constants with constants.
- On each polling, identify a range of lines to scan. This range will
include lines in the history if output has scrolled.
- Line in scrapeOutput and the terminal output routines (e.g.
sendLineToTerminal) are numbered as if writing to an infinitely-sized
terminal.
- Once history is large enough, write a string to column 1 ~200 lines
up. This synchronizing marker lets us know how much the console output
has scrolled.
- Freeze the console output by putting the console into select/mark mode.
Unfreeze it by sending an ESC keypress.
* The TestNet protocol starts with a terminal resize escape sequence, so
the server discards all input until it sees the sequence, and it delays
starting the agent. Eventually, the goal is to implement an SSH server,
and the SSH message that creates a PTY also provides the terminal size.
handled.
Use the UnixSignalHandler to detect terminal resizing. The client doesn't
do anything with the terminal size yet. It should send the size to the
server.
* Use disconnected() instead of readChannelFinished().
* Cleanup. There are three bidirectional pipes conceptually:
console <-> agent
agent <-> server
server <-> client
If one end of a pipe dies, start closing the other end, then clean up.
If the console dies (e.g. because cmd.exe exits), we still want to
collect the final console output and send it to the client.
To help with this, in the Agent, I call GetConsoleProcessList, then
scrapeOutput, then (potentially) disconnectFromServer.
- Add a very incomplete "telnet" server. It doesn't recognize any telnet
commands, so it's "telnet" only in the sense that I can connect to the
server and type commands. The commands are fed to a Win32 Console, but
I don't get to see the output over the network.
- Move AgentClient to the Shared directory and move QtEvent-specific code
out of it.
- Move the startShell routine into the AgentClient so I can share it
between the different console-consuming prototypes.