Rabbit Remote Control 0.1.0-de
Loading...
Searching...
No Matches
QTelnet.cpp
1#include "QTelnet.h"
2#include <QHostAddress>
3
4const char QTelnet::IACWILL[2] = { IAC, WILL };
5const char QTelnet::IACWONT[2] = { IAC, WONT };
6const char QTelnet::IACDO[2] = { IAC, DO };
7const char QTelnet::IACDONT[2] = { IAC, DONT };
8const char QTelnet::IACSB[2] = { IAC, SB };
9const char QTelnet::IACSE[2] = { IAC, SE };
10
11char QTelnet::_sendCodeArray[2] = { IAC, 0 };
12char QTelnet::_arrCRLF[2] = { 13, 10 };
13char QTelnet::_arrCR[2] = { 13, 0 };
14
15QTelnet::QTelnet(SocketType type, QObject *parent) :
16 QObject(parent), m_socketType(type), m_actualSB(0)
17{
18 connect(&m_tcpSocket, &QTcpSocket::errorOccurred, this, &QTelnet::socketError);
19 connect(&m_tcpSocket, &QTcpSocket::readyRead, this, &QTelnet::onTcpReadyRead);
20 connect(&m_tcpSocket, &QTcpSocket::stateChanged, this, &QTelnet::onStateChanged);
21#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)
22 connect(&m_webSocket, &QWebSocket::errorOccurred, this, &QTelnet::socketError);
23#else
24 connect(&m_webSocket, QOverload<QAbstractSocket::SocketError>::of(&QWebSocket::error), this, &QTelnet::socketError);
25#endif
26 connect(&m_webSocket, &QWebSocket::binaryMessageReceived, this, &QTelnet::binaryMessageReceived);
27 connect(&m_webSocket, &QWebSocket::stateChanged, this, &QTelnet::onStateChanged);
28}
29
30void QTelnet::setType(SocketType type)
31{
32 if(type != TCP && type != WEBSOCKET && type != SECUREWEBSOCKET)
33 m_socketType = TCP;
34 else
35 m_socketType = type;
36}
37
38QString QTelnet::peerInfo() const
39{
40 if(m_socketType == TCP)
41 return m_tcpSocket.peerName()+" ("+m_tcpSocket.peerAddress().toString()+" ):"+m_tcpSocket.peerPort();
42 else if(m_socketType == WEBSOCKET || m_socketType == SECUREWEBSOCKET)
43 return m_webSocket.peerName()+" ("+m_webSocket.peerAddress().toString()+" ):"+QString::number(m_webSocket.peerPort());
44
45 return QString();
46}
47
48QString QTelnet::peerName() const
49{
50 if(m_socketType == TCP)
51 return m_tcpSocket.peerName();
52 else if(m_socketType == WEBSOCKET || m_socketType == SECUREWEBSOCKET)
53 return m_webSocket.peerName();
54
55 return QString();
56}
57
58bool QTelnet::isConnected() const
59{
60 if(m_socketType == TCP)
61 return m_tcpSocket.state() == QAbstractSocket::ConnectedState;
62 else if(m_socketType == WEBSOCKET || m_socketType == SECUREWEBSOCKET)
63 return m_webSocket.state() == QAbstractSocket::ConnectedState;
64
65 return false;
66}
67
68void QTelnet::connectToHost(const QString &host, quint16 port)
69{
70 if(!isConnected()) {
72 if(m_socketType == TCP) {
73 m_tcpSocket.abort();
74 m_tcpSocket.connectToHost(host, port, QAbstractSocket::ReadWrite, QAbstractSocket::AnyIPProtocol);
75 } else if(m_socketType == WEBSOCKET) {
76 m_webSocket.abort();
77 m_webSocket.open(QUrl("ws://"+host+":"+QString::number(port)));
78 } else if(m_socketType == SECUREWEBSOCKET) {
79 m_webSocket.abort();
80 m_webSocket.open(QUrl("wss://"+host+":"+QString::number(port)));
81 }
82 }
83}
84
85void QTelnet::disconnectFromHost(void)
86{
87 if(m_socketType == TCP)
88 m_tcpSocket.disconnectFromHost();
89 else if(m_socketType == WEBSOCKET || m_socketType == SECUREWEBSOCKET)
90 m_webSocket.close();
91}
92
93void QTelnet::write(const char c)
94{
95 if(!isConnected())
96 return;
97 if(m_socketType == TCP)
98 m_tcpSocket.write( (char*)&c, 1 );
99 else if(m_socketType == WEBSOCKET || m_socketType == SECUREWEBSOCKET)
100 m_webSocket.sendBinaryMessage(QByteArray(&c, 1));
101}
102
103qint64 QTelnet::write(const char *data, qint64 len)
104{
105 if(!isConnected())
106 return 0;
107 if(m_socketType == TCP) {
108 return m_tcpSocket.write( data, len );
109 } else if(m_socketType == WEBSOCKET || m_socketType == SECUREWEBSOCKET) {
110 return m_webSocket.sendBinaryMessage(QByteArray(data, len));
111 }
112 return 0;
113}
114
115qint64 QTelnet::read(char *data, qint64 maxlen)
116{
117 if(!isConnected())
118 return 0;
119 if(m_socketType == TCP)
120 return m_tcpSocket.read(data, maxlen);
121 else if(m_socketType == WEBSOCKET || m_socketType == SECUREWEBSOCKET) {
122 return 0;
123 }
124 return 0;
125}
126
127bool QTelnet::testBinaryMode() const
128{
129 return m_receivedDX[(unsigned char)TELOPT_BINARY] == DO;
130}
131
132void QTelnet::sendData(const QByteArray &ba)
133{
134 if( isConnected() )
135 transpose( ba.constData(), ba.length() );
136}
137
138void QTelnet::sendData(const char *data, int len)
139{
140 if( isConnected() )
141 transpose( data, len );
142}
143
144void QTelnet::socketError(QAbstractSocket::SocketError err)
145{
146 disconnectFromHost();
147 emit error(err);
148}
149
150QString QTelnet::errorString()
151{
152 if(m_socketType == TCP)
153 return m_tcpSocket.errorString();
154 else if(m_socketType == WEBSOCKET || m_socketType == SECUREWEBSOCKET)
155 return m_webSocket.errorString();
156
157 return QString();
158}
159
160void QTelnet::setCustomCR(char cr, char cr2)
161{
162 _arrCR[0] = cr;
163 _arrCR[1] = cr2;
164}
165
166void QTelnet::setCustomCRLF(char lf, char cr)
167{
168 _arrCR[0] = lf;
169 _arrCR[1] = cr;
170}
171
172// Envia el codigo de control al servidor.
173void QTelnet::sendTelnetControl(char codigo)
174{
175 _sendCodeArray[1] = codigo;
176 write(_sendCodeArray, 2);
177}
178
179void QTelnet::writeCustomCRLF()
180{
181 write(_arrCRLF, 2);
182}
183
184void QTelnet::writeCustomCR()
185{
186 write(_arrCR, 2);
187}
188
191{
192 for( int i = 0; i < 256; i++ )
193 {
194 m_receivedDX[i] =
195 m_receivedWX[i] =
196 m_sentDX[i] =
197 m_sentWX[i] = 0;
198 m_negotiationState = STATE_DATA;
199 m_buffSB.clear();
200 m_actualSB = 0;
201 }
202 m_oldWinSize.setHeight(-1);
203 m_oldWinSize.setWidth(-1);
204}
205
206void QTelnet::sendSB(char code, char *arr, int iLen)
207{
208 write(IAC);
209 write(SB);
210 write(code);
211
212 write(arr, iLen);
213
214 write(IAC);
215 write(SE);
216}
217void QTelnet::sendWindowSize()
218{
219 if( isConnected() && (m_receivedDX[TELOPT_NAWS] == DO) && (m_oldWinSize != m_winSize) )
220 {
221 char size[4];
222
223 m_oldWinSize = m_winSize;
224 size[0] = (m_winSize.width()>>8) & 0xFF;
225 size[1] = m_winSize.width() & 0xFF;
226 size[2] = (m_winSize.height()>>8) & 0xFF;
227 size[3] = m_winSize.height() & 0xFF;
228 sendSB(TELOPT_NAWS, size, 4);
229 }
230}
231
232// Handle an incoming IAC SB type chars IAC SE
233void QTelnet::handleSB()
234{
235 switch( m_actualSB )
236 {
237 case TELOPT_TTYPE:
238 if( (m_buffSB.length() > 0) &&
239 ((unsigned char)m_buffSB[0] == (unsigned char)TELQUAL_SEND) )
240 {
241 write(IACSB, 2);
242 write(TELOPT_TTYPE);
243 write(TELQUAL_IS);
244 /* FIXME: need more logic here if we use
245 * more than one terminal type
246 */
247 write("SiraggaTerminal", 15);
248 write(IACSE, 2);
249 }
250 break;
251 }
252}
253
254// Analiza el texto saliente para que cumpla las normas del protocolo.
255// Además ya lo escribe en el m_tcpSocket.
256void QTelnet::transpose(const char *buf, int iLen)
257{
258 for( int i = 0; i < iLen; i++ )
259 {
260 switch( buf[i] )
261 {
262 case IAC:
263 // Escape IAC twice in stream ... to be telnet protocol compliant
264 // this is there in binary and non-binary mode.
265 write(IAC);
266 write(IAC);
267 break;
268 case 10: // \n
269 // We need to heed RFC 854. LF (\n) is 10, CR (\r) is 13
270 // we assume that the Terminal sends \n for lf+cr and \r for just cr
271 // linefeed+carriage return is CR LF
272
273 // En modo binario no se traduce nada.
274 if( testBinaryMode() || m_socketType == WEBSOCKET || m_socketType == SECUREWEBSOCKET)
275 write(buf[i]);
276 else
277 writeCustomCRLF();
278 break;
279 case 13: // \r
280 // carriage return is CR NUL */
281
282 // En modo binario no se traduce nada.
283 if( testBinaryMode() || m_socketType == WEBSOCKET || m_socketType == SECUREWEBSOCKET)
284 write(buf[i]);
285 else
286 writeCustomCRLF();
287 break;
288 default:
289 // all other characters are just copied
290 write(buf[i]);
291 break;
292 }
293 }
294}
295
296void QTelnet::willsReply(char action, char reply)
297{
298 if( (reply != m_sentDX[(unsigned char)action]) ||
299 (WILL != m_receivedWX[(unsigned char)action]) )
300 {
301 write(IAC);
302 write(reply);
303 write(action);
304
305 m_sentDX[(unsigned char)action] = reply;
306 m_receivedWX[(unsigned char)action] = WILL;
307 }
308}
309
310void QTelnet::wontsReply(char action, char reply)
311{
312 if( (reply != m_sentDX[(unsigned char)action]) ||
313 (WONT != m_receivedWX[(unsigned char)action]) )
314 {
315 write(IAC);
316 write(reply);
317 write(action);
318
319 m_sentDX[(unsigned char)action] = reply;
320 m_receivedWX[(unsigned char)action] = WONT;
321 }
322}
323
324void QTelnet::doesReply(char action, char reply)
325{
326 if( (reply != m_sentWX[(unsigned char)action]) ||
327 (DO != m_receivedDX[(unsigned char)action]) )
328 {
329 write(IAC);
330 write(reply);
331 write(action);
332
333 m_sentWX[(unsigned char)action] = reply;
334 m_receivedDX[(unsigned char)action] = DO;
335 }
336}
337
338void QTelnet::dontsReply(char action, char reply)
339{
340 if( (reply != m_sentWX[(unsigned char)action]) ||
341 (DONT != m_receivedDX[(unsigned char)action]) )
342 {
343 write(IAC);
344 write(reply);
345 write(action);
346
347 m_sentWX[(unsigned char)action] = reply;
348 m_receivedDX[(unsigned char)action] = DONT;
349 }
350}
351
352// Analiza el buffer de entrada colocá ndolo en el buffer de procesado usando el protocolo telnet.
353qint64 QTelnet::doTelnetInProtocol(qint64 buffSize)
354{
355 qint64 iIn, iOut;
356
357 for( iIn = 0, iOut = 0; iIn < buffSize; iIn++ )
358 {
359 char b = m_buffIncoming[iIn];
360
361 switch( m_negotiationState )
362 {
363 // TODO: Currently we implement only bypass CRLF and CR, do not convert
364 case STATE_DATA:
365 switch( b )
366 {
367 case IAC:
368 m_negotiationState = STATE_IAC;
369 break;
370 case '\r':
371 m_buffProcessed[iOut++] = '\r';
372 m_negotiationState = STATE_DATAR;
373 break;
374 case '\n':
375 m_buffProcessed[iOut++] = '\n';
376 m_negotiationState = STATE_DATAN;
377 break;
378 default:
379 m_buffProcessed[iOut++] = b;
380 break;
381 }
382 break;
383 case STATE_DATAN:
384 case STATE_DATAR:
385 switch( b )
386 {
387 case IAC:
388 m_negotiationState = STATE_IAC;
389 break;
390 case '\r':
391 m_buffProcessed[iOut++] = '\r';
392 m_negotiationState = STATE_DATA;
393 break;
394 case '\n':
395 m_buffProcessed[iOut++] = '\n';
396 m_negotiationState = STATE_DATA;
397 break;
398 default:
399 m_buffProcessed[iOut++] = b;
400 m_negotiationState = STATE_DATA;
401 break;
402 }
403 break;
404 case STATE_IAC:
405 switch( b )
406 {
407 case IAC: // Dos IAC seguidos, se intenta enviar un caracter con el valor IAC.
408 m_negotiationState = STATE_DATA;
409 m_buffProcessed[iOut++] = IAC;
410 break;
411 case WILL:
412 m_negotiationState = STATE_IACWILL;
413 break;
414 case WONT:
415 m_negotiationState = STATE_IACWONT;
416 break;
417 case DONT:
418 m_negotiationState = STATE_IACDONT;
419 break;
420 case DO:
421 m_negotiationState = STATE_IACDO;
422 break;
423 case EOR:
424 emitEndOfRecord();
425 m_negotiationState = STATE_DATA;
426 break;
427 case SB:
428 m_negotiationState = STATE_IACSB;
429 m_buffSB.clear();
430 break;
431 default:
432 m_negotiationState = STATE_DATA;
433 break;
434 }
435 break;
436 case STATE_IACWILL:
437 switch( b )
438 {
439 case TELOPT_ECHO:
440 emitEchoLocal(false);
441 willsReply(b, DO);
442 break;
443 case TELOPT_SGA:
444 willsReply(b, DO);
445 break;
446 case TELOPT_EOR:
447 willsReply(b, DO);
448 break;
449 case TELOPT_BINARY:
450 willsReply(b, DO);
451 break;
452 default:
453 willsReply(b, DONT);
454 break;
455 }
456 m_negotiationState = STATE_DATA;
457 break;
458 case STATE_IACWONT:
459 switch(b)
460 {
461 case TELOPT_ECHO:
462 emitEchoLocal(true);
463 wontsReply(b, DONT);
464 break;
465 case TELOPT_SGA:
466 wontsReply(b, DONT);
467 break;
468 case TELOPT_EOR:
469 wontsReply(b, DONT);
470 break;
471 case TELOPT_BINARY:
472 wontsReply(b, DONT);
473 break;
474 default:
475 wontsReply(b, DONT);
476 break;
477 }
478 m_negotiationState = STATE_DATA;
479 break;
480 case STATE_IACDO:
481 switch( b )
482 {
483 case TELOPT_ECHO:
484 doesReply(b, WILL);
485 emitEchoLocal(true);
486 break;
487 case TELOPT_SGA:
488 doesReply(b, WILL);
489 break;
490 case TELOPT_TTYPE:
491 doesReply(b, WILL);
492 break;
493 case TELOPT_BINARY:
494 doesReply(b, WILL);
495 break;
496 case TELOPT_NAWS:
497 m_receivedDX[(unsigned char)b] = (unsigned char)DO;
498 m_sentWX[(unsigned char)b] = (unsigned char)WILL;
499 write(IAC);
500 write(WILL);
501 write(b);
502
503 // Enviamos el tamaño de la pantalla.
504 sendWindowSize();
505 break;
506 default:
507 doesReply(b, WONT);
508 break;
509 }
510 m_negotiationState = STATE_DATA;
511 break;
512 case STATE_IACDONT:
513 switch (b)
514 {
515 case TELOPT_ECHO:
516 dontsReply(b, WONT);
517 emitEchoLocal(false);
518 break;
519 case TELOPT_SGA:
520 dontsReply(b, WONT);
521 break;
522 case TELOPT_NAWS:
523 dontsReply(b, WONT);
524 break;
525 case TELOPT_BINARY:
526 dontsReply(b, WONT);
527 break;
528 default:
529 dontsReply(b, WONT);
530 break;
531 }
532 m_negotiationState = STATE_DATA;
533 break;
534 case STATE_IACSB:
535 switch( b )
536 {
537 case IAC:
538 // Entramos en estado IAC en la sub-negociación.
539 m_negotiationState = STATE_IACSBIAC;
540 break;
541 default:
542 // Iniciamos la sub-negociación.
543 m_buffSB.clear();
544 m_actualSB = b;
545 m_negotiationState = STATE_IACSBDATA;
546 break;
547 }
548 break;
549 case STATE_IACSBDATA: // Estamos en datos de la subnegociación.
550 switch( b )
551 {
552 case IAC:
553 m_negotiationState = STATE_IACSBDATAIAC;
554 break;
555 default:
556 m_buffSB.append(b);
557 break;
558 }
559 break;
560 case STATE_IACSBIAC:
561 switch( b )
562 {
563 case IAC:
564 // Reiniciamos la sub-negociación.
565 m_buffSB.clear();
566 m_actualSB = b;
567 m_negotiationState = STATE_IACSBDATA;
568 break;
569 default:
570 // Salimos de la sub-negociación.
571 m_negotiationState = STATE_DATA;
572 break;
573 }
574 break;
575 case STATE_IACSBDATAIAC:
576 switch( b )
577 {
578 case IAC:
579 m_negotiationState = STATE_IACSBDATA;
580 m_buffSB.append(IAC);
581 break;
582 case SE:
583 handleSB();
584 m_actualSB = 0;
585 m_buffSB.clear();
586 m_negotiationState = STATE_DATA;
587 break;
588 case SB:
589 handleSB();
590 m_buffSB.clear();
591 m_negotiationState = STATE_IACSB;
592 break;
593 default:
594 m_buffSB.clear();
595 m_actualSB = 0;
596 m_negotiationState = STATE_DATA;
597 break;
598 }
599 break;
600 default:
601 m_negotiationState = STATE_DATA;
602 break;
603 }
604 }
605 return iOut;
606}
607
608void QTelnet::onTcpReadyRead()
609{
610 qint64 readed;
611 qint64 processed;
612
613 while( (readed = read(m_buffIncoming, IncommingBufferSize)) != 0 )
614 {
615 switch( readed )
616 {
617 case -1:
618 disconnectFromHost();
619 break;
620 default:
621 processed = doTelnetInProtocol(readed);
622 if( processed > 0 )
623 emit newData(m_buffProcessed, processed);
624
625 break;
626 }
627 }
628}
629
630void QTelnet::binaryMessageReceived(const QByteArray &message)
631{
632 emit newData(message.constData(), message.length());
633}
634
635void QTelnet::onStateChanged(QAbstractSocket::SocketState s)
636{
637 emit stateChanged(s);
638}
639
void resetProtocol()
Resetea los datos del protocolo. Debe llamarse cada vez que se inicia una conexión nueva.
Definition QTelnet.cpp:190