Browse files

Make Telnet connections able to run synchronously using vt_tiledata 2011

  • Loading branch information...
1 parent 4d99e03 commit 4f010bee76339c5f6e2e9eff7ffb8d474141664d @sorear committed Aug 18, 2011
Showing with 63 additions and 3 deletions.
  1. +4 −0 include/Telnet.h
  2. +56 −3 src/Telnet.cpp
  3. +3 −0 src/World.cpp
View
4 include/Telnet.h
@@ -23,7 +23,11 @@ class Telnet : public Connection {
private:
int _sock;
char _ping[3];
+ bool _vt_tiledata2011;
+ int _overs_pending;
int transmit(const char* data, int length);
+ int scanOvers(const char* data, int length);
+ int removeOvers(char* data, int length);
};
#endif
View
59 src/Telnet.cpp
@@ -13,7 +13,7 @@
using namespace std;
/* constructors/destructor */
-Telnet::Telnet() {
+Telnet::Telnet() : _vt_tiledata2011(false), _overs_pending(0) {
/* read login details from .account */
ifstream account;
account.open(".account");
@@ -98,14 +98,26 @@ Telnet::~Telnet() {
/* methods */
int Telnet::doRetrieve(char* buffer, int count) {
+ int returned = -1;
+ int retrieved = 0;
+ int overs = 0;
+ /* if the target is cooperating, we don't need to play games with the telnetd */
+ if (_vt_tiledata2011) {
+ while ((overs = scanOvers(buffer, retrieved)) < _overs_pending) {
+ returned = recv(_sock, &buffer[retrieved], count - retrieved - 1, 0);
+ retrieved += returned;
+ }
+ _overs_pending -= overs;
+ retrieved = removeOvers(buffer, retrieved);
+ buffer[retrieved] = 0;
+ return retrieved;
+ }
/* this is borrowed from TAEB:
* we can send a "ping" by transmitting [0xff, 0xfd, 0x63].
* then we'll just read until last bytes equal [?, ?, ?] */
transmit(_ping, 3);
/* sleep a bit in case of very low latency */
usleep(50000);
- int returned = -1;
- int retrieved = 0;
int more_data = true;
int tries = 5;
while (more_data && tries >= 0 && returned != 0) {
@@ -146,23 +158,64 @@ int Telnet::doRetrieve(char* buffer, int count) {
}
}
}
+ overs = scanOvers(buffer, retrieved);
+ if (overs) {
+ // good news! we just started a nethack with vt_tiledata 2011 enabled.
+ // we don't need to use any of this ping/pong hacks anymore
+ _vt_tiledata2011 = true;
+ _overs_pending -= overs;
+ retrieved = removeOvers(buffer, retrieved);
+ Debug::info() << "Detected vt_tiledata 2011. Switching to synchronous mode." << endl;
+ }
+ buffer[retrieved] = 0;
if (tries < 0)
Debug::warning() << "We were expecting data, but got none. Fix this bug, please!" << endl;
return retrieved;
}
int Telnet::transmit(const string& data) {
+ _overs_pending += data.length();
return transmit(data.c_str(), data.length());
}
void Telnet::start() {
transmit("p");
+ // previous character(s) will not be seen by nethack
+ _overs_pending = 1;
}
void Telnet::stop() {
}
/* private methods */
+/* doesn't count towards _overs_pending because this is used for sending the ping */
int Telnet::transmit(const char* data, int length) {
return send(_sock, data, length, 0);
}
+
+int Telnet::scanOvers(const char* data, int length) {
+ int found = 0;
+ for (const char* ptr = data; ptr <= data + length - 4; ++ptr) {
+ if (ptr[0] == 27 && ptr[1] == '[' && ptr[2] == '3' && ptr[3] == 'z') {
+ found++;
+ ptr += 3;
+ }
+ }
+ return found;
+}
+
+// XXX: the core expects to find --More-- at the end of data, so we need to remove ^[[3z from the data.
+int Telnet::removeOvers(char *data, int length) {
+ char* rp = data;
+ char* wp = data;
+ while (rp <= data + length - 4) {
+ if (rp[0] == 27 && rp[1] == '[' && rp[2] == '3' && rp[3] == 'z') {
+ rp += 4;
+ } else {
+ *(wp++) = *(rp++);
+ }
+ }
+ while (rp != data + length)
+ *(wp++) = *(rp++);
+ return wp - data;
+}
View
3 src/World.cpp
@@ -1538,6 +1538,9 @@ void World::handleEscapeSequence(int* pos, int* color) {
} else if (_data[*pos] == 'r') {
/* this is some scrolling crap, ignore it */
break;
+ } else if (_data[*pos] == 'z') {
+ /* this is generated by vt_tiledata; the stuff we care about is handled in Telnet */
+ break;
} else if (_data[*pos] == 27) {
/* escape char found, that shouldn't happen */
Debug::rawCharArray(_data, start, *pos + 1);

0 comments on commit 4f010be

Please sign in to comment.