From e72d6077b475bc6142afc3b5967db113922c76f5 Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Sun, 14 Oct 2007 22:27:51 +0000 Subject: Fixed an interesting ideosyncacy in Bu::Hash in a safe way, I should try to do this with the Bu::Archive next. Basically, there's one generic template function that will convert anything that can safely cast to a uint32_t and that supports direct comparisson, and doesn't have it's own override already to be a Hash key, such as char, uint8_t, uint64_t, etc. The Telnet protocol handler does everything I need it too for now, next up for it is escape sequence handling, it would be nice to make this general too, by using the termcap database or something, but there is an ANSI/ISO standard now, I may just go ahead and use that. Also, it looks like it'd be pretty easy to make the canonical mode editing functions be pluggable to facilitate different types of editing, but that can be done down the road as well. --- Doxyfile | 4 +- misc/iana-telnet-options.txt | 486 ++++++++++++++++++++++++ misc/rfc854-telnet.txt | 854 +++++++++++++++++++++++++++++++++++++++++++ src/hash.cpp | 20 - src/hash.h | 14 +- src/protocolhttp.h | 9 +- src/protocoltelnet.cpp | 532 +++++++++++++++++++++++++-- src/protocoltelnet.h | 151 +++++++- src/tests/telnetsrv.cpp | 85 +++++ 9 files changed, 2075 insertions(+), 80 deletions(-) create mode 100644 misc/iana-telnet-options.txt create mode 100644 misc/rfc854-telnet.txt create mode 100644 src/tests/telnetsrv.cpp diff --git a/Doxyfile b/Doxyfile index 4e64a4c..220119a 100644 --- a/Doxyfile +++ b/Doxyfile @@ -65,7 +65,7 @@ GENERATE_DEPRECATEDLIST= YES ENABLED_SECTIONS = MAX_INITIALIZER_LINES = 30 SHOW_USED_FILES = YES -SHOW_DIRECTORIES = YES +SHOW_DIRECTORIES = NO FILE_VERSION_FILTER = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages @@ -258,7 +258,7 @@ INCLUDE_GRAPH = YES INCLUDED_BY_GRAPH = YES CALL_GRAPH = NO GRAPHICAL_HIERARCHY = YES -DIRECTORY_GRAPH = YES +DIRECTORY_GRAPH = NO DOT_IMAGE_FORMAT = png DOT_PATH = DOTFILE_DIRS = diff --git a/misc/iana-telnet-options.txt b/misc/iana-telnet-options.txt new file mode 100644 index 0000000..d1338a3 --- /dev/null +++ b/misc/iana-telnet-options.txt @@ -0,0 +1,486 @@ + +TELNET OPTIONS + +(last updated 2003-11-06) + +The Telnet Protocol has a number of options that may be negotiated. +These options are listed here. "Internet Official Protocol Standards" +(STD 1) provides more detailed information. + +Options Name References +------- ----------------------- ---------- + 0 Binary Transmission [RFC856] + 1 Echo [RFC857] + 2 Reconnection [NIC50005] + 3 Suppress Go Ahead [RFC858] + 4 Approx Message Size Negotiation [ETHERNET] + 5 Status [RFC859] + 6 Timing Mark [RFC860] + 7 Remote Controlled Trans and Echo [RFC726] + 8 Output Line Width [NIC50005] + 9 Output Page Size [NIC50005] + 10 Output Carriage-Return Disposition [RFC652] + 11 Output Horizontal Tab Stops [RFC653] + 12 Output Horizontal Tab Disposition [RFC654] + 13 Output Formfeed Disposition [RFC655] + 14 Output Vertical Tabstops [RFC656] + 15 Output Vertical Tab Disposition [RFC657] + 16 Output Linefeed Disposition [RFC658] + 17 Extended ASCII [RFC698] + 18 Logout [RFC727] + 19 Byte Macro [RFC735] + 20 Data Entry Terminal [RFC1043,RFC732] + 21 SUPDUP [RFC736,RFC734] + 22 SUPDUP Output [RFC749] + 23 Send Location [RFC779] + 24 Terminal Type [RFC1091] + 25 End of Record [RFC885] + 26 TACACS User Identification [RFC927] + 27 Output Marking [RFC933] + 28 Terminal Location Number [RFC946] + 29 Telnet 3270 Regime [RFC1041] + 30 X.3 PAD [RFC1053] + 31 Negotiate About Window Size [RFC1073] + 32 Terminal Speed [RFC1079] + 33 Remote Flow Control [RFC1372] + 34 Linemode [RFC1184] + 35 X Display Location [RFC1096] + 36 Environment Option [RFC1408] + 37 Authentication Option [RFC2941] + 38 Encryption Option [RFC2946] + 39 New Environment Option [RFC1572] + 40 TN3270E [RFC1647] + 41 XAUTH [Earhart] + 42 CHARSET [RFC2066] + 43 Telnet Remote Serial Port (RSP) [Barnes] + 44 Com Port Control Option [RFC2217] + 45 Telnet Suppress Local Echo [Atmar] + 46 Telnet Start TLS [Boe] + 47 KERMIT [RFC2840] + 48 SEND-URL [Croft] + 49 FORWARD_X [Altman] + 50-137 Unassigned [IANA] + 138 TELOPT PRAGMA LOGON [McGregory] + 139 TELOPT SSPI LOGON [McGregory] + 140 TELOPT PRAGMA HEARTBEAT [McGregory] + 255 Extended-Options-List [RFC861] + +Telnet Authentication Types (Option 37) + +In [RFC2941], a list of authentication commands and types is +documented. Additions to the list are registerd by the IANA and +documented here. Note: Authentication types followed by (*) were +never submitted to the IETF for consideration as an Internet standard. + +Command Description Reference + 0 IS [RFC2941] + 1 SEND [RFC2941] + 2 REPLY [RFC2941] + 3 NAME [RFC2941] + +Type Description Reference + 0 NULL [RFC2941] + 1 KERBEROS_V4 [RFC2941] + 2 KERBEROS_V5 [RFC2942] + 3 SPX [RFC2941] * + 4 MINK [RFC2941] * + 5 SRP [RFC2944] + 6 RSA (also used by SRA) [RFC2941] + 7 SSL [RFC2941] + 8-9 Unassigned [IANA] + 10 LOKI [RFC2941] * + 11 SSA [Schoch] + 12 KEA_SJ [RFC2951] + 13 KEA_SJ_INTEG [RFC2951] + 14 DSS [RFC2943] + 15 NTLM [Kahn] * + +In [RFC 1411], on the KERBEROS_V4 Telnet Authentication type there are +a set of Suboption Commands. Additions to the list are registerd by +the IANA and documented here. + +Suboption Command Reference + 0 AUTH [RFC1411] + 1 REJECT [RFC1411] + 2 ACCEPT [RFC1411] + 3 CHALLENGE [RFC1411] + 4 RESPONSE [RFC1411] + 5 FORWARD [Brashear] + 6 FORWARD-ACCEPT [Brashear] + 7 FORWARD-REJECT [Brashear] + 8 EXP [Wu] + 9 PARAMS [Wu] + + +In the KERBEROS_V5 Telnet Authentication type there are a set of +Suboption Commands. Additions to the list are registerd by the IANA +and documented here. + +Suboption Command Reference + 0 AUTH [RFC2942] + 1 REJECT [RFC2942] + 2 ACCEPT [RFC2942] + 3 RESPONSE [RFC2942] + 4 FORWARD [RFC2942] + 5 FORWARD_ACCEPT [RFC2942] + 6 FORWARD-REJECT [RFC2942] + + +In the DSS Telnet Authentication type there are a set of +Suboption Commands. Additions to the list are registerd by the IANA +and documented here. + +Suboption Command Reference + 1 DSS_INITIALIZE [RFC2943] + 2 DSS_TOKENBA [RFC2943] + 3 DSS_CERTA_TOKENAB [RFC2943] + 4 DSS_CERTB_TOKENBA2 [RFC2943] + + +In the SRP Telnet Authentication type there are a set of Suboption +Commands. Additions to the list are registerd by the IANA and +documented here. + +Suboption Command Reference + 0 AUTH [RFC2944] + 1 REJECT [RFC2944] + 2 ACCEPT [RFC2944] + 3 CHALLENGE [RFC2944] + 4 RESPONSE [RFC2944] + 5-7 Unassigned [RFC2944] + 8 EXP [RFC2944] + 9 PARAMS [RFC2944] + + +In the KEA_SJ and KEA_SJ_INTEG Telnet Authentication types, there are +a set of Suboption Commands. Additions to the list are registerd by +the IANA and documented here. + +Suboption Command Reference + 1 KEA_CERTA_RA [RFC2951] + 2 KEA_CERTB_RB_IVB_NONCEB [RFC2951] + 3 KEA_IVA_RESPONSEB_NONCEA [RFC2951] + 4 KEA_RESPONSEA [RFC2951] + + +Telnet Encryption Types (Option 38) + +In the Telnet Encryption commands and types [RFC2946] there have been +various implementations in several widely distributed versions of +Telnet (e.g., at MIT, Stanford, and Columbia). Originally, only two +encryption types were specified. Additional encryption types have +been defined and are listed below. Additions to the list are +registerd by the IANA and documented here. + +Command + + 0 IS [RFC2946] + 1 SUPPORT [RFC2946] + 2 REPLY [RFC2946] + 3 START [RFC2946] + 4 END [RFC2946] + 5 REQUEST-START [RFC2946] + 6 REQUEST-END [RFC2946] + 7 ENC_KEYID [RFC2946] + 8 DEC_KEYID [RFC2946] + +Type + + 0 NULL [RFC2946] + 1 DES_CFB64 [RFC2946] + 2 DES_OFB64 [RFC2946] + 3 DES3_CFB64 [RFC2946] + 4 DES3_OFB64 [RFC2946] + 5-7 Unassigned [IANA] + 8 CAST5_40_CFB64 [RFC2946] + 9 CAST5_40_OFB64 [RFC2946] + 10 CAST128_CFB64 [RFC2946] + 11 CAST128_OFB64 [RFC2946] + 12 AES_CCM [Josefsson] + +In the DES3_CFB64 Telnet Encryption type there are a set of Suboption +Commands. Additions to the list are registerd by the IANA and +documented here. + +Suboption Command Reference + 1 CFB64_IV [RFC2947] + 2 CFB64_IV_OK [RFC2947] + 3 CFB64_IV_BAD [RFC2947] + + +In the DES3_OFB64 Telnet Encryption type there are a set of Suboption +Commands. Additions to the list are registerd by the IANA and +documented here. + +Suboption Command Reference + 1 OFB64_IV [RFC2948] + 2 OFB64_IV_OK [RFC2948] + 3 OFB64_IV_BAD [RFC2948] + + +In the CAST5_40_OFB64 and CAST128_OFB64 Telnet Encryption types, there +are a set of Suboption Commands. Additions to the list are registerd +by the IANA and documented here. + +Suboption Command Reference + 1 OFB64_IV [RFC2949] + 2 OFB64_IV_OK [RFC2949] + 3 OFB64_IV_BAD [RFC2949] + + +In the CAST5_40_CFB64 and CAST128_CFB64 Telnet Encryption types, there +are a set of Suboption Commands. Additions to the list are registerd +by the IANA and documented here. + +Suboption Command Reference + 1 CFB64_IV [RFC2950] + 2 CFB64_IV_OK [RFC2950] + 3 CFB64_IV_BAD [RFC2950] + + +In the DES_CFB64 Telnet Encryption type there are a set of Suboption +Commands. Additions to the list are registerd by the IANA and +documented here. + +Suboption Command Reference + 1 CFB64_IV [RFC2952] + 2 CFB64_IV_OK [RFC2952] + 3 CFB64_IV_BAD [RFC2952] + + +In the DES_OFB64 Telnet Encryption type there are a set of Suboption +Commands. Additions to the list are registerd by the IANA and +documented here. + +Suboption Command Reference + 1 OFB64_IV [RFC2953] + 2 OFB64_IV_OK [RFC2953] + 3 OFB64_IV_BAD [RFC2953] + + +REFERENCES + +[ETHERNET] "The Ethernet, A Local Area Network: Data Link Layer and + Physical Layer Specification", AA-K759B-TK, Digital + Equipment Corporation, Maynard, MA. Also as: "The + Ethernet - A Local Area Network", Version 1.0, Digital + Equipment Corporation, Intel Corporation, Xerox + Corporation, September 1980. And: "The Ethernet, A Local + Area Network: Data Link Layer and Physical Layer + Specifications", Digital, Intel and Xerox, November 1982. + And: XEROX, "The Ethernet, A Local Area Network: Data Link + Layer and Physical Layer Specification", X3T51/80-50, Xerox + Corporation, Stamford, CT., October 1980. + +[NIC50005] DDN Protocol Handbook, "Telnet Reconnection Option", + "Telnet Output Line Width Option", "Telnet Output Page Size + Option", NIC 50005, December 1985. + +[RFC652] Crocker, D., "Telnet Output Carriage-Return Disposition + Option", RFC 652, UCLA-NMC, October 1974. + +[RFC653] Crocker, D., "Telnet Output Horizontal Tabstops Option", + RFC 653, UCLA-NMC, October 1974. + +[RFC654] Crocker, D., "Telnet Output Horizontal Tab Disposition + Option", RFC 654, UCLA-NMC, October 1974. + +[RFC655] Crocker, D., "Telnet Output Formfeed Disposition Option", + RFC 655, UCLA-NMC, October 1974. + +[RFC656] Crocker, D., "Telnet Output Vertical Tabstops Option", + RFC 656, UCLA-NMC, October 1974. + +[RFC657] Crocker, D., "Telnet Output Vertical Tab Disposition Option", + RFC 657, UCLA-NMC, October 1974. + +[RFC658] Crocker, D., "Telnet Output Linefeed Disposition", RFC 658, + UCLA-NMC, October 1974. + +[RFC698] Tovar, "Telnet Extended ASCII Option", RFC 698, Stanford + University-AI, July 1975. + +[RFC726] Postel, J. and D. Crocker, "Remote Controlled Transmission + and Echoing Telnet Option", RFC 726, SRI-ARC, UC Irvine, + March 1977. + +[RFC727] Crispin, M., "Telnet Logout Option", RFC 727, Stanford + University-AI, April 1977. + +[RFC734] Crispin, M., "SUPDUP Protocol", RFC 734, Stanford, + October 1977. + +[RFC735] Crocker, D. and R. Gumpertz, "Revised Telnet Byte Marco + Option", RFC 735, Rand, CMU, November 1977. + +[RFC736] Crispin, M., "Telnet SUPDUP Option", Stanford University-AI, + RFC 736, Stanford, October 1977. + +[RFC749] Greenberg, B., "Telnet SUPDUP-OUTPUT Option", RFC 749, + MIT-Multics, September 1978. + +[RFC779] Killian, E., "Telnet Send-Location Option", RFC 779, + LLL, April 1981. + +[RFC856] Postel, J. and J. Reynolds, "Telnet Binary Transmission", + STD 27, RFC 856, USC/Information Sciences Institute, May + 1983. + +[RFC857] Postel, J. and J. Reynolds, "Telnet Echo Option", STD 28, RFC + 857, USC/Information Sciences Institute, May 1983. + +[RFC858] Postel, J. and J. Reynolds, "Telnet Suppress Go Ahead + Option", STD 29, RFC 858, USC/Information Sciences Institute, + May 1983. + +[RFC859] Postel, J. and J. Reynolds, "Telnet Status Option", STD 30, + RFC 859, USC/Information Sciences Institute, May 1983. + +[RFC860] Postel, J. and J. Reynolds, "Telnet Timing Mark Option", + STD 31, RFC 860, USC/Information Sciences Institute, May + 1983. + +[RFC861] Postel, J. and J. Reynolds, "Telnet Extended Options - List + Option", STD 32, RFC 861, USC/Information Sciences Institute, + May 1983. + +[RFC885] Postel, J., "Telnet End of Record Option", RFC 885, + USC/Information Sciences Institute, December 1983. + +[RFC927] Anderson, B., "TACACS User Identification Telnet Option", + RFC 927, BBN, December 1984. + +[RFC933] Silverman, S., "Output Marking Telnet Option", RFC 933, + MITRE, January 1985. + +[RFC946] Nedved, R., "Telnet Terminal Location Number Option", + RFC 946, Carnegie-Mellon University, May 1985. + +[RDC1041] Rekhter, J., "Telnet 3270 Regime Option", RFC 1041, + IBM, January 1988. + +[RFC1043] Yasuda, A., and T. Thompson, "TELNET Data Entry Terminal + Option DODIIS Implementation", RFC 1043, DIA, February 1988. + +[RFC1053] Levy, S., and T. Jacobson, "Telnet X.3 PAD Option", + RFC 1053, Minnesota Supercomputer Center, April 1988. + +[RFC1073] Waitzman, D., "Telnet Window Size Option", RFC 1073, + BBN STC, October, 1988. + +[RFC1079] Hedrick, C., "Telnet Terminal Speed Option", RFC 1079, + Rutgers University, December 1988. + +[RFC1091] VanBokkelen, J., "Telnet Terminal Type Option", + RFC 1091, FTP Software, Inc., February 1989. + +[RFC1096] Marcy, G., "Telnet X Display Location Option", RFC 1096, + Carnegie Mellon University, March 1989. + +[RFC1184] Borman, D., Editor, "Telnet Linemode Option", + RFC 1184, Cray Research, Inc., October 1990. + +[RFC1372] Hedrick, C., and D. Borman, "Telnet Remote Flow Control + Option", RFC 1372, Rutgers University, Cray Research, Inc., + October 1992. + +[RFC1408] Borman, D., Editor, "Telnet Environment Option", RFC 1408, + Cray Research, Inc., January 1993. + +[RFC1411] Borman, D., Editor, "Telnet Authentication: Kerberos + Version 4", RFC 1411, Cray Research, Inc., January 1993. + +[RFC1416] Borman, D., Editor, "Telnet Authentication Option", RFC + 1416, Cray Research, Inc., February 1993. + +[RFC1572] Alexander, S., Editor, "Telnet Environment Option", RFC1572, + Lachman Technology, Inc., January 1994. + +[RFC1647] Kelly, B., "TN3270 Enhancements", RFC1647, Auburn + University, July 1994. + +[RFC2066] Gellens, R., "Telnet CharSet Option", RFC 2066, Unisys, + January 1997. + +[RFC2217] Clark, G., "Telnet Com Port Control Option", RFC 2217, + Cisco Systems, Inc., October 1997. + +[RFC2840] Altman, J., "Telnet Kermit Option", RFC 2840, May 2000. + +[RFC2941] Ts'o, T. and J. Altman, "Telnet Authentication Option", + RFC 2941, September 2000. + +[RFC2942] Ts'o, T., "Telnet Authentication: Kerberos Version 5", + RFC 2942, September 2000. + +[RFC2943] Housley, R., Horting, T. and P. Yee, "TELNET Authentication + Using DSA", RFC 2943, September 2000. + +[RFC2944] Wu, T., "Telnet Authentication: SRP", RFC 2944, September + 2000. + +[RFC2946] Ts'o, T., "Telnet Data Encryption Option", RFC 2946, + September 2000. + +[RFC2947] Altman, J., "Telnet Encryption: DES3 64 bit Cipher + Feedback", RFC 2947, September 2000. + +[RFC2948] Altman, J., "Telnet Encryption: DES3 64 bit Output + Feedback", RFC 2948, September 2000. + +[RFC2949] Altman, J., "Telnet Encryption: CAST-128 64 bit Output + Feedback", RFC 2949, September 2000. + +[RFC2950] Altman, J., "Telnet Encryption: CAST-128 64 bit Cipher + Feedback", September 2000. + +[RFC2951] Housley, R., Horting, T. and P. Yee, "TELNET Authentication + Using KEA and SKIPJACK", September 2000. + +[RFC2952] Ts'o, T., "Telnet Encryption: DES 64 bit Cipher Feedback", + RFC 2952, September 2000. + +[RFC2953] Ts'o, T., "Telnet Encryption: DES 64 bit Output Feedback", + RFC 2953, September 2000. + +PEOPLE +------ + +[Altman] Jeffrey Altman, , August + 1998, January 2000. + +[Atmar] Wirt Atmar, , June 1998. + +[Barnes] Robert Barnes, , July 1997. + +[Boe] Michael Boe, , June 1998. + +[Brashear] Derrick Brashear, , January 1995. + +[Borman] Dave Borman, , January 1995. + +[Croft] David Croft, , September 1998. + +[Earhart] Rob Earhart, , April 1995. + +[Horting] Todd Horting , April 1998. + +[Hudson] Tim Hudson , December 1998. + +[IANA] Internet Assigned Numbers Authority, , January 1995. + +[Josefsson] S. Josefsson , November 2003. + http://josefsson.org/shishi/shishi.html#Telnet%20encryption%20with%20AES-CCM + +[Kahn] Louis Kahn, , October 1998. + +[McGregory] Steve McGregory , December 1998. + +[Schoch] Steven Schoch, , January 1995. + +[Ts'o] Theodore Ts'o, , September 1998. + +[Wu] Thomas Wu, , July 1997, September 1998. + +[] + diff --git a/misc/rfc854-telnet.txt b/misc/rfc854-telnet.txt new file mode 100644 index 0000000..e794bf7 --- /dev/null +++ b/misc/rfc854-telnet.txt @@ -0,0 +1,854 @@ + +Network Working Group J. Postel +Request for Comments: 854 J. Reynolds + ISI +Obsoletes: NIC 18639 May 1983 + + TELNET PROTOCOL SPECIFICATION + + +This RFC specifies a standard for the ARPA Internet community. Hosts on +the ARPA Internet are expected to adopt and implement this standard. + +INTRODUCTION + + The purpose of the TELNET Protocol is to provide a fairly general, + bi-directional, eight-bit byte oriented communications facility. Its + primary goal is to allow a standard method of interfacing terminal + devices and terminal-oriented processes to each other. It is + envisioned that the protocol may also be used for terminal-terminal + communication ("linking") and process-process communication + (distributed computation). + +GENERAL CONSIDERATIONS + + A TELNET connection is a Transmission Control Protocol (TCP) + connection used to transmit data with interspersed TELNET control + information. + + The TELNET Protocol is built upon three main ideas: first, the + concept of a "Network Virtual Terminal"; second, the principle of + negotiated options; and third, a symmetric view of terminals and + processes. + + 1. When a TELNET connection is first established, each end is + assumed to originate and terminate at a "Network Virtual Terminal", + or NVT. An NVT is an imaginary device which provides a standard, + network-wide, intermediate representation of a canonical terminal. + This eliminates the need for "server" and "user" hosts to keep + information about the characteristics of each other's terminals and + terminal handling conventions. All hosts, both user and server, map + their local device characteristics and conventions so as to appear to + be dealing with an NVT over the network, and each can assume a + similar mapping by the other party. The NVT is intended to strike a + balance between being overly restricted (not providing hosts a rich + enough vocabulary for mapping into their local character sets), and + being overly inclusive (penalizing users with modest terminals). + + NOTE: The "user" host is the host to which the physical terminal + is normally attached, and the "server" host is the host which is + normally providing some service. As an alternate point of view, + + + + +Postel & Reynolds [Page 1] + + + +RFC 854 May 1983 + + + applicable even in terminal-to-terminal or process-to-process + communications, the "user" host is the host which initiated the + communication. + + 2. The principle of negotiated options takes cognizance of the fact + that many hosts will wish to provide additional services over and + above those available within an NVT, and many users will have + sophisticated terminals and would like to have elegant, rather than + minimal, services. Independent of, but structured within the TELNET + Protocol are various "options" that will be sanctioned and may be + used with the "DO, DON'T, WILL, WON'T" structure (discussed below) to + allow a user and server to agree to use a more elaborate (or perhaps + just different) set of conventions for their TELNET connection. Such + options could include changing the character set, the echo mode, etc. + + The basic strategy for setting up the use of options is to have + either party (or both) initiate a request that some option take + effect. The other party may then either accept or reject the + request. If the request is accepted the option immediately takes + effect; if it is rejected the associated aspect of the connection + remains as specified for an NVT. Clearly, a party may always refuse + a request to enable, and must never refuse a request to disable some + option since all parties must be prepared to support the NVT. + + The syntax of option negotiation has been set up so that if both + parties request an option simultaneously, each will see the other's + request as the positive acknowledgment of its own. + + 3. The symmetry of the negotiation syntax can potentially lead to + nonterminating acknowledgment loops -- each party seeing the incoming + commands not as acknowledgments but as new requests which must be + acknowledged. To prevent such loops, the following rules prevail: + + a. Parties may only request a change in option status; i.e., a + party may not send out a "request" merely to announce what mode it + is in. + + b. If a party receives what appears to be a request to enter some + mode it is already in, the request should not be acknowledged. + This non-response is essential to prevent endless loops in the + negotiation. It is required that a response be sent to requests + for a change of mode -- even if the mode is not changed. + + c. Whenever one party sends an option command to a second party, + whether as a request or an acknowledgment, and use of the option + will have any effect on the processing of the data being sent from + the first party to the second, then the command must be inserted + in the data stream at the point where it is desired that it take + + +Postel & Reynolds [Page 2] + + + +RFC 854 May 1983 + + + effect. (It should be noted that some time will elapse between + the transmission of a request and the receipt of an + acknowledgment, which may be negative. Thus, a host may wish to + buffer data, after requesting an option, until it learns whether + the request is accepted or rejected, in order to hide the + "uncertainty period" from the user.) + + Option requests are likely to flurry back and forth when a TELNET + connection is first established, as each party attempts to get the + best possible service from the other party. Beyond that, however, + options can be used to dynamically modify the characteristics of the + connection to suit changing local conditions. For example, the NVT, + as will be explained later, uses a transmission discipline well + suited to the many "line at a time" applications such as BASIC, but + poorly suited to the many "character at a time" applications such as + NLS. A server might elect to devote the extra processor overhead + required for a "character at a time" discipline when it was suitable + for the local process and would negotiate an appropriate option. + However, rather than then being permanently burdened with the extra + processing overhead, it could switch (i.e., negotiate) back to NVT + when the detailed control was no longer necessary. + + It is possible for requests initiated by processes to stimulate a + nonterminating request loop if the process responds to a rejection by + merely re-requesting the option. To prevent such loops from + occurring, rejected requests should not be repeated until something + changes. Operationally, this can mean the process is running a + different program, or the user has given another command, or whatever + makes sense in the context of the given process and the given option. + A good rule of thumb is that a re-request should only occur as a + result of subsequent information from the other end of the connection + or when demanded by local human intervention. + + Option designers should not feel constrained by the somewhat limited + syntax available for option negotiation. The intent of the simple + syntax is to make it easy to have options -- since it is + correspondingly easy to profess ignorance about them. If some + particular option requires a richer negotiation structure than + possible within "DO, DON'T, WILL, WON'T", the proper tack is to use + "DO, DON'T, WILL, WON'T" to establish that both parties understand + the option, and once this is accomplished a more exotic syntax can be + used freely. For example, a party might send a request to alter + (establish) line length. If it is accepted, then a different syntax + can be used for actually negotiating the line length -- such a + "sub-negotiation" might include fields for minimum allowable, maximum + allowable and desired line lengths. The important concept is that + + + + +Postel & Reynolds [Page 3] + + + +RFC 854 May 1983 + + + such expanded negotiations should never begin until some prior + (standard) negotiation has established that both parties are capable + of parsing the expanded syntax. + + In summary, WILL XXX is sent, by either party, to indicate that + party's desire (offer) to begin performing option XXX, DO XXX and + DON'T XXX being its positive and negative acknowledgments; similarly, + DO XXX is sent to indicate a desire (request) that the other party + (i.e., the recipient of the DO) begin performing option XXX, WILL XXX + and WON'T XXX being the positive and negative acknowledgments. Since + the NVT is what is left when no options are enabled, the DON'T and + WON'T responses are guaranteed to leave the connection in a state + which both ends can handle. Thus, all hosts may implement their + TELNET processes to be totally unaware of options that are not + supported, simply returning a rejection to (i.e., refusing) any + option request that cannot be understood. + + As much as possible, the TELNET protocol has been made server-user + symmetrical so that it easily and naturally covers the user-user + (linking) and server-server (cooperating processes) cases. It is + hoped, but not absolutely required, that options will further this + intent. In any case, it is explicitly acknowledged that symmetry is + an operating principle rather than an ironclad rule. + + A companion document, "TELNET Option Specifications," should be + consulted for information about the procedure for establishing new + options. + +THE NETWORK VIRTUAL TERMINAL + + The Network Virtual Terminal (NVT) is a bi-directional character + device. The NVT has a printer and a keyboard. The printer responds + to incoming data and the keyboard produces outgoing data which is + sent over the TELNET connection and, if "echoes" are desired, to the + NVT's printer as well. "Echoes" will not be expected to traverse the + network (although options exist to enable a "remote" echoing mode of + operation, no host is required to implement this option). The code + set is seven-bit USASCII in an eight-bit field, except as modified + herein. Any code conversion and timing considerations are local + problems and do not affect the NVT. + + TRANSMISSION OF DATA + + Although a TELNET connection through the network is intrinsically + full duplex, the NVT is to be viewed as a half-duplex device + operating in a line-buffered mode. That is, unless and until + + + + +Postel & Reynolds [Page 4] + + + +RFC 854 May 1983 + + + options are negotiated to the contrary, the following default + conditions pertain to the transmission of data over the TELNET + connection: + + 1) Insofar as the availability of local buffer space permits, + data should be accumulated in the host where it is generated + until a complete line of data is ready for transmission, or + until some locally-defined explicit signal to transmit occurs. + This signal could be generated either by a process or by a + human user. + + The motivation for this rule is the high cost, to some hosts, + of processing network input interrupts, coupled with the + default NVT specification that "echoes" do not traverse the + network. Thus, it is reasonable to buffer some amount of data + at its source. Many systems take some processing action at the + end of each input line (even line printers or card punches + frequently tend to work this way), so the transmission should + be triggered at the end of a line. On the other hand, a user + or process may sometimes find it necessary or desirable to + provide data which does not terminate at the end of a line; + therefore implementers are cautioned to provide methods of + locally signaling that all buffered data should be transmitted + immediately. + + 2) When a process has completed sending data to an NVT printer + and has no queued input from the NVT keyboard for further + processing (i.e., when a process at one end of a TELNET + connection cannot proceed without input from the other end), + the process must transmit the TELNET Go Ahead (GA) command. + + This rule is not intended to require that the TELNET GA command + be sent from a terminal at the end of each line, since server + hosts do not normally require a special signal (in addition to + end-of-line or other locally-defined characters) in order to + commence processing. Rather, the TELNET GA is designed to help + a user's local host operate a physically half duplex terminal + which has a "lockable" keyboard such as the IBM 2741. A + description of this type of terminal may help to explain the + proper use of the GA command. + + The terminal-computer connection is always under control of + either the user or the computer. Neither can unilaterally + seize control from the other; rather the controlling end must + relinguish its control explicitly. At the terminal end, the + hardware is constructed so as to relinquish control each time + that a "line" is terminated (i.e., when the "New Line" key is + typed by the user). When this occurs, the attached (local) + + +Postel & Reynolds [Page 5] + + + +RFC 854 May 1983 + + + computer processes the input data, decides if output should be + generated, and if not returns control to the terminal. If + output should be generated, control is retained by the computer + until all output has been transmitted. + + The difficulties of using this type of terminal through the + network should be obvious. The "local" computer is no longer + able to decide whether to retain control after seeing an + end-of-line signal or not; this decision can only be made by + the "remote" computer which is processing the data. Therefore, + the TELNET GA command provides a mechanism whereby the "remote" + (server) computer can signal the "local" (user) computer that + it is time to pass control to the user of the terminal. It + should be transmitted at those times, and only at those times, + when the user should be given control of the terminal. Note + that premature transmission of the GA command may result in the + blocking of output, since the user is likely to assume that the + transmitting system has paused, and therefore he will fail to + turn the line around manually. + + The foregoing, of course, does not apply to the user-to-server + direction of communication. In this direction, GAs may be sent at + any time, but need not ever be sent. Also, if the TELNET + connection is being used for process-to-process communication, GAs + need not be sent in either direction. Finally, for + terminal-to-terminal communication, GAs may be required in + neither, one, or both directions. If a host plans to support + terminal-to-terminal communication it is suggested that the host + provide the user with a means of manually signaling that it is + time for a GA to be sent over the TELNET connection; this, + however, is not a requirement on the implementer of a TELNET + process. + + Note that the symmetry of the TELNET model requires that there is + an NVT at each end of the TELNET connection, at least + conceptually. + + STANDARD REPRESENTATION OF CONTROL FUNCTIONS + + As stated in the Introduction to this document, the primary goal + of the TELNET protocol is the provision of a standard interfacing + of terminal devices and terminal-oriented processes through the + network. Early experiences with this type of interconnection have + shown that certain functions are implemented by most servers, but + that the methods of invoking these functions differ widely. For a + human user who interacts with several server systems, these + differences are highly frustrating. TELNET, therefore, defines a + standard representation for five of these functions, as described + + +Postel & Reynolds [Page 6] + + + +RFC 854 May 1983 + + + below. These standard representations have standard, but not + required, meanings (with the exception that the Interrupt Process + (IP) function may be required by other protocols which use + TELNET); that is, a system which does not provide the function to + local users need not provide it to network users and may treat the + standard representation for the function as a No-operation. On + the other hand, a system which does provide the function to a + local user is obliged to provide the same function to a network + user who transmits the standard representation for the function. + + Interrupt Process (IP) + + Many systems provide a function which suspends, interrupts, + aborts, or terminates the operation of a user process. This + function is frequently used when a user believes his process is + in an unending loop, or when an unwanted process has been + inadvertently activated. IP is the standard representation for + invoking this function. It should be noted by implementers + that IP may be required by other protocols which use TELNET, + and therefore should be implemented if these other protocols + are to be supported. + + Abort Output (AO) + + Many systems provide a function which allows a process, which + is generating output, to run to completion (or to reach the + same stopping point it would reach if running to completion) + but without sending the output to the user's terminal. + Further, this function typically clears any output already + produced but not yet actually printed (or displayed) on the + user's terminal. AO is the standard representation for + invoking this function. For example, some subsystem might + normally accept a user's command, send a long text string to + the user's terminal in response, and finally signal readiness + to accept the next command by sending a "prompt" character + (preceded by ) to the user's terminal. If the AO were + received during the transmission of the text string, a + reasonable implementation would be to suppress the remainder of + the text string, but transmit the prompt character and the + preceding . (This is possibly in distinction to the + action which might be taken if an IP were received; the IP + might cause suppression of the text string and an exit from the + subsystem.) + + It should be noted, by server systems which provide this + function, that there may be buffers external to the system (in + + + + +Postel & Reynolds [Page 7] + + + +RFC 854 May 1983 + + + the network and the user's local host) which should be cleared; + the appropriate way to do this is to transmit the "Synch" + signal (described below) to the user system. + + Are You There (AYT) + + Many systems provide a function which provides the user with + some visible (e.g., printable) evidence that the system is + still up and running. This function may be invoked by the user + when the system is unexpectedly "silent" for a long time, + because of the unanticipated (by the user) length of a + computation, an unusually heavy system load, etc. AYT is the + standard representation for invoking this function. + + Erase Character (EC) + + Many systems provide a function which deletes the last + preceding undeleted character or "print position"* from the + stream of data being supplied by the user. This function is + typically used to edit keyboard input when typing mistakes are + made. EC is the standard representation for invoking this + function. + + *NOTE: A "print position" may contain several characters + which are the result of overstrikes, or of sequences such as + BS ... + + Erase Line (EL) + + Many systems provide a function which deletes all the data in + the current "line" of input. This function is typically used + to edit keyboard input. EL is the standard representation for + invoking this function. + + THE TELNET "SYNCH" SIGNAL + + Most time-sharing systems provide mechanisms which allow a + terminal user to regain control of a "runaway" process; the IP and + AO functions described above are examples of these mechanisms. + Such systems, when used locally, have access to all of the signals + supplied by the user, whether these are normal characters or + special "out of band" signals such as those supplied by the + teletype "BREAK" key or the IBM 2741 "ATTN" key. This is not + necessarily true when terminals are connected to the system + through the network; the network's flow control mechanisms may + cause such a signal to be buffered elsewhere, for example in the + user's host. + + + +Postel & Reynolds [Page 8] + + + +RFC 854 May 1983 + + + To counter this problem, the TELNET "Synch" mechanism is + introduced. A Synch signal consists of a TCP Urgent notification, + coupled with the TELNET command DATA MARK. The Urgent + notification, which is not subject to the flow control pertaining + to the TELNET connection, is used to invoke special handling of + the data stream by the process which receives it. In this mode, + the data stream is immediately scanned for "interesting" signals + as defined below, discarding intervening data. The TELNET command + DATA MARK (DM) is the synchronizing mark in the data stream which + indicates that any special signal has already occurred and the + recipient can return to normal processing of the data stream. + + The Synch is sent via the TCP send operation with the Urgent + flag set and the DM as the last (or only) data octet. + + When several Synchs are sent in rapid succession, the Urgent + notifications may be merged. It is not possible to count Urgents + since the number received will be less than or equal the number + sent. When in normal mode, a DM is a no operation; when in urgent + mode, it signals the end of the urgent processing. + + If TCP indicates the end of Urgent data before the DM is found, + TELNET should continue the special handling of the data stream + until the DM is found. + + If TCP indicates more Urgent data after the DM is found, it can + only be because of a subsequent Synch. TELNET should continue + the special handling of the data stream until another DM is + found. + + "Interesting" signals are defined to be: the TELNET standard + representations of IP, AO, and AYT (but not EC or EL); the local + analogs of these standard representations (if any); all other + TELNET commands; other site-defined signals which can be acted on + without delaying the scan of the data stream. + + Since one effect of the SYNCH mechanism is the discarding of + essentially all characters (except TELNET commands) between the + sender of the Synch and its recipient, this mechanism is specified + as the standard way to clear the data path when that is desired. + For example, if a user at a terminal causes an AO to be + transmitted, the server which receives the AO (if it provides that + function at all) should return a Synch to the user. + + Finally, just as the TCP Urgent notification is needed at the + TELNET level as an out-of-band signal, so other protocols which + make use of TELNET may require a TELNET command which can be + viewed as an out-of-band signal at a different level. + + +Postel & Reynolds [Page 9] + + + +RFC 854 May 1983 + + + By convention the sequence [IP, Synch] is to be used as such a + signal. For example, suppose that some other protocol, which uses + TELNET, defines the character string STOP analogously to the + TELNET command AO. Imagine that a user of this protocol wishes a + server to process the STOP string, but the connection is blocked + because the server is processing other commands. The user should + instruct his system to: + + 1. Send the TELNET IP character; + + 2. Send the TELNET SYNC sequence, that is: + + Send the Data Mark (DM) as the only character + in a TCP urgent mode send operation. + + 3. Send the character string STOP; and + + 4. Send the other protocol's analog of the TELNET DM, if any. + + The user (or process acting on his behalf) must transmit the + TELNET SYNCH sequence of step 2 above to ensure that the TELNET IP + gets through to the server's TELNET interpreter. + + The Urgent should wake up the TELNET process; the IP should + wake up the next higher level process. + + THE NVT PRINTER AND KEYBOARD + + The NVT printer has an unspecified carriage width and page length + and can produce representations of all 95 USASCII graphics (codes + 32 through 126). Of the 33 USASCII control codes (0 through 31 + and 127), and the 128 uncovered codes (128 through 255), the + following have specified meaning to the NVT printer: + + NAME CODE MEANING + + NULL (NUL) 0 No Operation + Line Feed (LF) 10 Moves the printer to the + next print line, keeping the + same horizontal position. + Carriage Return (CR) 13 Moves the printer to the left + margin of the current line. + + + + + + + + +Postel & Reynolds [Page 10] + + + +RFC 854 May 1983 + + + In addition, the following codes shall have defined, but not + required, effects on the NVT printer. Neither end of a TELNET + connection may assume that the other party will take, or will + have taken, any particular action upon receipt or transmission + of these: + + BELL (BEL) 7 Produces an audible or + visible signal (which does + NOT move the print head). + Back Space (BS) 8 Moves the print head one + character position towards + the left margin. + Horizontal Tab (HT) 9 Moves the printer to the + next horizontal tab stop. + It remains unspecified how + either party determines or + establishes where such tab + stops are located. + Vertical Tab (VT) 11 Moves the printer to the + next vertical tab stop. It + remains unspecified how + either party determines or + establishes where such tab + stops are located. + Form Feed (FF) 12 Moves the printer to the top + of the next page, keeping + the same horizontal position. + + All remaining codes do not cause the NVT printer to take any + action. + + The sequence "CR LF", as defined, will cause the NVT to be + positioned at the left margin of the next print line (as would, + for example, the sequence "LF CR"). However, many systems and + terminals do not treat CR and LF independently, and will have to + go to some effort to simulate their effect. (For example, some + terminals do not have a CR independent of the LF, but on such + terminals it may be possible to simulate a CR by backspacing.) + Therefore, the sequence "CR LF" must be treated as a single "new + line" character and used whenever their combined action is + intended; the sequence "CR NUL" must be used where a carriage + return alone is actually desired; and the CR character must be + avoided in other contexts. This rule gives assurance to systems + which must decide whether to perform a "new line" function or a + multiple-backspace that the TELNET stream contains a character + following a CR that will allow a rational decision. + + Note that "CR LF" or "CR NUL" is required in both directions + + +Postel & Reynolds [Page 11] + + + +RFC 854 May 1983 + + + (in the default ASCII mode), to preserve the symmetry of the + NVT model. Even though it may be known in some situations + (e.g., with remote echo and suppress go ahead options in + effect) that characters are not being sent to an actual + printer, nonetheless, for the sake of consistency, the protocol + requires that a NUL be inserted following a CR not followed by + a LF in the data stream. The converse of this is that a NUL + received in the data stream after a CR (in the absence of + options negotiations which explicitly specify otherwise) should + be stripped out prior to applying the NVT to local character + set mapping. + + The NVT keyboard has keys, or key combinations, or key sequences, + for generating all 128 USASCII codes. Note that although many + have no effect on the NVT printer, the NVT keyboard is capable of + generating them. + + In addition to these codes, the NVT keyboard shall be capable of + generating the following additional codes which, except as noted, + have defined, but not reguired, meanings. The actual code + assignments for these "characters" are in the TELNET Command + section, because they are viewed as being, in some sense, generic + and should be available even when the data stream is interpreted + as being some other character set. + + Synch + + This key allows the user to clear his data path to the other + party. The activation of this key causes a DM (see command + section) to be sent in the data stream and a TCP Urgent + notification is associated with it. The pair DM-Urgent is to + have required meaning as defined previously. + + Break (BRK) + + This code is provided because it is a signal outside the + USASCII set which is currently given local meaning within many + systems. It is intended to indicate that the Break Key or the + Attention Key was hit. Note, however, that this is intended to + provide a 129th code for systems which require it, not as a + synonym for the IP standard representation. + + Interrupt Process (IP) + + Suspend, interrupt, abort or terminate the process to which the + NVT is connected. Also, part of the out-of-band signal for + other protocols which use TELNET. + + + +Postel & Reynolds [Page 12] + + + +RFC 854 May 1983 + + + Abort Output (AO) + + Allow the current process to (appear to) run to completion, but + do not send its output to the user. Also, send a Synch to the + user. + + Are You There (AYT) + + Send back to the NVT some visible (i.e., printable) evidence + that the AYT was received. + + Erase Character (EC) + + The recipient should delete the last preceding undeleted + character or "print position" from the data stream. + + Erase Line (EL) + + The recipient should delete characters from the data stream + back to, but not including, the last "CR LF" sequence sent over + the TELNET connection. + + The spirit of these "extra" keys, and also the printer format + effectors, is that they should represent a natural extension of + the mapping that already must be done from "NVT" into "local". + Just as the NVT data byte 68 (104 octal) should be mapped into + whatever the local code for "uppercase D" is, so the EC character + should be mapped into whatever the local "Erase Character" + function is. Further, just as the mapping for 124 (174 octal) is + somewhat arbitrary in an environment that has no "vertical bar" + character, the EL character may have a somewhat arbitrary mapping + (or none at all) if there is no local "Erase Line" facility. + Similarly for format effectors: if the terminal actually does + have a "Vertical Tab", then the mapping for VT is obvious, and + only when the terminal does not have a vertical tab should the + effect of VT be unpredictable. + +TELNET COMMAND STRUCTURE + + All TELNET commands consist of at least a two byte sequence: the + "Interpret as Command" (IAC) escape character followed by the code + for the command. The commands dealing with option negotiation are + three byte sequences, the third byte being the code for the option + referenced. This format was chosen so that as more comprehensive use + of the "data space" is made -- by negotiations from the basic NVT, of + course -- collisions of data bytes with reserved command values will + be minimized, all such collisions requiring the inconvenience, and + + + +Postel & Reynolds [Page 13] + + + +RFC 854 May 1983 + + + inefficiency, of "escaping" the data bytes into the stream. With the + current set-up, only the IAC need be doubled to be sent as data, and + the other 255 codes may be passed transparently. + + The following are the defined TELNET commands. Note that these codes + and code sequences have the indicated meaning only when immediately + preceded by an IAC. + + NAME CODE MEANING + + SE 240 End of subnegotiation parameters. + NOP 241 No operation. + Data Mark 242 The data stream portion of a Synch. + This should always be accompanied + by a TCP Urgent notification. + Break 243 NVT character BRK. + Interrupt Process 244 The function IP. + Abort output 245 The function AO. + Are You There 246 The function AYT. + Erase character 247 The function EC. + Erase Line 248 The function EL. + Go ahead 249 The GA signal. + SB 250 Indicates that what follows is + subnegotiation of the indicated + option. + WILL (option code) 251 Indicates the desire to begin + performing, or confirmation that + you are now performing, the + indicated option. + WON'T (option code) 252 Indicates the refusal to perform, + or continue performing, the + indicated option. + DO (option code) 253 Indicates the request that the + other party perform, or + confirmation that you are expecting + the other party to perform, the + indicated option. + DON'T (option code) 254 Indicates the demand that the + other party stop performing, + or confirmation that you are no + longer expecting the other party + to perform, the indicated option. + IAC 255 Data Byte 255. + + + + + + + +Postel & Reynolds [Page 14] + + + +RFC 854 May 1983 + + +CONNECTION ESTABLISHMENT + + The TELNET TCP connection is established between the user's port U + and the server's port L. The server listens on its well known port L + for such connections. Since a TCP connection is full duplex and + identified by the pair of ports, the server can engage in many + simultaneous connections involving its port L and different user + ports U. + + Port Assignment + + When used for remote user access to service hosts (i.e., remote + terminal access) this protocol is assigned server port 23 + (27 octal). That is L=23. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Postel & Reynolds [Page 15] + diff --git a/src/hash.cpp b/src/hash.cpp index a207c29..9b8a1c1 100644 --- a/src/hash.cpp +++ b/src/hash.cpp @@ -2,26 +2,6 @@ namespace Bu { subExceptionDef( HashException ) } -template<> uint32_t Bu::__calcHashCode( const int &k ) -{ - return k; -} - -template<> bool Bu::__cmpHashKeys( const int &a, const int &b ) -{ - return a == b; -} - -template<> uint32_t Bu::__calcHashCode( const unsigned int &k ) -{ - return k; -} - -template<> bool Bu::__cmpHashKeys( const unsigned int &a, const unsigned int &b ) -{ - return a == b; -} - template<> uint32_t Bu::__calcHashCode( const char * const &k ) { diff --git a/src/hash.h b/src/hash.h index 62b19c9..be57786 100644 --- a/src/hash.h +++ b/src/hash.h @@ -1008,12 +1008,16 @@ namespace Bu challoc ca; sizecalc szCalc; }; + + template uint32_t __calcHashCode( const T &k ) + { + return static_cast( k ); + } - template<> uint32_t __calcHashCode( const int &k ); - template<> bool __cmpHashKeys( const int &a, const int &b ); - - template<> uint32_t __calcHashCode( const unsigned int &k ); - template<> bool __cmpHashKeys( const unsigned int &a, const unsigned int &b ); + template bool __cmpHashKeys( const T &a, const T &b ) + { + return (a == b); + } template<> uint32_t __calcHashCode( const char * const &k ); template<> bool __cmpHashKeys( const char * const &a, const char * const &b ); diff --git a/src/protocolhttp.h b/src/protocolhttp.h index e2612f5..85510e3 100644 --- a/src/protocolhttp.h +++ b/src/protocolhttp.h @@ -11,7 +11,14 @@ namespace Bu { /** - * + * An HTTP Protocol handler. Yes, I know that HTTP stands for Hyper Text + * Transfer Protocol, and that the Protocol part is redundant, but in this + * case the word Protocol is refering to the Libbu++ construct Bu::Protocol, + * and not a means of encoding conversations. Anyway, this class represents + * a general HTTP server processor. Every time a request comes in it calls + * the onRequest function in a subclass with the method and URI that were + * requested. The sub-class can then do whatever it needs to to send back + * a response. */ class ProtocolHttp : public Protocol { diff --git a/src/protocoltelnet.cpp b/src/protocoltelnet.cpp index b0209db..e4fc926 100644 --- a/src/protocoltelnet.cpp +++ b/src/protocoltelnet.cpp @@ -1,30 +1,69 @@ #include "bu/protocoltelnet.h" #include "bu/client.h" -#define CODE_SE '\xf0' /**< End of subnegotiation params. */ -#define CODE_NOP '\xf1' /**< No operation (keep-alive). */ -#define CODE_DM '\xf2' /**< Datastream side of a Synch. */ -#define CODE_BRK '\xf3' /**< Break character. */ -#define CODE_IP '\xf4' /**< Interrupt Process character. */ -#define CODE_AO '\xf5' /**< Abort Output character. */ -#define CODE_AYT '\xf6' /**< Are You There? character. */ -#define CODE_EC '\xf7' /**< Erase Character character. */ -#define CODE_EL '\xf8' /**< Erase Line character. */ -#define CODE_GA '\xf9' /**< Go Ahead signal. */ -#define CODE_SB '\xfa' /**< Begin subnegotiation options. */ -#define CODE_WILL '\xfb' /**< Desire to do something. */ -#define CODE_WONT '\xfc' /**< Refuse to perform. */ -#define CODE_DO '\xfd' /**< Request option. */ -#define CODE_DONT '\xfe' /**< Demand a stop. */ - -#define CODE_IAC '\xff' /**< Interpret-As-Command. */ - -#define OPT_BINARY '\x00' /**< Binary mode (file transfers?). */ -#define OPT_ECHO '\x01' /**< (local) Echo mode. */ +/* We apparently at least want defs for the lower 13, not sure we care about + * the rest of the chars, maybe escape. + */ +#define CH_NUL '\x00' /* NUL */ +#define CH_SOH '\x01' /* Start Of Heading */ +#define CH_STX '\x02' /* Start of Text */ +#define CH_ETX '\x03' /* End of Text */ +#define CH_EOT '\x04' /* End of transmission */ +#define CH_ENQ '\x05' /* Enquiery */ +#define CH_ACK '\x06' /* Acknowledge */ +#define CH_BEL '\x07' /* Bell */ +#define CH_BS '\x08' /* Backspace */ +#define CH_TAB '\x09' /* Horizontal Tab */ +#define CH_LF '\x0A' /* NL Line feed, new line */ +#define CH_VT '\x0B' /* Vertical Tab */ +#define CH_FF '\x0C' /* Form feed, new page */ +#define CH_CR '\x0D' /* Carriage return */ +#define CH_ESC '\x1B' /* Escape */ +#define CH_DEL '\x7F' /* Delete */ + +#define CODE_SE '\xf0' /* End of subnegotiation params. */ +#define CODE_NOP '\xf1' /* No operation (keep-alive). */ +#define CODE_DM '\xf2' /* Datastream side of a Synch. */ +#define CODE_BRK '\xf3' /* Break character. */ +#define CODE_IP '\xf4' /* Interrupt Process character. */ +#define CODE_AO '\xf5' /* Abort Output character. */ +#define CODE_AYT '\xf6' /* Are You There? character. */ +#define CODE_EC '\xf7' /* Erase Character character. */ +#define CODE_EL '\xf8' /* Erase Line character. */ +#define CODE_GA '\xf9' /* Go Ahead signal. */ +#define CODE_SB '\xfa' /* Begin subnegotiation options. */ +#define CODE_WILL '\xfb' /* Desire to do something. */ +#define CODE_WONT '\xfc' /* Refuse to perform. */ +#define CODE_DO '\xfd' /* Request option. */ +#define CODE_DONT '\xfe' /* Demand a stop. */ + +#define CODE_IAC '\xff' /* Interpret-As-Command. */ + +#define OPT_BINARY '\x00' /* Binary mode (file transfers?). */ +#define OPT_ECHO '\x01' /* (local) Echo mode. */ +#define OPT_SUPGA '\x03' /* Suppress Go Ahead signals. */ +#define OPT_STATUS '\x05' /* Allow status messages. */ +#define OPT_TIMING '\x06' /* Place a timing mark in the code. */ +#define OPT_EXASCII '\x11' /* Extended ASCII. */ +#define OPT_LOGOUT '\x12' /* Logout. */ +#define OPT_TTYPE '\x18' /* Terminal Type. */ +#define OPT_NAWS '\x1f' /* Negotiate about window size. */ +#define OPT_TSPEED '\x20' /* Terminal Speed. */ +#define OPT_NEWENV '\x27' /* New Environment Option. */ +#define OPT_EXOPL '\xff' /* Can we, will we, handle extended options. */ + +#ifndef __TELNET_DEBUG +# define printCode( a ) (void)0 +# define printOpt( a ) (void)0 +#endif Bu::ProtocolTelnet::ProtocolTelnet() : oBinary( *this, OPT_BINARY ), - oEcho( *this, OPT_ECHO ) + oEcho( *this, OPT_ECHO ), + oNAWS( *this, OPT_NAWS ), + oSuppressGA(*this, OPT_SUPGA ), + bCanonical( true ), + bSubOpt( false ) { } @@ -34,13 +73,410 @@ Bu::ProtocolTelnet::~ProtocolTelnet() void Bu::ProtocolTelnet::onNewConnection( Bu::Client *pClient ) { + this->pClient = pClient; } void Bu::ProtocolTelnet::onNewData( Bu::Client *pClient ) { + char bc; + int iLeft; + while( (iLeft = pClient->getInputSize()) ) + { + if( bSubOpt ) + { + pClient->peek( &bc, 1 ); + if( bc == CODE_IAC ) + { + if( iLeft <= 1 ) return; + char bc2; + printCode( CODE_IAC ); + pClient->peek( &bc2, 1, 1 ); + printCode( bc2 ); + if( bc2 == CODE_SE ) + { + bSubOpt = false; + onSubOpt(); + } + else if( bc2 == CODE_IAC ) + { + sSubBuf += CODE_IAC; + } + else + { + // Error of some sort. + } + pClient->seek( 1 ); + } + else + { + sSubBuf += bc; + } + pClient->seek( 1 ); + } + else + { + pClient->peek( &bc, 1 ); + if( bc == CODE_IAC ) + { + if( iLeft <= 1 ) return; + char bc2; + pClient->peek( &bc2, 1, 1 ); + printCode( bc ); + printCode( bc2 ); + + switch( bc2 ) + { + case CODE_WILL: + if( iLeft <= 2 ) return; + { + char bc3; + pClient->peek( &bc3, 1, 2 ); + pClient->seek( 1 ); + printOpt( bc3 ); + onWill( bc3 ); + } + break; + + case CODE_WONT: + if( iLeft <= 2 ) return; + { + char bc3; + pClient->peek( &bc3, 1, 2 ); + pClient->seek( 1 ); + printOpt( bc3 ); + onWont( bc3 ); + } + break; + + case CODE_DO: + if( iLeft <= 2 ) return; + { + char bc3; + pClient->peek( &bc3, 1, 2 ); + pClient->seek( 1 ); + printOpt( bc3 ); + onDo( bc3 ); + } + break; + + case CODE_DONT: + if( iLeft <= 2 ) return; + { + char bc3; + pClient->peek( &bc3, 1, 2 ); + pClient->seek( 1 ); + printOpt( bc3 ); + onDont( bc3 ); + } + break; + + case CODE_SB: + if( iLeft <= 2 ) return; + { + pClient->peek( &cSubOpt, 1, 2 ); + pClient->seek( 1 ); + printOpt( cSubOpt ); + bSubOpt = true; + } + break; + + case CODE_IAC: + sDataBuf += CODE_IAC; + printCode( CODE_IAC ); + break; + } + pClient->seek( 1 ); +#ifdef __TELNET_DEBUG + printf("\n"); +#endif + } + else if( bc == CODE_SB ) + { + } + else + { + // This is where control code handling goes + // Also, possibly, character code conversion, although I'm not + // sure that really matters anymore, go ASCII/UTF-8 + if( bCanonical ) + { + if( bc < 0x20 || bc >= CH_DEL ) + { + if( bc == CH_CR ) + { + if( iLeft <= 1 ) return; + char bc2; + pClient->peek( &bc2, 1, 1 ); + if( bc2 == CH_NUL || bc2 == CH_LF ) + { + onCtlChar( bc ); + gotLine( sDataBuf ); + sDataBuf.clear(); + } + pClient->seek( 1 ); + } + else + { + onCtlChar( bc ); + } + } + else + { + sDataBuf += bc; + if( oEcho.isLocalSet() ) + { + pClient->write( &bc, 1 ); +#ifdef __TELNET_DEBUG + printf("%c", bc ); + fflush( stdout ); +#endif + } + } + } + else + { + sDataBuf += bc; + if( oEcho.isLocalSet() ) + { + pClient->write( &bc, 1 ); + } + } + } + pClient->seek( 1 ); + } + } + + // It's true, this code will not be executed if we only have half of an + // IAC code or multibyte escape sequence or something, but then again, it + // shouldn't be called then, and really, shouldn't be, it'll be called soon + // enough, when we get the rest of that code. + if( !bCanonical ) + { + gotData( sDataBuf ); + } +} + +void Bu::ProtocolTelnet::setCanonical( bool bCon ) +{ + bCanonical = bCon; +} + +bool Bu::ProtocolTelnet::isCanonical() +{ + return bCanonical; +} + +void Bu::ProtocolTelnet::write( const Bu::FString &sData ) +{ + pClient->write( sData ); +} + +void Bu::ProtocolTelnet::write( char *pData, int iSize ) +{ + pClient->write( pData, iSize ); +} + +void Bu::ProtocolTelnet::write( char cData ) +{ + pClient->write( &cData, 1 ); +} + +void Bu::ProtocolTelnet::onWill( char cCode ) +{ + try + { + Option *pOpt = hOpts[cCode]; + if( pOpt->isRemoteEnabled() ) + { + pOpt->fOpts |= Option::fRemoteIs; + char buf[3] = { CODE_IAC, CODE_DO, cCode }; + pClient->write( buf, 3 ); + } + else + { + char buf[3] = { CODE_IAC, CODE_DONT, cCode }; + pClient->write( buf, 3 ); + } + + } + catch( Bu::HashException &e ) + { + char buf[3] = { CODE_IAC, CODE_DONT, cCode }; + pClient->write( buf, 3 ); + } +} + +void Bu::ProtocolTelnet::onWont( char cCode ) +{ + try + { + Option *pOpt = hOpts[cCode]; + + pOpt->fOpts &= ~Option::fRemoteIs; + char buf[3] = { CODE_IAC, CODE_DONT, cCode }; + pClient->write( buf, 3 ); + } + catch( Bu::HashException &e ) + { + char buf[3] = { CODE_IAC, CODE_DONT, cCode }; + pClient->write( buf, 3 ); + } +} + +void Bu::ProtocolTelnet::onDo( char cCode ) +{ + try + { + Option *pOpt = hOpts[cCode]; + if( pOpt->isLocalEnabled() ) + { + pOpt->fOpts |= Option::fLocalIs; + char buf[3] = { CODE_IAC, CODE_WILL, cCode }; + pClient->write( buf, 3 ); + } + else + { + char buf[3] = { CODE_IAC, CODE_WONT, cCode }; + pClient->write( buf, 3 ); + } + + } + catch( Bu::HashException &e ) + { + char buf[3] = { CODE_IAC, CODE_WONT, cCode }; + pClient->write( buf, 3 ); + } +} + +void Bu::ProtocolTelnet::onDont( char cCode ) +{ + try + { + Option *pOpt = hOpts[cCode]; + + pOpt->fOpts &= ~Option::fLocalIs; + char buf[3] = { CODE_IAC, CODE_DONT, cCode }; + pClient->write( buf, 3 ); + } + catch( Bu::HashException &e ) + { + char buf[3] = { CODE_IAC, CODE_DONT, cCode }; + pClient->write( buf, 3 ); + } } +void Bu::ProtocolTelnet::onSubOpt() +{ + switch( cSubOpt ) + { + case OPT_NAWS: + { + uint16_t iWidth, iHeight; + ((char *)&iWidth)[1] = sSubBuf[0]; + ((char *)&iWidth)[0] = sSubBuf[1]; + ((char *)&iHeight)[1] = sSubBuf[2]; + ((char *)&iHeight)[0] = sSubBuf[3]; + onSubNAWS( iWidth, iHeight ); + } + break; + default: + onSubUnknown( cSubOpt, sSubBuf ); + break; + } + + sSubBuf.clear(); +} + +void Bu::ProtocolTelnet::onCtlChar( char cChr ) +{ +#ifdef __TELNET_DEBUG + switch( cChr ) + { + case CH_NUL: printf("NUL "); break; + case CH_SOH: printf("SOH "); break; + case CH_STX: printf("STX "); break; + case CH_ETX: printf("ETX "); break; + case CH_EOT: printf("EOT "); break; + case CH_ENQ: printf("ENQ "); break; + case CH_ACK: printf("ACK "); break; + case CH_BEL: printf("BEL "); break; + case CH_BS: printf("BS "); break; + case CH_TAB: printf("TAB "); break; + case CH_LF: printf("LF "); break; + case CH_VT: printf("VT "); break; + case CH_FF: printf("FF "); break; + case CH_CR: printf("CR "); break; + case CH_ESC: printf("ESC "); break; + case CH_DEL: printf("DEL "); break; + default: printf("!![%02x] ", cChr ); break; + } + fflush( stdout ); +#endif + + switch( cChr ) + { + case CH_DEL: + { + if( sDataBuf.getSize() > 0 ) + { + sDataBuf.resize( sDataBuf.getSize()-1 ); + char buf[3] = { CH_BS, ' ', CH_BS }; + pClient->write( buf, 3 ); + } + } + break; + + } +} + +#ifdef __TELNET_DEBUG +void Bu::ProtocolTelnet::printCode( char cCode ) +{ + switch( cCode ) + { + case CODE_SE: printf("SE "); break; + case CODE_NOP: printf("NOP "); break; + case CODE_DM: printf("DM "); break; + case CODE_BRK: printf("BRK "); break; + case CODE_IP: printf("IP "); break; + case CODE_AO: printf("AO "); break; + case CODE_AYT: printf("AYT "); break; + case CODE_EC: printf("EC "); break; + case CODE_EL: printf("EL "); break; + case CODE_GA: printf("GA "); break; + case CODE_SB: printf("SB "); break; + case CODE_WILL: printf("WILL "); break; + case CODE_WONT: printf("WONT "); break; + case CODE_DO: printf("DO "); break; + case CODE_DONT: printf("DONT "); break; + case CODE_IAC: printf("IAC "); break; + default: printf("??%02x ", cCode ); break; + } + fflush( stdout ); +} + +void Bu::ProtocolTelnet::printOpt( char cOpt ) +{ + switch( cOpt ) + { + case OPT_BINARY: printf("BINARY "); break; + case OPT_ECHO: printf("ECHO "); break; + case OPT_SUPGA: printf("SUPGA "); break; + case OPT_STATUS: printf("STATUS "); break; + case OPT_TIMING: printf("TIMING "); break; + case OPT_EXASCII: printf("EXASCII "); break; + case OPT_LOGOUT: printf("LOGOUT "); break; + case OPT_TTYPE: printf("TTYPE "); break; + case OPT_NAWS: printf("NAWS "); break; + case OPT_TSPEED: printf("TSPEED "); break; + case OPT_NEWENV: printf("NEWENV "); break; + case OPT_EXOPL: printf("EXOPL "); break; + default: printf("??%02x ", cOpt); break; + } + fflush( stdout ); +} +#endif Bu::ProtocolTelnet::Option::Option( Bu::ProtocolTelnet &rPT, char cCode ) : rPT( rPT ), @@ -68,19 +504,31 @@ void Bu::ProtocolTelnet::Option::localSet( bool bSet ) { if( bSet == (bool)(fOpts&fLocalIs) ) return; - char buf[2]; + char buf[3] = { CODE_IAC, 0, cCode }; if( bSet ) { - buf[0] = CODE_WILL; - buf[1] = cCode; - rPT.pClient->write( buf, 2 ); + buf[1] = CODE_WILL; + rPT.pClient->write( buf, 3 ); +#ifdef __TELNET_DEBUG + printf("<= "); + rPT.printCode( buf[0] ); + rPT.printCode( buf[1] ); + rPT.printOpt( buf[2] ); + printf("\n"); +#endif } else { - buf[0] = CODE_WONT; - buf[1] = cCode; - rPT.pClient->write( buf, 2 ); + buf[1] = CODE_WONT; + rPT.pClient->write( buf, 3 ); +#ifdef __TELNET_DEBUG + printf("<= "); + rPT.printCode( buf[0] ); + rPT.printCode( buf[1] ); + rPT.printOpt( buf[2] ); + printf("\n"); +#endif } } @@ -101,21 +549,33 @@ void Bu::ProtocolTelnet::Option::remoteEnable( bool bSet ) void Bu::ProtocolTelnet::Option::remoteSet( bool bSet ) { - if( bSet == (bool)(fOpts&fRemoteIs) ) return; + //if( bSet == (bool)(fOpts&fRemoteIs) ) return; - char buf[2]; + char buf[3] = { CODE_IAC, 0, cCode }; if( bSet ) { - buf[0] = CODE_DO; - buf[1] = cCode; - rPT.pClient->write( buf, 2 ); + buf[1] = CODE_DO; + rPT.pClient->write( buf, 3 ); +#ifdef __TELNET_DEBUG + printf("<= "); + rPT.printCode( buf[0] ); + rPT.printCode( buf[1] ); + rPT.printOpt( buf[2] ); + printf("\n"); +#endif } else { - buf[0] = CODE_DONT; - buf[1] = cCode; - rPT.pClient->write( buf, 2 ); + buf[1] = CODE_DONT; + rPT.pClient->write( buf, 3 ); +#ifdef __TELNET_DEBUG + printf("<= "); + rPT.printCode( buf[0] ); + rPT.printCode( buf[1] ); + rPT.printOpt( buf[2] ); + printf("\n"); +#endif } } diff --git a/src/protocoltelnet.h b/src/protocoltelnet.h index 3a606b5..f773f1e 100644 --- a/src/protocoltelnet.h +++ b/src/protocoltelnet.h @@ -3,35 +3,131 @@ #include "bu/protocol.h" #include "bu/hash.h" +#include "bu/fstring.h" + +// #define __TELNET_DEBUG namespace Bu { + /** + * Telnet Protocol handler. This attempts to provide useful and general + * support for most of the most commonly used Telnet extensions in a simple + * and easy to use way. The Option variables control the settings that can + * be used on the line, and control which virtual "callbacks" will be called + * when different events happen. + * + * To setup initial values and to disable any options you wish override the + * onNewConnection function in your own class, like this: + *@code + class MyTelnet : public Bu::ProtocolTelnet + { + public: + ... + + virtual void onNewConnection( class Bu::Client *pClient ) + { + // Call the parent class' onNewConnection to get everything all + // set up. + Bu::ProtocolTelnet::onNewConnection( pClient ); + + // These functions disable the option to send files via telnet, + // disabling the remote option means that we won't accept this + // option (binary data being sent to us) from the client. + // + // Disabling the local option means that the client cannot ask us + // to send them binary data. + oBinary.enableRemote( false ); + oBinary.enableLocal( false ); + + // This requests that the client send us window size updates + // whenever the size of their window changes, and an initial set to + // boot. + // + // To see if this option is set later, try oNAWS.isRemoteSet(), but + // wait a little while, asking immediatly will always return false, + // since the remote side has yet to receive our request. + oNAWS.remoteSet(); + } + } + @endcode + * + */ class ProtocolTelnet : public Protocol { public: ProtocolTelnet(); virtual ~ProtocolTelnet(); + /** + * If you override this function in a child class, make sure to call + * this version of it as the very first thing that you do, before you + * set any options. See the example in the class docs. + */ virtual void onNewConnection( class Bu::Client *pClient ); + + /** + * You should never override this function unless you really, really + * know what you're doing. If you want to get data after each line + * entered (in canonical mode) or after any data arrives (non canonical + * mode) then override the gotLine and gotData functions, respectively. + */ virtual void onNewData( class Bu::Client *pClient ); - enum OptMode - { - optOff, - optOn, - optDesire, - optRefuse - }; + /** + * Override this function to be notified of lines being submitted by + * the client. This function is only called in canonical mode, after + * all edits are performed on the data. In this mode weather you use + * the line or not, the data will be cleared from the buffer when this + * function returns, any changes made to the buffer will be destroyed. + */ + virtual void gotLine( Bu::FString &sLine ){}; - OptMode getLocalOptBinary(); - void setLocalOptBinary( OptMode eMode ); - OptMode getRemoteOptBinary(); - void setRemoteOptBinary( OptMode eMode ); + /** + * Override this function to be notified of any new data that comes in + * from the client. This function is only called in non-canonical mode, + * and includes all raw data minus telnet control codes and ansi + * escape sequences. In this mode control of the buffer is up to the + * child class in this function, the buffer will never be cleared unless + * it happens in this function's override. + */ + virtual void gotData( Bu::FString &sData ){}; - OptMode getLocalOptEcho(); - void setLocalOptEcho( OptMode eMode ); - OptMode getRemoteOptEcho(); - void setRemoteOptEcho( OptMode eMode ); + /** + * Using this function to enable or disable canonical mode only affects + * the way the data is processed and which virtual functions are called + * during processing. It does not affect options set locally or + * remotely. Setting this to false will enable char-at-a-time mode, + * effectively disabling internal line-editing code. Characters + * such as backspace that are detected will not be handled and will be + * sent to the user override. The subclass will also be notified every + * time new data is available, not just whole lines. + * + * When set to true (the default), line editing control codes will be + * interpreted and used, and the subclass will only be notified when + * complete lines are available in the buffer. + */ + void setCanonical( bool bCon=true ); + bool isCanonical(); + + void write( const Bu::FString &sData ); + void write( char *pData, int iSize ); + void write( char cData ); + + public: + /** + * If you wish to know the current dimensions of the client window, + * override this function, it will be called whenever the size changes. + */ + virtual void onSubNAWS( uint16_t iWidth, uint16_t iHeight ){}; + + /** + * This function is called whenever an unknown sub negotiation option is + * sent over the line. This doesn't mean that it's malformatted, it + * just means that this class doesn't support that option yet, but you + * can handle it yourself if you'd like. Feel free to change the + * sSubBuf, it will be cleared as soon as this function returns anyway. + */ + virtual void onSubUnknown( char cSubOpt, Bu::FString &sSubBuf ){}; private: /** @@ -75,15 +171,38 @@ namespace Bu char fOpts; char cCode; }; + friend class Bu::ProtocolTelnet::Option; Hash hOpts; + public: Option oBinary; Option oEcho; + Option oNAWS; + Option oSuppressGA; + private: + void onWill( char cCode ); + void onWont( char cCode ); + void onDo( char cCode ); + void onDont( char cCode ); + void onSubOpt(); + void onCtlChar( char cChr ); + +#ifdef __TELNET_DEBUG + void printCode( char cCode ); + void printOpt( char cOpt ); +#endif + + private: Client *pClient; - friend class Bu::ProtocolTelnet::Option; + Bu::FString sDataBuf; /**< Buffer for regular line data. */ + Bu::FString sSubBuf; /**< Buffer for subnegotiation data. */ + char cSubOpt; /**< Which suboption are we processing. */ + + bool bCanonical; /**< Are we canonicalizing incoming data? */ + bool bSubOpt; /**< Are we processing a suboption right now? */ }; } diff --git a/src/tests/telnetsrv.cpp b/src/tests/telnetsrv.cpp new file mode 100644 index 0000000..39e3217 --- /dev/null +++ b/src/tests/telnetsrv.cpp @@ -0,0 +1,85 @@ +#include "bu/server.h" +#include "bu/protocoltelnet.h" +#include "bu/client.h" + +class MyTelnet : public Bu::ProtocolTelnet +{ +public: + MyTelnet() + { + } + + virtual ~MyTelnet() + { + } + + virtual void onNewConnection( Bu::Client *pClient ) + { + Bu::ProtocolTelnet::onNewConnection( pClient ); + + //oNAWS.remoteSet(); + oEcho.localSet(); + oSuppressGA.remoteSet( true ); + oSuppressGA.localSet( true ); + setCanonical(); + } + + virtual void onSubNAWS( uint16_t iWidth, uint16_t iHeight ) + { + printf("New dim = (%dx%d)\n", iWidth, iHeight ); + } + + virtual void gotLine( Bu::FString &sLine ) + { + printf("Line: \"%s\"\n", sLine.getStr() ); + write("\n\r", 2 ); + } + +private: + +}; + +class TelServer : public Bu::Server +{ +public: + TelServer() + { + } + + virtual ~TelServer() + { + } + + virtual void onNewConnection( Bu::Client *pClient, int iPort ) + { + printf("New connection.\n"); + + pClient->setProtocol( new MyTelnet() ); + } + + virtual void onClosedConnection( Bu::Client *pClient ) + { + printf("Lost connection.\n"); + + delete pClient->getProtocol(); + } + +private: + +}; + +int main( int argc, char *argv[] ) +{ + TelServer ts; + + ts.addPort( 4000 ); + ts.setTimeout( 0, 5000 ); + + printf("Initializing server on port: 4000\n"); + + for(;;) + { + ts.scan(); + } +} + -- cgit v1.2.3