MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame^] | 1 | CONCEPT |
| 2 | Telnet Negotiations |
| 3 | |
| 4 | DESCRIPTION |
| 5 | The telnet protocol is used to control textbased connections |
| 6 | between a client (the 'telnet' program or a mud client) and a |
| 7 | server (the game driver). Most of the options offered by the |
| 8 | protocol are optional and need to be negotiated between the |
| 9 | client and the server. Consequently, and due to their |
| 10 | specialized nature, mud clients don't have to support the full |
| 11 | telnet option feature set. |
| 12 | |
| 13 | For the server to find out if a client supports the telnet |
| 14 | protocol at all, one good approach is to a simple, commonly |
| 15 | used telnet command to the client. If the client reacts |
| 16 | conform to the protocol (or sends telnet commands itself), the |
| 17 | mud can continue to negotiate further options. If the client |
| 18 | does not react, the mud can safely refrain from further |
| 19 | negotiations. |
| 20 | |
| 21 | The following list is a more or less comprehensive overview of |
| 22 | the telnet related RFCs (available for example on |
| 23 | http://www.faqs.org/rfcs): |
| 24 | |
| 25 | RFC Titel rel. Code |
| 26 | |
| 27 | 495 TELNET Protocol Specification |
| 28 | 513 Comments on the new TELNET specifications |
| 29 | 559 Comments on the new TELNET Protocol and its Implem |
| 30 | 595 Some Thoughts in Defense of the TELNET Go-Ahead |
| 31 | 596 Second Thoughts on Telnet Go-Ahead |
| 32 | 652 Telnet Output Carriage-Return Disposition Option NAOCRD 10 |
| 33 | 653 Telnet Output Horizontal Tabstops Option NAOHTS 11 |
| 34 | 654 Telnet Output Horizontal Tab Disposition Option NAOHTD 12 |
| 35 | 655 Telnet Output Formfeed Disposition Option NAOFFD 13 |
| 36 | 656 Telnet Output Vertical Tabstops Option NAOVTS 14 |
| 37 | 657 Telnet Output Vertical Tab Disposition Option NAOVTD 15 |
| 38 | 658 Telnet Output Linefeed Disposition NAOLFD 16 |
| 39 | 698 Telnet Extended Ascii Option X-ASCII 17 |
| 40 | 727 Telnet Logout Option LOGOUT 18 |
| 41 | 728 A Minor Pitfall in the Telnet Protocol |
| 42 | 735 Revised TELNET Byte Macro Option BM 19 |
| 43 | 749 Telnet SUPDUP-OUTPUT Option SUPDUP 22 |
| 44 | 764 Telnet Protocol Specification |
| 45 | 779 Telnet SEND-LOCATION Option SENDLOC 23 |
| 46 | 818 The Remote User Telnet Service |
| 47 | 854 Telnet Protocol Specification |
| 48 | 855 Telnet Option Specifications |
| 49 | 856 Telnet Binary Transmission BINARY 0 |
| 50 | 857 Telnet Echo Option ECHO 1 |
| 51 | 858 Telnet Suppress Go Ahead Option SGA 3 |
| 52 | 859 Telnet Status Option STATUS 5 |
| 53 | 860 Telnet Timing Mark Option TM 6 |
| 54 | 861 Telnet Extended Options - List Option EXOPL 255 |
| 55 | 884 Telnet Terminal Type Option TTYPE 24 |
| 56 | 885 Telnet End of Record Option EOR 25 |
| 57 | 930 Telnet Terminal Type Option TTYPE 24 |
| 58 | 933 Output Marking Telnet Option OUTMRK 27 |
| 59 | 946 Telnet Terminal Location Number Option TTYLOC 28 |
| 60 | 1043 Telnet Data Entry Terminal Option DODIIS Implement DET 20 |
| 61 | 1053 Telnet X.3 PAD Option X.3-PAD 30 |
| 62 | 1073 Telnet Window Size Option NAWS 31 |
| 63 | 1079 Telnet Terminal Speed Option TSPEED 32 |
| 64 | 1080 Telnet Remote Flow Control Option FLOWCTRL 33 |
| 65 | 1091 Telnet Terminal-Type Option TTYPE 24 |
| 66 | 1096 Telnet X Display Location Option XDISPLOC 35 |
| 67 | 1116 Telnet Linemode Option LINEMODE 34 |
| 68 | 1143 The Q Method of Implementing TELNET Option Negotia |
| 69 | 1184 Telnet Linemode Option LINEMODE 34 |
| 70 | 1372 Telnet Remote Flow Control Option FLOWCTRL 33 |
| 71 | 1408 Telnet Environment Option ENVIRON 36 |
| 72 | 1571 Telnet Environment Option Interoperability Issues |
| 73 | 1572 Telnet Environment Option NEWENV 39 |
| 74 | 2066 Telnet Charset Option CHARSET 42 |
| 75 | 2217 Telnet Com Port Control Option COMPORT 44 |
| 76 | 2877 5250 Telnet Enhancements |
| 77 | |
| 78 | All negotiations start with the special character IAC which is |
| 79 | defined in /usr/include/arpa/telnet.h (or in |
| 80 | src/driver/telnet.h for 3.2(.1)) and has the decimal value of |
| 81 | 255. Negotiations are based on different telnetoptions (their |
| 82 | values are defined in telnet.h too). Before a negotiation can |
| 83 | start the client and the server have to agree that they |
| 84 | support the option. |
| 85 | This works in the following way: |
| 86 | |
| 87 | If a client wants to send something to the server it has to |
| 88 | send 'IAC WILL option' (For terminaltype negotation this would |
| 89 | be the 3 bytes 255,251,24; again, check telnet.h) to confirm |
| 90 | that it is able to do that. If the server is supporting that |
| 91 | option and wants to receive something it sends 'IAC DO option' |
| 92 | (255,253,option) |
| 93 | |
| 94 | If one side is receiving an 'IAC WILL option' and has not yet |
| 95 | sent with DO or DONT it has to respond with either 'IAC DO |
| 96 | option' if it will support this negotiation or 'IAC DONT |
| 97 | option' if it won't. |
| 98 | |
| 99 | If one side is receiving an 'IAC DO option' and has not yet |
| 100 | sent a WILL or WONT it has to reply with either 'IAC WILL |
| 101 | option' if it supports the option or 'IAC WONT option' if not. |
| 102 | |
| 103 | A small example: Lets assume we want to negotiating |
| 104 | terminaltype. (TELOPT_TTYPE with value 24). client is the |
| 105 | telnet executable on the playerside, the server is the |
| 106 | gamedriver. |
| 107 | |
| 108 | client server |
| 109 | IAC WILL TTYPE |
| 110 | IAC DO TTYPE |
| 111 | |
| 112 | Or: |
| 113 | IAC DO TTYPE |
| 114 | IAC WILL TTYPE |
| 115 | |
| 116 | After this we are ready to transfer the terminaltype from the |
| 117 | client to the server as explained below. |
| 118 | |
| 119 | Now we are ready to start the real negotiations. I explain the |
| 120 | 3 options I have currently implemented. |
| 121 | |
| 122 | First TerminalType aka TTYPE aka 24 aka TELOPT_TTYPE assuming |
| 123 | the client and the server have exchanged WILL/DO. |
| 124 | |
| 125 | The server is now free to send 'IAC SB TELOPT_TTYPE |
| 126 | TELQUAL_SEND IAC SE' which will be replied with 'IAC SB |
| 127 | TELOPT_TTYPE TELQUAL_IS terminaltype IAC SE' where |
| 128 | terminaltype is a non-zero terminated string (it's terminated |
| 129 | by the IAC) (For values look up telnet.h) AND switch the |
| 130 | client's terminalemulation to 'terminaltype'. terminaltype is |
| 131 | case-insensitive. terminal-type may be UNKNOWN. The server may |
| 132 | repeat the SEND request and the client will respond with the |
| 133 | next preferred terminaltype. If this is the same as the |
| 134 | previous received, it marks the end of the list of |
| 135 | terminaltypes. The next SEND request will start the |
| 136 | terminaltypes from the beginning. |
| 137 | |
| 138 | Example: (we have exchanged WILL/DO already) |
| 139 | client server |
| 140 | IAC SB TTYPE SEND IAC SE |
| 141 | IAC SB TTYPE IS VT200 IAC SE |
| 142 | IAC SB TTYPE SEND IAC SE |
| 143 | IAC SB TTYPE IS VT100 IAC SE |
| 144 | IAC SB TTYPE SEND IAC SE |
| 145 | IAC SB TTYPE IS VT52 IAC SE |
| 146 | IAC SB TTYPE SEND IAC SE |
| 147 | IAC SB TTYPE IS VT52 IAC SE |
| 148 | /* this marks that we have all terminaltypes. We decide to use the |
| 149 | * vt200 mode so we have to skip to VT200 |
| 150 | */ |
| 151 | IAC SB TTYPE SEND IAC SE |
| 152 | IAC SB TTYPE IS VT200 IAC SE |
| 153 | |
| 154 | |
| 155 | Next important option is NAWS (31) or WindowSizeNegotiation. |
| 156 | |
| 157 | This one is a bit easier than terminaltype. After having |
| 158 | received a IAC DO NAWS from the server, the client will reply |
| 159 | with IAC WILL NAWS and immediately after that send IAC SB NAWS |
| 160 | columns_high columns_low lines_high lines_low IAC SE where |
| 161 | xx_low refers to the lowbyte of xx and xx_high refers to the |
| 162 | highbyte of xx. This will be automagically resent at every |
| 163 | windowresize (when the client gets a SIGWINCH for example) or |
| 164 | at your request with 'IAC SB NAWS SEND IAC SE'. |
| 165 | |
| 166 | Example: (WILL/DO exchanged) |
| 167 | client server |
| 168 | IAC SB NAWS 0 80 0 24 IAC SE /* the standard vt100 windowsize */ |
| 169 | /* no reply */ |
| 170 | |
| 171 | And, a bit less important but most complex, the LINEMODE (34) |
| 172 | option. It was implemented it due to the fact, that |
| 173 | some weird DOS telnets would not work otherwise. Implemented |
| 174 | are only the absolute basic feature, which is the actual |
| 175 | switching the telnet to linemode. After exchanging WILL/DO the |
| 176 | server sends a modechange request to the client using IAC SB |
| 177 | LINEMODE LM_MODE MODE_EDIT IAC SE, which should turn on local |
| 178 | commandline-editing for the client. If a client supports |
| 179 | LINEMODE it HAS to support this modechange. The client will |
| 180 | reply with IAC SB LINEMODE LM_MODE MODE_EDIT|MODE_ACK IAC SE |
| 181 | (x|y is bitwise or). Thats it for linemode. (You will perhaps |
| 182 | receive other IAC SB LINEMODEs with other LM_xxx ... you may |
| 183 | ignore them. (At least IRIX 5.x sends IAC SB LINEMODE LM_SLC |
| 184 | .... IAC SE which declares the local characterset.)). |
| 185 | |
| 186 | Example: (WILL/DO negotiated) |
| 187 | |
| 188 | client server |
| 189 | IAC SB LINEMODE LM_MODE |
| 190 | MODE_EDIT IAC SE |
| 191 | IAC SB LINEMODE LM_MODE |
| 192 | MODE_EDIT|MODE_ACK IAC SE |
| 193 | |
| 194 | Note: The option is much more funnier as it looks here, it for |
| 195 | example supports a mixed mode between linemode and |
| 196 | charactermode... flushing the input at certain characters (at |
| 197 | ESC or TAB for shell-like commandline completition). We suggest |
| 198 | reading RFC 1184. |
| 199 | |
| 200 | You might be interested in TELOPT_XDISPLAYLOC and TELOPT_ENVIRON too. |
| 201 | |
| 202 | Now, how to implement this using LDMud? |
| 203 | |
| 204 | 0. Patch src/driver/comm1.c, function init_telopts() to include |
| 205 | telopts_do[TELOPT_XXX] = reply_h_telnet_neg; |
| 206 | telopts_dont[TELOPT_XXX] = reply_h_telnet_neg; |
| 207 | telopts_will[TELOPT_XXX] = reply_h_telnet_neg; |
| 208 | telopts_wont[TELOPT_XXX] = reply_h_telnet_neg; |
| 209 | for every telnet negotiation you want to use. |
| 210 | Do not overwrite the TELOPT_ECHO and TELOPT_SGA hooks. |
| 211 | |
| 212 | Alternatively, set the driver hook H_NOECHO in master.c: |
| 213 | this diverts _all_ telnet data into the mudlib. |
| 214 | |
| 215 | 1. Add a new driver hook to master.c just below the others. |
| 216 | set_driver_hook(H_TELNET_NEG,"telnet_neg"), |
| 217 | 2. Make a telnet.h for your mudlib... just change the arrays in |
| 218 | src/driver/telnet.h. |
| 219 | 3. define a function |
| 220 | |
| 221 | void telnet_neg(int cmd, int option, int * optargs) |
| 222 | |
| 223 | in your interactive objects (login.c , shells, player.c or |
| 224 | whereever). And note, in ALL objects, through which a |
| 225 | player is handed through (in TAPPMud these are login.c and |
| 226 | player.c). [Ok, master.c is interactive for a very short |
| 227 | time too, but it won't accept input, will it?] |
| 228 | 'cmd' will be TELCMD_xxxx (see telnet.h), 'option' one of |
| 229 | TELOPT_xxxx and 'optargs' will be an array of ints (bytes in |
| 230 | fact) when 'cmd' is SB. |
| 231 | Parse 'cmd'/'option' and reply with appropiate answers |
| 232 | using binary_message() (appropiate meaning sending the |
| 233 | right DO/DONT/WILL/WONT if not sent before and using the SB |
| 234 | return values). |
| 235 | 3.1. Sent IAC DO TTYPE IAC DO NAWS IAC DO LINEMODE at the |
| 236 | first time you can do it (before cat()ing /WELCOME perhaps). |
| 237 | 3.2. Note all sent and received WILL/WONT/DO/DONT options for |
| 238 | conforming to the standard, avoiding endless loops and for |
| 239 | easy debugging :) |
| 240 | 3.3. Pass those recevied/sent data and other data when the |
| 241 | interactive object is changed (from login.c to player.c or |
| 242 | at other bodychanges). Clear the data when the player goes |
| 243 | linkdead or quits. You won't need to save this data. |
| 244 | 3.4. Lower_case() terminaltypes... ;) |
| 245 | 3.5. Use reasonable defaultvalues if the client does not |
| 246 | support one of the options. (columns 80,lines 24 if not |
| 247 | NAWS, unknown or vt100 for no terminaltype) |
| 248 | |
| 249 | The WILL/WONT/DO/DONT data is best saved in a mapping looking |
| 250 | like this: |
| 251 | ([ "received": ([ option1: DO_DONT_OR_0;WILL_WONT_OR_0, ... ]) |
| 252 | , "sent" : ([ option1: DO_DONT_OR_0;WILL_WONT_OR_0, ... ]) |
| 253 | ]) |
| 254 | |
| 255 | (Ok, it can be done better. But not without confusing *me* |
| 256 | more.) |
| 257 | |
| 258 | Before sending anything check |
| 259 | TN["sent"][option,0_if_do_dont_or_1_if_will_wont] |
| 260 | so you don't enter endless loops, save network traffic and the |
| 261 | like. |
| 262 | |
| 263 | The windowsize is best saved in the players environment |
| 264 | variables so that he can modify them later on. (Or in two |
| 265 | integers in the player object...). Use for these values is |
| 266 | clear I think. |
| 267 | |
| 268 | The terminaltypes received using above mentioned method are |
| 269 | best stored in an array. The actual set terminaltype is best |
| 270 | stored in an environment variable where the player can modify |
| 271 | it. Upon modifying it the IAC SB TTYPE SEND IAC SE cycle |
| 272 | should be started to match the emulation to the entered new |
| 273 | terminaltype. You then may use data retrieved from |
| 274 | /etc/termcap (man 5 termcap) or /usr/lib/terminfo/*/* (SysVID, |
| 275 | man 5 terminfo) to implement terminalcontrol codes dependend |
| 276 | on the terminaltype. /etc/termcap may prove to be the easiest |
| 277 | way tough /usr/lib/terminfo/*/* is the newer (and better) SysV |
| 278 | way of doing it. |
| 279 | |
| 280 | [Anyone got a description of the internal terminfo format for |
| 281 | me? -Marcus] |
| 282 | |
| 283 | LINEMODE replies may be left alone if only using the mode |
| 284 | change to MODE_EDIT |
| 285 | |
| 286 | Some statistics about what clients support telnet negotiations: |
| 287 | |
| 288 | Tinyfugue and some other mudclients usually do not support |
| 289 | negotiations. |
| 290 | Except for TF, which supports the Telnet End-Of-Record option |
| 291 | as marker for the end of the prompt. So if you send IAC EOR |
| 292 | after every prompt, it will print the prompt always in the |
| 293 | input window. (Do not forget to negotiate that. First IAC WILL |
| 294 | TELOPT_EOR/wait for IAC DO TELOPT_EOR). Newer versions of |
| 295 | TF will support NAWS and there will be a patch for TTYPE |
| 296 | negotiation available soon. |
| 297 | |
| 298 | All telnets able to do negotiations I've encountered support |
| 299 | the TTYPE option. |
| 300 | HP9.x,Irix5.x,Linux,EP/IX,CUTELNET/NCSATELNET (Novell) and |
| 301 | perhaps more support NAWS. |
| 302 | At least Irix5.x,Linux,CU/NCSATELNET support LINEMODE. |
| 303 | SUN does not support NAWS and LINEMODE neither in SunOS 4.1.3 |
| 304 | nor in Solaris 2.3. |
| 305 | |
| 306 | For getting RFCs you can for example use |
| 307 | ftp://ftp.uni-erlangen.de/pub/doc/rfc/ |
| 308 | |
| 309 | |
| 310 | BUGS |
| 311 | Not all aspects of the options are mentioned to keep this doc |
| 312 | at a reasonable size. Refer to the RFCs to get more confused. |
| 313 | |
| 314 | CREDITS |
| 315 | Provided by Marcus@TAPPMud (Marcus Meissner, |
| 316 | <msmeissn@cip.informatik.uni-erlangen.de>). |