bvterm 2.xx Protocol Specification ============================================================================== This document is Copyright (C) 2010 by Bitvise Limited. Last updated: 2010-10-19 This document and the information contained herein are provided on an "AS IS" basis. BITVISE LIMITED DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. ============================================================================== The purpose of the bvterm terminal protocol is to provide a quality Windows terminal experience that cannot be achieved with other well established terminal protocols such as xterm. On Windows, character based applications receive keyboard input and render their output in a Windows Console. bvterm 2.xx is based on the Windows Console API; it may even loosely be viewed as a Windows Console API remote procedure call specification. The current protocol version is 2.0. As of the time of this writing, bvterm 2.xx is supported by Bitvise WinSSHD 5.xx, and Tunnelier 4.25 or newer. Older versions of WinSSHD and Tunnelier supported bvterm versions 1.xx. Bitvise considers these versions obsolete for new implementations, and recommends implementation of bvterm 2.0 as described herein. bvterm is intended for integration with SSH. Most of the bvterm protocol requires only a reliable communication channel supporting an 8-bit binary stream in both directions. However, an external mechanism such as SSH channel requests is needed for initial negotiation. Packet format: byte[3] packet-size (little-endian, not counting the size field itself) byte packet-type Types used in packet definitions: bool = byte boolean-value (zero = false, non-zero = true) word16 = byte[2] value (little-endian) word32 = byte[4] value (little-endian) charinfo = word16 unicode-char word16 attribute (Windows Console attribute) Implementations must ignore packets of unrecognized types. When packets contain superfluous data beyond recognized fields, such superfluous data must also be ignored. Server-to-client packets ======================== The client must be able to accept packets with a size of up to 409600 bytes. byte BVT_BEEP = 6 word32 frequency word32 duration Sent by the server to have the client generate a tone on the PC speaker. For more information, please lookup Beep() in MSDN. The BVT_BEEP packet has been adopted from bvterm 1.2. byte BVT_MESSAGE_BEEP = 7 word32 type Sent by the server to have the client play a waveform sound. For more information, please lookup MessageBeep() in MSDN. The BVT_MESSAGE_BEEP packet has been adopted from bvterm 1.2. byte BVT_VERSION = 8 byte version Sent by the server to enable the bvterm version chosen by the server. The server can choose one of the bvterm versions that the client has requested in the "bvterm-req" channel request. Please see the "Integrating bvterm with SSH2" section for more information. The most significant 4 bits of the version byte represent the major version, while the less significant 4 bits represent the minor bvterm version. For example, 2.0 is encoded as 0x20. This packet can only be sent as the first - initial packet. The client must ignore any BVT_VERSION packets received at a different point. Clients implementing older bvterm versions must assume bvterm version 1.1 if the first packet sent by the server is not BVT_VERSION. Clients implementing only bvterm 2.xx must report an error and close the channel if the first packet received is not BVT_VERSION, or if the version byte is less than 0x20. The BVT_VERSION packet has been adopted from bvterm 1.2. byte BVT_SET_TEXT_ATTRIBUTE = 9 word16 attribute Sent by the server to set a current text attribute on the client. The current text attribute value affects the BVT_SET_BUFFER_SIZE packet only. The server should set it before sending any BVT_SET_BUFFER_SIZE packets. For more information, please lookup SetConsoleTextAttribute() in MSDN. byte BVT_SET_BUFFER_SIZE = 10 word16 columns word16 rows Sent by the server to set a new screen buffer size on the client. If the screen buffer is enlarged in any way, then the client must fill the new cells with space characters (' ') and the current text attribute. The server should have previously set the current text attribute with BVT_SET_TEXT_ATTRIBUTE. If the server has failed to set a current text attribute, the client should assume the default text attribute of a newly opened Windows Command prompt - gray text, without intensity, on a black background. For more information, please lookup SetConsoleScreenBufferSize() in MSDN. byte BVT_SCROLL_BUFFER = 11 word16 scroll-left word16 scroll-top word16 scroll-right word16 scroll-bottom word16 clip-left word16 clip-top word16 clip-right word16 clip-bottom word16 dest-column word16 dest-row charinfo fill-character bool fill-double-width Sent by the server to scroll screen buffer on the client. Fill-double-width is true if fill-character on the server occupies two columns in width. According to the MSDN's IsDBCSLeadByteEx() documentation, only the following Windows Console code pages are capable of displaying double-width characters: 932 (Japanese Shift-JIS) 936 (Simplified Chinese GBK) 949 (Korean Unified Hangul Code) 950 (Traditional Chinese Big5) 1361 (Korean Johab) The Tunnelier bvterm client outputs to a Windows console, and will replace fill-character with '?' if fill-double-width is true and the client's console code page is not one of the above. For more information about other fields, please lookup ScrollConsoleScreenBuffer() in MSDN. byte BVT_SET_CURSOR_POS = 12 word16 column word16 row Sent by the server to set a cursor position on the client. For more information, please lookup SetConsoleCursorPos() in MSDN. byte BVT_SET_CURSOR_INFO = 13 word32 size bool visible Sent by the server to set cursor settings on the client. For more information, please lookup SetConsoleCursorInfo() in MSDN. byte BVT_SET_WINDOW_INFO = 14 word32 window-info-magic bool absolute word16 left word16 top word16 right word16 bottom Sent by the server to set a window size and position on the client. For information about window-info-magic, please see BVT_WINDOW_SIZE_NOTIFY. For more information about other fields, please lookup SetConsoleWindowInfo() in MSDN. byte BVT_WRITE_OUTPUT_CHARACTER = 15 word32 character-count word16 unicode-character[character-count] word32 double-width-count byte double-width[double-width-count] word16 column word16 row Sent by the server to print characters to the client's screen buffer. Double-width array is a bit vector for the unicode-character array. If a particular unicode-character on the server occupies two columns in width, then its associated double-width bit will be set. Double-width array may hold less bits than there are unicode-characters, in which case the missing double-width bytes are assumed to be 0x00. Accordingly, the server may completely omit the double-width array (double-width-count set to 0) if there are no double width characters present in the packet. In a two byte 0x06 0x01 double-width array, the 2nd, 3rd, and 9th character are double width. For more information, please lookup WriteConsoleOutputCharacter() in MSDN. byte BVT_WRITE_OUTPUT_ATTRIBUTE = 16 word32 attribute-count word16 attribute[attribute-count] word16 column word16 row Sent by the server to apply attributes to the client's screen buffer. For more information, please lookup WriteConsoleOutputAttribute() in MSDN. byte BVT_FILL_OUTPUT_CHARACTER = 17 word16 unicode-character bool double-width word32 length word16 column word16 row Sent by the server to fill the client's screen buffer with the requested character. Double-width is true if unicode-character on the server occupies two columns in width. For more information about other fields, please lookup FillConsoleOutputCharacter() in MSDN. byte BVT_FILL_OUTPUT_ATTRIBUTE = 18 word16 attribute word32 length word16 column word16 row Sent by the server to fill the client's screen buffer with the requested attribute. For more information, please lookup WriteConsoleOutputAttribute() in MSDN. byte BVT_WRITE_OUTPUT = 19 word32 character-count charinfo character[output-count] word16 left word16 top word16 right word16 bottom Sent by the server to both print characters and apply attributes to the client's screen buffer. For more information, please lookup WriteConsoleOutput() in MSDN. Note that the character array may hold single width characters only. byte BVT_FILL_OUTPUT = 20 charinfo character word16 left word16 top word16 right word16 bottom Sent by the server to fill the client's screen buffer with the requested character and attribute. For more information, please lookup FillConsoleOutput() in MSDN. Note that the character array may hold single width characters only. Client-to-server packets ======================== The server must accept packets with a size of up to 4096 bytes. byte BVT_KEY = 128 bool key-down byte repeat-count word16 virtual-key-code word16 unicode-character word32 control-key-state Sent by the client to describe a keyboard event that has taken place. For more information, please lookup KEY_EVENT_RECORD in MSDN. Note that the virtual-key-scan field is omitted because it is device-dependent. The BVT_KEY packet has been adopted from bvterm 1.0. byte BVT_BUFFER_SIZE_REQEST = 129 word16 columns word16 rows Sent by the client to request a resize of the buffer. The client must not resize the buffer on its own, but must wait for server to respond with a BVT_SET_BUFFER_SIZE packet. The BVT_BUFFER_SIZE_NOTIFY packet has been adopted from bvterm 1.0. byte BVT_WINDOW_SIZE_NOTIFY = 130 word32 last-window-info-magic word16 columns-minus-1 word16 rows-minus-1 Sent by the client to notify a resize of the viewing area. No response is to be sent back by the server. Last-window-info-magic must be set to the last window-info-magic received with BVT_SET_WINDOW_INFO. If such a packet has not yet been received, then last-window-info-magic must be set to 0. The server should ignore BVT_WINDOW_SIZE_NOTIFY packets where last-window-info-magic does not match the last windows-info-magic sent in BVT_SET_WINDOW_INFO. Due to behavior of early bvterm implementations, the columns and rows sent in this packet are subtracted by 1. The client sends: columns = actual-columns - 1 And the server interprets: actual-columns = columns + 1 The BVT_WINDOW_SIZE_NOTIFY packet has been adopted from bvterm 1.0. byte BVT_SIGNAL = 131 byte ctrl-event Sent by the client to describe a console CTRL event that has taken place. Ctrl-event can be either CTRL_C_EVENT (= 0) or CTRL_BREAK_EVENT (= 1). The BVT_SIGNAL packet has been adopted from bvterm 1.1. Integrating bvterm with SSH2 ============================ Integration of bvterm 2.xx with SSH2 has been adopted from bvterm 1.xx. At any point after establishing an SSH session, the client begins a bvterm session by opening a "session" channel, setting up the terminal, and sending a "shell" channel request. Instead of preceding the "shell" channel request with "pty-req", the client must precede it with a "bvterm-req" channel request: byte SSH_MSG_CHANNEL_REQUEST uint32 recipient_channel string "bvterm-req" boolean want_reply uint32 initial-buffer-width (e.g. 80) uint32 initial-buffer-height (e.g. 100) uint32 initial-window-width (e.g. 80) uint32 initial-window-height (e.g. 25) string versions-requested (e.g. "\x20") If the client wants to find out whether the server supports bvterm, the client should send "bvterm-req" with want_reply == TRUE. If the server responds with SSH_MSG_CHANNEL_SUCCESS, then the server supports bvterm and the client can now safely submit a "shell" channel request. If the server responds with SSH_MSG_CHANNEL_FAILURE, then the server doesn't support bvterm and the client should either abort, or revert to another type of terminal by sending a "pty-req" channel request before "shell". The versions-requested field is optional for older bvterm implementations, and was added in bvterm 1.2. A client implementing bvterm 2.xx, but not older bvterm versions, must not omit this field. A client supporting bvterm 1.2 or newer should use this field to list the bvterm versions that it supports, in order from most to least desirable. The server, implementing bvterm 1.2 or newer, must then pick the first bvterm version from the list that it supports. If this field is missing, "\x11\x10" is assumed. Each byte in the versions requested string represents a bvterm version. The more significant 4 bits of that byte represents the major version, while the less significant 4 bits represents the minor bvterm version. For example, 2.0 followed by 1.2 and 1.1 is encoded as "\x20\x12\x11". If the client submits "bvterm-req" as well as "pty-req", or if the client submits multiple "bvterm-req" packets, the server must act according to the last of these packets received before the "shell" request. On compatibility of channel request name with SSH specification =============================================================== We understand that the SSH specification calls for naming private extensions using a name@domain syntax. On this topic, bvterm authors are in disagreement with the SSH specification. We believe that: - Names without appendages are easy to choose in a way that is sufficiently unique, and "bvterm-req" is sufficiently unique. - The @domain syntax hinders changing status of a name from private to registered. If an extension becomes standardized and receives an un-appendaged name, all implementations must be modified to recognize the new name, even if behavior is identical. The channel request name "bvterm-req" has been used by our implementations without issue for nearly a decade. At this point, we believe that defining an alternative appendaged alias would not serve any goal except a principle, and would add confusion. We request that new implementations continue to use the channel request name "bvterm-req" exclusively. Version history =============== 2010-10-15: First published. 2010-10-19: Added discussion of channel request name, and Version History.