How to detect xterm resize in-band - linux

I'm looking for a way to get resize events on an xterm as an alternative to the winch signal. I need to get a signal for the xterm resize that is remote compatible, that is, could be used over a serial line/telnet/ssh/whatever. The winch signal is only for local machine tasks.
I know that vi/curses can do this because I have tried ssh and use vi to edit a file, and it responds to resizing of the window.

So after a bit of research, it does seem there is no in-band method for this. I don't think it would be difficult to add. You have two sides to a connection, ssh, serial or whatever, let's say A and B where A is on the host and B is the remote. To get behavior equivalent to a local windowed task, I would say at least two things are essential:
Mouse movement/button messaging.
Window resize messaging.
The second, can be a two step process. If the B task gets an alert that the window size has changed, it can use in band queries to determine what the new size is, using the (perhaps infamous) method of setting the cursor to the end of an impossibly large screen and then reading the actual location of the cursor that results, then restoring the location, all done with standard in-band controls.
Why care about in-band vs. out of band? Well, nobody cares now :-), but serial lines used to be quite popular, and in-band, that is, actual escape sequences sent down the line are going to work, but telnet or ssh "out of band" communication is not.
It would not be difficult to add, a local program that shims the ssh or telnet, or even xterm itself, can get the winch message and change that to an escape alert to the B side. Here the mouse messaging is instructive. The messages consist of two actions:
The B side must enable such messages, so that the A side won't send unknown escapes to it.
The A side must have an escape to signify winch.
Thus a new escape from B to A, and one from A to B.
I'm actually fairly satisfied with winch. What was wanted is to have the same capabilities as vi/curses (based on my observation). This kind of support is already far better than Windows, which (as far as I know) implements none of this remote side support.

Related

Telnet: How to remove NULL (0x00) after every CR (0x0d) on send, using char mode (interactive mode)?

I am using my open source Serial-to-IP converter (Serial Network Interface, SNI) to communicate with headless Slackware server using ttyS0 console. SNI during connection sends back to Telnet command set ff fb 01 ff fb 03. This turns Telnet from Line mode to Char mode. But i notice that Telnet replaces (adds) my CR press (0x0d) to two chars 0x0d 0x00. The Slackware's TTY itself is immune to this, but some commands i run under it, at least cat and mcedit, are not. So i try to do the following:
Insert filter in my SNI so it just throw away NULLs at direction IP->Serial. It works, but it quite ugly, because no binary transfer will be allowed anymore.
Modify Telnet's source code to remove addind NULL to CR:
inetutils-1.9.4/telnet/telnet.c from line 2294:
case '\r':
if (!crlf)
{
NETADD ('\r'); <-- added
// NET2ADD ('\r', '\0'); <-- removed
}
else
{
NET2ADD ('\r', '\n');
}
bol = flushline = 1;
break;
It also work, so i ensure i am on the right way catching the problem.
But it is also ugly due to multiple reasons, include that it is quite not portable, and obligate me to have my own non-standard telnet binary.
So the question is: It is possible to command to Telnet not to modify my CRs? (looking at this source code piece, it is not possible at all with original code, but i am sure i miss something, and this should be possible without modify source code). Note: Replace 0x0d to 0x0d, 0x0a (this is present in code) will not work with Linux TTY: it interprets this as two CRs.
And sub-question is: Where is 0x0d+0x00 used at all? I do not know any hardware device, teletype machine, etc., and any TTY, where NULL after CR used, at all. Thanks.
So i take some investigation to see how this should be solved correctly, in terms of not to abuse the software, and to find the correct tools, or clearly show there are no such tools currently.
First of all, i show why my setup is exactly as it is, and why it uses (or not uses) standard tools.
My goal is very common and essential to Linux world (as i think before). Because Linux is network operating system, Linux box should be fully configurable via network (so can/should be fully useful when headless, i.e. without display monitor). But at time when Lilo/Grub starts, there is no network. Only serial ports are able at this time (and Lilo/Grub supports it). Why it is important to remote control at this time? Just because you can (remotely) compile new custom kernel for your Slackware box, and want to test it, adding as 2nd option in Lilo list, and want to return to original kernel even when remote machine stuck when booting, so no way to remotely edit/agjust Lilo options.
But serial console is really much more powerful tool for Linux machine.
It shows boot messages and shut down messages which impossible to see via ssh, due to network is not initialized at these moments. (And remember, we do not have display).
It lets you to (suddenly or intentionally) drop all network interfaces without a fear to lost your machine, when it is many miles from you.
Note: Serial console will not work out-of-box, but can be configured in quite well known standard ways, and described in many places. Example is http://docs.slackware.com/howtos:general_admin:serial_console
Note: There is problem that serial port should be BIOS-recognized, i.e., fully onboard. USB and PCIE devices will never work at stage when Lilo/Grub boots. Fortunately there is a good news. Hardware serial ports now (slowly) return to motherboards. I test new modern Asus J1900I-C for my server, it have two rs232 ports, and it all work fine.
To use serial console benefits remotely, some sort of SNI, Serial Network Interface, should be used (and it is the only way, AFAIK). SNI typically contains (simplest possible) TCP listening server, and raw IP-to-serial duplex translator. I start study and using SNIs when Lantronix X-Port was invented. It was in 2006, and was working fine with Slackware box. (I can't remember if there was \r\0 problems or not with XPort, but let's continue). XPort was too expensive, and was replaced with my own open source SNI immediately when Wiznet W5100 was issued. (Really, there is other, essential problem, why i need to replace Lantronix. It can't press Reset or Power buttons on motherboard, while my device can, and now server is absolutely under full remote control even after kernel panic; but it is offtopic here). Also nowadays there are many cheap no-named SNIs at online shops; i do not test these.
All these times i was using telnet to connect to SNI. The main reason was that XPort docs have examples of that. And, most times it working; i can't say that \r\0 problem stops my work. Most times it is not noticeable at all (say, mc commander is resistent to NULL 's). But mcedit fear the NULLs. And recently i start to catch the problem, so this question arrives as an result.
(now please re-read from begin of thread).
And now i try to answer to my own question. All these times i was misuse the software. Telnet was not written for human communication; instead, Telnet (suddenly) use Telnet protocol, not Raw protocol; and \r\0s are probably part of protocol. (probably, because RFC says nothing about requirement of NULLs anywhere).
While Telnet and Raw protocols may looks quite close, they are not match, so sometimes should work but sometimes not.
Using bruteforce and recompiling binary, i show that Telnet can be very easily turned to Raw mode; but it is non-standard software after that, and there is no chance that it can be pushed to worldwide repos.
So i search for Raw utilites.
netcat and ncat are not have Char mode, only Line mode, so only pure console possible, no ANSI colors, mc, passwords, etc. Putty is too complex and uses GUI. And... No more utilites i found! This was quite strange and annoying...
Then i try to use initially character-based terminals, minicom and gtkterm. They are both do not allow feed ip:port structure istead of ttyS* name. But there is data translators exist, i try socat. It connects to SNI server and creates virtual serial port; then character terminal software connects to that port.
And that, finally, work. Whoa.
But very many disadvantages in this chain; complex, hard to remember commands, can't be written in one line; when SNI drops TCP connection, it is impossible to see/catch that; a LOT of garbage issued by socat into virtual port at connection time (457 packets i count!). Here are the commands for brave people who may find my work useful.
sudo socat pty,link=/dev/ttyMYPORT,raw tcp:10.1.1.11:10001 &
then
sudo chmod a+rw /dev/ttyMYPORT; gtkterm -p /dev/ttyMYPORT
or
sudo chmod a+rw /dev/ttyMYPORT; minicom -o --color=on -D /dev/ttyMYPORT
And conclusion, i do not found any simple software nowadays, that can be directly used to communicate in human raw character mode with serial port via network bridge. (Please suggest something). Thanks.
I believe the solution you are looking for is a few lines higher:
if (!crlf)
If we set crlf = true, then we would get \r\n instead of \r\0. That's probably going to work for cat and friends.
Looking through the telnet source, it appears crlf is some sort of "toggle" option. Looking an man telnet and a bit of Googling, it appears you can run something like this:
$ telnet
telnet> toggle crlf
...and you'll get \r\n sent from then on.

