Utils/Termlib: Fix handling of very narrow windows
[senf.git] / Utils / Termlib / Telnet.hh
1 // $Id$
2 //
3 // Copyright (C) 2008 
4 // Fraunhofer Institute for Open Communication Systems (FOKUS)
5 // Competence Center NETwork research (NET), St. Augustin, GERMANY
6 //     Stefan Bund <g0dil@berlios.de>
7 //
8 // This program is free software; you can redistribute it and/or modify
9 // it under the terms of the GNU General Public License as published by
10 // the Free Software Foundation; either version 2 of the License, or
11 // (at your option) any later version.
12 //
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 // GNU General Public License for more details.
17 //
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the
20 // Free Software Foundation, Inc.,
21 // 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22
23 /** \file
24     \brief Telnet public header */
25
26 #ifndef HH_SENF_Scheduler_Console_Telnet_
27 #define HH_SENF_Scheduler_Console_Telnet_ 1
28
29 // Custom includes
30 #include <vector>
31 #include <map>
32 #include <senf/Socket.hh>
33 #include <senf/Scheduler/Scheduler.hh>
34 #include <senf/Scheduler/ClockService.hh>
35
36 //#include "Telnet.mpp"
37 ///////////////////////////////hh.p////////////////////////////////////////
38
39 namespace senf {
40 namespace term {
41
42     /** \brief  Telnet server
43
44         \see 
45             <a href="http://tools.ietf.org/html/rfc854">RFC 854</a> The Telnet protocol \n
46             <a href="http://tools.ietf.org/html/rfc854">RFC 855</a> Telnet option specifications
47
48         \todo SYNCH handling
49      */
50     class BaseTelnetProtocol
51     {
52     public:
53         static unsigned const DEFAULT_REQUEST_TIMEOUT_MS = 500u;
54
55         typedef ClientSocketHandle<senf::MakeSocketPolicy<
56             ConnectedCommunicationPolicy, 
57             StreamFramingPolicy, 
58             ReadablePolicy,
59             WriteablePolicy>::policy> Handle;
60
61         typedef unsigned char option_type;
62
63         struct TelnetHandler;
64
65         void write(std::string const & s);
66         void write(char c);
67
68         Handle handle();
69
70         void sendNOP();
71         void sendBRK();
72         void sendIP();
73         void sendAO();
74         void sendAYT();
75         void sendEC();
76         void sendEL();
77         void sendGA();
78         
79         void sendOptionParameters(option_type option, std::string const & data);
80
81         void requestLocalOption(option_type option, bool enabled = true);
82         void acceptLocalOption(option_type option, bool enabled = true);
83
84         void requestPeerOption(option_type option, bool enabled = true);
85         void acceptPeerOption(option_type option, bool enabled = true);
86
87         bool localOption(option_type option);
88         bool peerOption(option_type option);
89         
90     protected:
91         explicit BaseTelnetProtocol(Handle handle);
92         BaseTelnetProtocol();
93         virtual ~BaseTelnetProtocol();
94
95         template <class Handler>
96         void registerHandler(Handler * h, bool request=true);
97
98         void incrementRequestCounter();
99         void decrementRequestCounter();
100         bool requestsPending();
101
102 #ifndef DOXYGEN
103     private:
104 #endif
105         virtual void v_setupComplete() = 0;
106         virtual void v_charReceived(char c) = 0;
107         virtual void v_eof() = 0;
108
109         virtual void v_handleNOP();
110         virtual void v_handleBRK();
111         virtual void v_handleIP();
112         virtual void v_handleAO();
113         virtual void v_handleAYT();
114         virtual void v_handleEC();
115         virtual void v_handleEL();
116         virtual void v_handleGA();
117         
118 #ifdef DOXYGEN
119     private:
120 #endif
121         void handleChar(char c);
122         void handleNormalChar(char c);
123         void handleCommand(char c);
124         void handleOption(char c);
125         void handleCR(char c);
126         void handleSBOption(char c);
127         void handleSBData(char c);
128         void handleSBIAC(char c);
129         void emit(char c);
130         void processCommand();
131         void transmit(char c);
132
133         void sendWILL(char option);
134         void sendWONT(char option);
135         void sendDO(char option);
136         void sendDONT(char option);
137
138         void readHandler(int state);
139         void writeHandler(int state);
140         void timeout();
141
142         enum Command { 
143             CMD_NONE = 0,
144             CMD_SE = 240,
145             CMD_NOP = 241,
146             CMD_DM = 242,
147             CMD_BRK = 243,
148             CMD_IP = 244,
149             CMD_AO = 245,
150             CMD_AYT = 246,
151             CMD_EC = 247,
152             CMD_EL = 248,
153             CMD_GA = 249,
154             CMD_SB = 250,
155             CMD_WILL = 251,
156             CMD_WONT = 252,
157             CMD_DO = 253,
158             CMD_DONT = 254,
159             CMD_IAC = 255,
160         };
161
162         struct OptInfo
163         {
164             enum WantState { WANTED, ACCEPTED, DISABLED };
165             enum OptionState { NONE, REQUEST_SENT, ACKNOWLEDGED };
166
167             OptInfo();
168             OptInfo(bool local, option_type option);
169
170             ///////////////////////////////////////////////////////////////
171
172             bool const local;
173             option_type const option;
174
175             WantState wantState;
176             OptionState optionState;
177             bool enabled;
178             
179         };
180
181         OptInfo & getOption(bool local, option_type option);
182         void request(OptInfo & info, bool enabled);
183         void response(OptInfo & info, bool enabled);
184
185         typedef std::map<std::pair<bool, option_type>, OptInfo> OptionsMap;
186         OptionsMap options_;
187
188         typedef std::map<option_type, TelnetHandler*> OptionHandlerMap;
189         OptionHandlerMap handlers_;
190
191         Handle handle_;
192
193         typedef std::vector<char> SendQueue;
194         SendQueue sendQueue_;
195
196         enum CharState { NORMAL, IAC_SEEN, EXPECT_OPTION, CR_SEEN, 
197                          SB_OPTION, SB_DATA, SB_IAC_SEEN };
198         CharState charState_;
199
200         Command command_;
201         option_type option_;
202         std::string data_;
203
204         senf::scheduler::FdEvent inputEvent_;
205         senf::scheduler::FdEvent outputEvent_;
206
207         unsigned pendingRequests_;
208
209         ClockService::clock_type requestTimeout_;
210         scheduler::TimerEvent timeout_;
211
212         friend class TelnetHandler;
213     };
214
215     struct BaseTelnetProtocol::TelnetHandler
216         : public virtual BaseTelnetProtocol
217     {
218         virtual ~TelnetHandler();
219         virtual void v_init() = 0;
220         virtual void v_handleOptionParameters(std::string const & data) = 0;
221     };
222
223     // See http://www.iana.org/assignments/telnet-options for a list of options
224     namespace telnetopt { BaseTelnetProtocol::option_type const ECHO = 1u; }
225     namespace telnetopt { BaseTelnetProtocol::option_type const TRANSMIT_BINARY = 0u; }
226     namespace telnetopt { BaseTelnetProtocol::option_type const SUPPRESS_GO_AHEAD = 3u; }
227     namespace telnetopt { BaseTelnetProtocol::option_type const TERMINAL_TYPE = 24u; }
228     namespace telnetopt { BaseTelnetProtocol::option_type const NAWS = 31u; }
229     namespace telnetopt { BaseTelnetProtocol::option_type const LINEMODE = 34u; }
230
231 namespace telnethandler {
232
233     class TerminalType
234         : public BaseTelnetProtocol::TelnetHandler
235     {
236     public:
237         static option_type const OPTION_CODE = telnetopt::TERMINAL_TYPE;
238
239         void nextTerminalType();
240         std::string const & terminalType() const;
241         
242     protected:
243         TerminalType();
244
245     private:
246         virtual void v_init();
247         virtual void v_handleOptionParameters(std::string const & data);
248
249         std::string type_;
250     };
251
252     class NAWS 
253         : public BaseTelnetProtocol::TelnetHandler
254     {
255     public:
256         static option_type const OPTION_CODE = telnetopt::NAWS;
257
258         unsigned width() const;
259         unsigned height() const;
260
261     protected:
262         NAWS();
263         
264     private:
265         virtual void v_windowSizeChanged() = 0;
266
267         virtual void v_init();
268         virtual void v_handleOptionParameters(std::string const & data);
269
270         unsigned width_;
271         unsigned height_;
272     };
273     
274 }
275
276 }}
277
278 ///////////////////////////////hh.e////////////////////////////////////////
279 #include "Telnet.cci"
280
281 //#include "Telnet.ct"
282 #include "Telnet.cti"
283 #endif
284
285 \f
286 // Local Variables:
287 // mode: c++
288 // fill-column: 100
289 // comment-column: 40
290 // c-file-style: "senf"
291 // indent-tabs-mode: nil
292 // ispell-local-dictionary: "american"
293 // compile-command: "scons -u test"
294 // End: