1 #include "NativeFeatureIncludes.h"
2 #if _RAKNET_SUPPORT_TelnetTransport==1
3
4 #include "TelnetTransport.h"
5 #include "TCPInterface.h"
6 #include <stdio.h>
7 #include <string.h>
8 #include <stdarg.h>
9 #include "LinuxStrings.h"
10
11 // #define _PRINTF_DEBUG
12
13 #define ECHO_INPUT
14
15 #ifdef _MSC_VER
16 #pragma warning( push )
17 #endif
18
TelnetTransport()19 TelnetTransport::TelnetTransport()
20 {
21 tcpInterface=0;
22 sendSuffix=0;
23 sendPrefix=0;
24 }
~TelnetTransport()25 TelnetTransport::~TelnetTransport()
26 {
27 Stop();
28 if (sendSuffix)
29 rakFree_Ex(sendSuffix, __FILE__, __LINE__ );
30 if (sendPrefix)
31 rakFree_Ex(sendPrefix, __FILE__, __LINE__ );
32 }
Start(unsigned short port,bool serverMode)33 bool TelnetTransport::Start(unsigned short port, bool serverMode)
34 {
35 (void) serverMode;
36 AutoAllocate();
37 RakAssert(serverMode);
38 return tcpInterface->Start(port, 64);
39 }
Stop(void)40 void TelnetTransport::Stop(void)
41 {
42 if (tcpInterface==0) return;
43 tcpInterface->Stop();
44 unsigned i;
45 for (i=0; i < remoteClients.Size(); i++)
46 RakNet::OP_DELETE(remoteClients[i], __FILE__, __LINE__);
47 remoteClients.Clear(false, __FILE__, __LINE__);
48 RakNet::OP_DELETE(tcpInterface, __FILE__, __LINE__);
49 tcpInterface=0;
50 }
Send(SystemAddress systemAddress,const char * data,...)51 void TelnetTransport::Send( SystemAddress systemAddress, const char *data,... )
52 {
53 if (tcpInterface==0) return;
54
55 if (data==0 || data[0]==0)
56 return;
57
58 char text[REMOTE_MAX_TEXT_INPUT];
59 size_t prefixLength;
60 if (sendPrefix)
61 {
62 strcpy(text, sendPrefix);
63 prefixLength = strlen(sendPrefix);
64 }
65 else
66 {
67 text[0]=0;
68 prefixLength=0;
69 }
70 va_list ap;
71 va_start(ap, data);
72 _vsnprintf(text+prefixLength, REMOTE_MAX_TEXT_INPUT-prefixLength, data, ap);
73 va_end(ap);
74 text[REMOTE_MAX_TEXT_INPUT-1]=0;
75
76 if (sendSuffix)
77 {
78 size_t length = strlen(text);
79 size_t availableChars = REMOTE_MAX_TEXT_INPUT-length-1;
80 strncat(text, sendSuffix, availableChars);
81 }
82
83 tcpInterface->Send(text, (unsigned int) strlen(text), systemAddress, false);
84 }
CloseConnection(SystemAddress systemAddress)85 void TelnetTransport::CloseConnection( SystemAddress systemAddress )
86 {
87 tcpInterface->CloseConnection(systemAddress);
88 }
Receive(void)89 Packet* TelnetTransport::Receive( void )
90 {
91 if (tcpInterface==0) return 0;
92 Packet *p = tcpInterface->Receive();
93 if (p==0)
94 return 0;
95
96 /*
97 if (p->data[0]==255)
98 {
99 unsigned i;
100 for (i=0; i < p->length; i++)
101 {
102 RAKNET_DEBUG_PRINTF("%i ", p->data[i]);
103 }
104 RAKNET_DEBUG_PRINTF("\n");
105 tcpInterface->DeallocatePacket(p);
106 return 0;
107 }
108 */
109
110 // Get this guy's cursor buffer. This is real bullcrap that I have to do this.
111 unsigned i;
112 TelnetClient *remoteClient=0;
113 for (i=0; i < remoteClients.Size(); i++)
114 {
115 if (remoteClients[i]->systemAddress==p->systemAddress)
116 remoteClient=remoteClients[i];
117 }
118 //RakAssert(remoteClient);
119 if (remoteClient==0)
120 {
121 tcpInterface->DeallocatePacket(p);
122 return 0;
123 }
124
125
126 if (p->length==3 && p->data[0]==27 && p->data[1]==91 && p->data[2]==65)
127 {
128 if (remoteClient->lastSentTextInput[0])
129 {
130 // Up arrow, return last string
131 for (int i=0; remoteClient->textInput[i]; i++)
132 remoteClient->textInput[i]=8;
133 strcat(remoteClient->textInput, remoteClient->lastSentTextInput);
134 tcpInterface->Send((const char *)remoteClient->textInput, strlen(remoteClient->textInput), p->systemAddress, false);
135 strcpy(remoteClient->textInput,remoteClient->lastSentTextInput);
136 remoteClient->cursorPosition=strlen(remoteClient->textInput);
137 }
138
139 return 0;
140 }
141
142
143 // 127 is delete - ignore that
144 // 9 is tab
145 // 27 is escape
146 if (p->data[0]>=127 || p->data[0]==9 || p->data[0]==27)
147 {
148 tcpInterface->DeallocatePacket(p);
149 return 0;
150 }
151
152 // Hack - I don't know what the hell this is about but cursor keys send 3 characters at a time. I can block these
153 //Up=27,91,65
154 //Down=27,91,66
155 //Right=27,91,67
156 //Left=27,91,68
157 if (p->length==3 && p->data[0]==27 && p->data[1]==91 && p->data[2]>=65 && p->data[2]<=68)
158 {
159 tcpInterface->DeallocatePacket(p);
160 return 0;
161 }
162
163
164
165 // Echo
166 #ifdef ECHO_INPUT
167 tcpInterface->Send((const char *)p->data, p->length, p->systemAddress, false);
168 #endif
169
170 bool gotLine;
171 // Process each character in turn
172 for (i=0; i < p->length; i++)
173 {
174
175 #ifdef ECHO_INPUT
176 if (p->data[i]==8)
177 {
178 char spaceThenBack[2];
179 spaceThenBack[0]=' ';
180 spaceThenBack[1]=8;
181 tcpInterface->Send((const char *)spaceThenBack, 2, p->systemAddress, false);
182 }
183 #endif
184
185 gotLine=ReassembleLine(remoteClient, p->data[i]);
186 if (gotLine && remoteClient->textInput[0])
187 {
188
189 Packet *reassembledLine = (Packet*) rakMalloc_Ex(sizeof(Packet), __FILE__, __LINE__);
190 reassembledLine->length=(unsigned int) strlen(remoteClient->textInput);
191 memcpy(remoteClient->lastSentTextInput, remoteClient->textInput, reassembledLine->length+1);
192 RakAssert(reassembledLine->length < REMOTE_MAX_TEXT_INPUT);
193 reassembledLine->data= (unsigned char*) rakMalloc_Ex( reassembledLine->length+1, __FILE__, __LINE__ );
194 memcpy(reassembledLine->data, remoteClient->textInput, reassembledLine->length);
195 #ifdef _PRINTF_DEBUG
196 memset(remoteClient->textInput, 0, REMOTE_MAX_TEXT_INPUT);
197 #endif
198 reassembledLine->data[reassembledLine->length]=0;
199 reassembledLine->systemAddress=p->systemAddress;
200 tcpInterface->DeallocatePacket(p);
201 return reassembledLine;
202 }
203 }
204
205 tcpInterface->DeallocatePacket(p);
206 return 0;
207 }
DeallocatePacket(Packet * packet)208 void TelnetTransport::DeallocatePacket( Packet *packet )
209 {
210 if (tcpInterface==0) return;
211 rakFree_Ex(packet->data, __FILE__, __LINE__ );
212 rakFree_Ex(packet, __FILE__, __LINE__ );
213 }
HasNewIncomingConnection(void)214 SystemAddress TelnetTransport::HasNewIncomingConnection(void)
215 {
216 unsigned i;
217 SystemAddress newConnection;
218 newConnection = tcpInterface->HasNewIncomingConnection();
219 // 03/16/06 Can't force the stupid windows telnet to use line mode or local echo so now I have to track all the remote players and their
220 // input buffer
221 if (newConnection != UNASSIGNED_SYSTEM_ADDRESS)
222 {
223 unsigned char command[10];
224 // http://www.pcmicro.com/netfoss/RFC857.html
225 // IAC WON'T ECHO
226 command[0]=255; // IAC
227 //command[1]=253; // WON'T
228 command[1]=251; // WILL
229 command[2]=1; // ECHO
230 tcpInterface->Send((const char*)command, 3, newConnection, false);
231
232 /*
233 // Tell the other side to use line mode
234 // http://www.faqs.org/rfcs/rfc1184.html
235 // IAC DO LINEMODE
236 // command[0]=255; // IAC
237 // command[1]=252; // DO
238 // command[2]=34; // LINEMODE
239 // tcpInterface->Send((const char*)command, 3, newConnection);
240
241 */
242
243 TelnetClient *remoteClient=0;
244 for (i=0; i < remoteClients.Size(); i++)
245 {
246 if (remoteClients[i]->systemAddress==newConnection)
247 {
248 remoteClient=remoteClients[i];
249 remoteClient->cursorPosition=0;
250 }
251 }
252
253 if (remoteClient==0)
254 {
255 remoteClient=new TelnetClient;
256 remoteClient->lastSentTextInput[0]=0;
257 remoteClient->cursorPosition=0;
258 remoteClient->systemAddress=newConnection;
259 #ifdef _PRINTF_DEBUG
260 memset(remoteClient->textInput, 0, REMOTE_MAX_TEXT_INPUT);
261 #endif
262 }
263
264 remoteClients.Insert(remoteClient, __FILE__, __LINE__);
265 }
266 return newConnection;
267 }
HasLostConnection(void)268 SystemAddress TelnetTransport::HasLostConnection(void)
269 {
270 SystemAddress systemAddress;
271 unsigned i;
272 systemAddress=tcpInterface->HasLostConnection();
273 if (systemAddress!=UNASSIGNED_SYSTEM_ADDRESS)
274 {
275 for (i=0; i < remoteClients.Size(); i++)
276 {
277 if (remoteClients[i]->systemAddress==systemAddress)
278 {
279 RakNet::OP_DELETE(remoteClients[i], __FILE__, __LINE__);
280 remoteClients[i]=remoteClients[remoteClients.Size()-1];
281 remoteClients.RemoveFromEnd();
282 }
283 }
284 }
285 return systemAddress;
286 }
GetCommandParser(void)287 CommandParserInterface* TelnetTransport::GetCommandParser(void)
288 {
289 return 0;
290 }
SetSendSuffix(const char * suffix)291 void TelnetTransport::SetSendSuffix(const char *suffix)
292 {
293 if (sendSuffix)
294 {
295 rakFree_Ex(sendSuffix, __FILE__, __LINE__ );
296 sendSuffix=0;
297 }
298 if (suffix)
299 {
300 sendSuffix = (char*) rakMalloc_Ex(strlen(suffix)+1, __FILE__, __LINE__);
301 strcpy(sendSuffix, suffix);
302 }
303 }
SetSendPrefix(const char * prefix)304 void TelnetTransport::SetSendPrefix(const char *prefix)
305 {
306 if (sendPrefix)
307 {
308 rakFree_Ex(sendPrefix, __FILE__, __LINE__ );
309 sendPrefix=0;
310 }
311 if (prefix)
312 {
313 sendPrefix = (char*) rakMalloc_Ex(strlen(prefix)+1, __FILE__, __LINE__);
314 strcpy(sendPrefix, prefix);
315 }
316 }
AutoAllocate(void)317 void TelnetTransport::AutoAllocate(void)
318 {
319 if (tcpInterface==0)
320 tcpInterface=new TCPInterface;
321 }
ReassembleLine(TelnetTransport::TelnetClient * remoteClient,unsigned char c)322 bool TelnetTransport::ReassembleLine(TelnetTransport::TelnetClient* remoteClient, unsigned char c)
323 {
324 if (c=='\n')
325 {
326 remoteClient->textInput[remoteClient->cursorPosition]=0;
327 remoteClient->cursorPosition=0;
328 #ifdef _PRINTF_DEBUG
329 RAKNET_DEBUG_PRINTF("[Done] %s\n", remoteClient->textInput);
330 #endif
331 return true;
332 }
333 else if (c==8) // backspace
334 {
335 if (remoteClient->cursorPosition>0)
336 {
337 remoteClient->textInput[--remoteClient->cursorPosition]=0;
338 #ifdef _PRINTF_DEBUG
339 RAKNET_DEBUG_PRINTF("[Back] %s\n", remoteClient->textInput);
340 #endif
341 }
342 }
343 else if (c>=32 && c <127)
344 {
345 if (remoteClient->cursorPosition < REMOTE_MAX_TEXT_INPUT)
346 {
347 remoteClient->textInput[remoteClient->cursorPosition++]=c;
348 #ifdef _PRINTF_DEBUG
349 RAKNET_DEBUG_PRINTF("[Norm] %s\n", remoteClient->textInput);
350 #endif
351 }
352 }
353 return false;
354 }
355
356 #ifdef _MSC_VER
357 #pragma warning( pop )
358 #endif
359
360 #endif // _RAKNET_SUPPORT_*
361