How do I "dump" the contents of an X terminal programmatically a la /dev/vcs{,a} in the Linux console?

Linux's kernel-level console/non-X terminal emulator contains a very cool feature (if compiled in): each /dev/ttyN device corresponds with /dev/vcsaN and /dev/vcsN devices which represent the in-memory (displayed) state of that tty, with and without attributes (color, flashing, etc) respectively. This allows you to very easily cat /dev/vcs7 and see a dump of /dev/tty7 wherever cat was launched. I used this incredibly practical capability the other day to login to a system via SSH and remotely watch a dd process I'd forgotten to put inside a screen (or similar) session - it was running off a text console, so I took a few moments to finetune the character ranges that I wanted to grab, and presently I was watching dd's transfer status over SSH (once every second, incidentally).
To reiterate and clarify, /dev/vcs{,a}* are character devices that retrieve the current in-memory representation the kernel console VT100 emulator, represented as a single "line" of text (there are no "newlines" at the end of each "line" of the screen). Just to remove confusion, I want to note that I can't tail -f this device: it's not a character stream like the TTY itself is. (But I've never needed this kind of behavior, for what it's worth.)
I've kept my ears perked for many years for a method to dump the character-cell memory state of X terminal emulators - or indeed any arbitrary process that needs to work with ttys, in some similar manner as I can with the Linux console. And... I am rather surprised that there is no practical solution to this problem - since it has, arguably, existed for approximately 30 years - X was introduced in 1984 - or, to be pedantic, at least 19 years - /dev/vcs{,a}* was introduced in kernel 1.1.94; the newest file in that release is dated 22 Feb 1995. (The oldest is from 1st Dec 1993 :P)
I would like to say that I do understand and realize that the tty itself is not a "screen buffer" as such but a character stream, and that the nonstandard feature I essentially exploited above is a quirky capability specific to the Linux VT102 emulator. However, this feature is cool enough (why else would it be in the mainline tree? :D) that, in my opinion, there should be a counterpart to it for things that work with /dev/pts*.
This afternoon, I needed to screen-scrape the output of an interactive ncurses application so I could extract metadata from the information it presented in my terminal. (There was no other practical way to achieve the goal I was aiming for.) Linux' kernel VT100 driver would permit such a task to be completed very easily, and I made the mistake of thinking that it, in light of this, it couldn't truly be that hard to do the same under X11.
By 9AM, I'd decided that the easiest way to experimentally request a dump of a remote screen would be to run it in dtach (think "screen -x" without any other options) and hack the dtach code to request a screen update and quit.
Around 11AM-12PM, I was requesting screen updates and dumping them to stdout.
Around 3:30PM, I accepted that using dtach would be impossible:
First of all, it relies on the application itself to send the screen redraws on request, by design, to keep the code simple. This is great, but, as luck would have it, the application I was using didn't support whole-screen repaints - it would only redraw on screen-size change (and only if the screen size was truly different!).
Running the program inside a screen session (because screen is a true terminal emulator and has an internal 2D character-cell buffer), then running screen -x inside dtach, also mysteriously failed to produce character cell updates.
I have previously examined screen and found the code sufficiently insane enough to remove any inclinations I might otherwise have to hack on it; all I can say is that said insanity may be one of the reasons screen does not already have the capabilities I have presented here (which would arguably be very easy to implement).
Other questions similar to this one frequently get answers to use typescript, or script; I just want to clarify that script saves the stream of the tty itself to a file, which I would need to push through a VT100 emulator to obtain a screen image of the current state of the tty in question. In other words, script would be a very insane solution to my problem.
I'm not marking this as accepted since it doesn't solve the actual core issue (which is many years old), but I was able to achieve the specific goal I set out to do.
My specific requirements were that I wanted to screen-scrape the output of the ncdu interactive disk usage browser, so I could simply press Enter in another terminal (or perform some similar, easy sequence) to add the directory currently highlighted/selected in ncdu to a file-list of files I wanted to work with.My goal was not to have to distract myself with endless copy+paste and/or retyping of directory names (probably with not a few inaccuracies to boot), so I could focus on the directories I wanted to select.
screen has a refresh feature, accessed by pressing (by default) CTRL+A, CTRL+L. I extended my copy of dtach to be capable of sending keystrokes in addition to dumping remote screens to stdout, and wrapped dtach in a script that transmitted the refresh sequence (\001\014) to screen -x running inside dtach. This worked perfectly, retrieving complete screen updates without any flicker.
I will warn anyone interested in trying this technique, however, that you will need to perfect the art of dodging VT100 escape sequences. I used regular expressions for this so I wasn't writing thousands of lines of code; here's the specific part of the script that extracted out the two pieces of information I needed:
sh -c "(sleep 0.1; dtach -k qq $'\001\014') &"; path="$(dtach -d qq -t 130000 | sed -n $'/^\033\[7m.*\/\.\./q;/---.*$/{s/.*--- //;s/ -\+.*//;h};/^\033\[7m/{s/.\033.*//g;s/\r.*//g;s/ *$//g;s/^\033\[7m *[^ ]\+ \[[# ]*\] *\(\/*\)\(.*\)$/\/\\2\\1/;p;g;p;q}' | sed 'N;s/\(.*\)\n\(.*\)/\2\1/')"
Since screenshots are cool and help people visualize things, here's a look at how it works when it's running:
The file shown inverted at the bottom of the ncdu-scrape window is being screen-scraped from the ncdu window itself; the four files in the list are there because I selected them using the arrow keys in ncdu, moved my mouse over to the ncdu-scrape window (I use focus-follows-mouse), and pressed Enter. That added the file to the list (a simple text file itself).
Having said this, I would like to clarify that the regular expression above is not a code sample to run with; it is, rather, a warning: for anything beyond incredibly trivial (!!) content extractions such as the one presented here, you're basically getting into the same territory as large corporations/interests who want to convert from VT100-based systems to something more modern, who have to spend tends of thousands commissioning large translation frameworks that perform the kind of conversion outlined above on an especially large scale.
Saner solutions appreciated.

How RealVNC works?

I would to know how RealVNC remote viewer works.
It frequently send screenshots to the client in real time ?
or does it use other approach ?
As a very high-level overview, there are two types of VNC servers:
Screen-grabbing. These servers will capture the current display into a buffer, compare it to the client state, and send only the rectangles that differ to the client.
Hook-assisted. Hooking into the display update process, these servers will be informed when the screen changes by the display manager or OS. They can then use that information to send only the changed rectangles to the client.
In both cases, it is effectively a stream of screen updates; however, only the changed regions of the screen are transmitted to the client. Depending on the version of the VNC protocol in use, these updates may be compressed as well.
(Note that the client is free to request a complete screen update any time it wants to, but the server will only do this on its own if the entire screen is changed.)
Also, screen updates are not the only things transmitted. There are separate channels that the server can use to send clipboard updates and mouse position updates (since a user physically at the remote machine may be able to move the mouse too).
The display side of the protocol is
based around a single graphics
primitive: “put a rectangle of pixel
data at a given x,y position”. At
first glance this might seem an
inefficient way of drawing many user
interface components. However,
allowing various different encodings
for the pixel data gives us a large
degree of flexibility in how to trade
off various parameters such as network
bandwidth, client drawing speed and
server processing speed. A sequence of
these rectangles makes a framebuffer
update (or simply update). An update
represents a change from one valid
framebuffer state to another, so in
some ways is similar to a frame of
video. The rectangles in an update are
usually disjoint but this is not
necessarily the case.
Read here to find out more how it works
Yes. It just sends some sort of screenshots (compressed and which reuses unchanged portions of the previous screenshot).
This is by the way the VNC protocol, any client work that way (although the actual way to compress images etc etc may change).
Essentially the server sends Frame Buffer Updates to the client and the client sends keyboard and mouse input and frame buffer update requests to the server.
Frame Buffer Update messages can have different encodings, but in essence they are different ways of representing square screen areas of pixel data. Generally the client asks for Frame Buffer Updates for the entire screen but it can ask for just an area of the screen (for example, small screen clients showing a viewport of the servers screen). The server then sends a FBU (frame buffer update) that contains rectangles where the screen has changed since the last FBU was sent to the client.
The best reference for the RFB/VNC protocol is here. The IETF has a recent (2011) standards document RFC 6143 that covers RFB although it is not an extensive as the reference guide.
It essentially works by sending screenshots on the fly. ("Real time" is something of a misnomer here in that there is no clear deadline.) It does attempt to optimize by only sending areas of the screen that have changed, and some forks of the VNC code line use a mirror driver to receive notification when areas of the display are written to, while others use window message hooks to detect repaint requests.

detect automatic key-repeats in curses

I'm writing a little text mode application using curses on Linux.
For keyboard input I use the curses functions. Key auto-repeats work, e.g. if I hold a key down I get multiple key events until I release the key again.
Is it also possible to distinguish between real key events and those generated by the key repeat logic?
Background: The application is a little data-entry front-end where the user can modify integer numbers of certain parameters. In the long run the application will work without a standard keyboard. I will only have four buttons for data-entry: 'increase', 'decrease', 'ok' and 'cancel'.
Since the number ranges are large I'd like to know if the user holds down a key. If he does so I can scan faster through my numeric range by not incrementing my number by one but by 10 or maybe 100. If the user otoh taps the key the input method should be precise again and just increase/decrease the numbers by one.
Is this possible with the keyboard input functions of curses?
No - curses just receives keys from the terminal. If you really need it you could try to find out if the key repeats are automated or not by looking at the delay between each keypress. However, especially over remote connections, this might not be a good solution as the delay will be affected by network latency.
The best solution might be using UP/DOWN for small steps and PAGEUP/PAGEDOWN for large steps.

Serial port determinism

This seems like a simple question, but it is difficult to search for. I need to interface with a device over the serial port. In the event my program (or another) does not finish writing a command to the device, how do I ensure the next run of the program can successfully send a command?
Example:
The foo program runs and begins writing "A_VERY_LONG_COMMAND"
The user terminates the program, but the program has only written, "A_VERY"
The user runs the program again, and the command is resent. Except, the device sees "A_VERYA_VERY_LONG_COMMAND," which isn't what we want.
Is there any way to make this more deterministic? Serial port programming feels very out-of-control due to issues like this.
The required method depends on the device.
Serial ports have additional control signal lines as well as the serial data line; perhaps one of them will reset the device's input. I've never done serial port programming but I think ioctl() handles this.
There may be a single byte which will reset, e.g. some control character.
There might be a timing-based signal, e.g. Hayes command set modems use “pause +++ pause”.
It might just reset after not receiving a complete command after a fixed time.
It might be useful to know whether the device was originally intended to support interactive use (serial terminal), control by a program, or both.
I would guess that if you call write("A_VERY_LONG_COMMAND"), and then the user hits Ctrl+C while the bytes are going out on the line, the driver layer should finish sending the full buffer. And if the user interrupts in the middle of the call, the driver layer will probably just ignore the whole thing.
Just in case, when you open a new COM port, it's always wise to clear the port.
Do you have control over the device end? It might make sense to implement a timeout to make the device ignore unfinished or otherwise corrupt packets.
The embedded device should be implemented such that you can either send an abort/clear/break character that will dump the contents of its command buffer and give you a clean slate on your client app startup.
Or else it should provide a software reset character which will reset the command buffer and all state.
Or else it so be designed so that you can send a command termination (perhaps a newline, etc, depending on command protocol) and possibly have an error generated on the parsing of a garbled partial command that was in its buffer, query/clear the error, and then be good to go.
It wouldn't be a bad idea upon connection of your client program to send some health/status/error query repeatedly until you get a sound response, and only then commence sending configuration or operation commands. Unless you can via a query determine that the device was left in a suitable state, you probably want to assume nothing and configure it from scratch, after a configuration reset if available.

Resources