7 #include "log/logger.hpp"
9 static constexpr std::size_t buffer_size = 2 * 0xFFFF + 20;//8192;
11 #define SLIP_ESCAPE_CHAR ( (char) 0xDB)
12 #define SLIP_CONNECTION ( (char) 0xC0)
13 #define SLIP_RESET ( (char) 0xCB )
15 //#define SLIP_IO_DEBUG
16 //#define RAW_IO_DEBUG
17 //#define UNMASK_DEBUG
19 char hexDigit( char c ) {
35 std::string toHex( const char* buf, int len ) {
36 std::string data = "000000";
38 for( int i = 0; i < len; i++ ) {
39 data.append( 1, ' ' );
40 data.append( 1, hexDigit( ( buf[i] >> 4 ) & 0xF ) );
41 data.append( 1, hexDigit( buf[i] & 0xF ) );
47 SlipBIO::SlipBIO() : buffer( buffer_size ), decodeTarget( 0 ), decodePos( 0 ), rawPos( 0 ) {
50 void SlipBIO::setTarget( std::shared_ptr<OpensslBIO> target, bool server ) {
51 this->target = target;
52 this->server = server;
55 SlipBIO::SlipBIO( std::shared_ptr<OpensslBIO> target ) : target( target ), buffer( std::vector<char>( buffer_size ) ), decodeTarget( 0 ), decodePos( 0 ), rawPos( 0 ) {
58 SlipBIO::~SlipBIO() {}
60 int SlipBIO::write( const char* buf, int num ) {
62 logger::notef( "slip-out: %s", toHex( buf, num ) );
66 logger::note( "denying read because of reset-need!" );
73 for( int i = 0; i < num; i++ ) {
74 if( ( buf[i] == SLIP_CONNECTION ) || ( buf[i] == SLIP_ESCAPE_CHAR ) ) {
79 int totalLen = num + badOnes; // 2
80 char* targetPtr = ( char* ) malloc( totalLen );
86 std::shared_ptr<char> t = std::shared_ptr<char>( targetPtr, free );
89 for( int i = 0; i < num; i++ ) {
90 if( buf[i] == SLIP_CONNECTION ) {
91 targetPtr[j++] = SLIP_ESCAPE_CHAR;
92 targetPtr[j++] = ( char )0xDC;
93 } else if( buf[i] == SLIP_ESCAPE_CHAR ) {
94 targetPtr[j++] = SLIP_ESCAPE_CHAR;
95 targetPtr[j++] = ( char )0xDD;
97 targetPtr[j++] = buf[i];
106 int dlen = target->write( targetPtr + sent, std::min( 1024, j - sent ) );
108 std::ostringstream debug;
109 debug << "Wrote " << dlen << " bytes: ";
110 debug << toHex( targetPtr + sent, dlen );
111 logger::note( debug.str() );
115 throw std::runtime_error( "Error, target write failed" );
116 } else if( dlen == 0 ) {
118 logger::note( "waiting for write ability" );
132 int SlipBIO::read( char* buf, int size ) {
134 logger::note( "starting read" );
137 // while we have no data to decode or unmasking does not yield a full package
138 while( decodeTarget == 0 ) {
140 logger::note( "denying read because of reset-need!" );
144 if( decodePos < rawPos ) {
148 continue; // probably Packet :-)
149 } else if( res == -1 ) {
150 logger::note( "sending reset because of malfomed packet" );
155 if( decodeTarget != 0 ) {
156 // we have data now, emit it!
160 // we have no data, read more
161 if( buffer.size() - rawPos < 64 ) {
162 // not enough space... package is too big
164 waitForConnection = true;
171 logger::note( "beginning read" );
174 std::ostringstream converter;
175 converter << "rawPos is now: " << rawPos << ", buffer.size():" << buffer.size();
176 logger::note( converter.str() );
178 int len = target->read( buffer.data() + rawPos, buffer.size() - rawPos );
180 logger::note( toHex( buffer.data() + rawPos, len ) );
186 logger::note( "Reporting EOS from slip" );
198 int len = std::min( decodeTarget, ( unsigned int ) size );
199 // a package finished, return it
200 std::copy( buffer.data(), buffer.data() + len, buf );
201 // move the buffer contents back
202 std::copy( buffer.data() + len, buffer.data() + decodeTarget, buffer.data() );
205 std::ostringstream convert;
206 convert << "decodeTarget: " << decodeTarget << ", rawPos: " << rawPos << ", decodePos: " << decodePos;
207 convert << ", requested were: " << size;
208 logger::note( convert.str() );
211 if( decodeTarget == 0 && rawPos <= decodePos + 1 ) {
212 // compact the remaining at most 1 byte of raw data
213 buffer[0] = buffer[decodePos];
219 logger::notef( "slip-in: %s", toHex( buf, len ) );
225 long SlipBIO::ctrl( int cmod, long arg1, void* arg2 ) {
230 if( cmod == BIO_CTRL_RESET ) {
234 waitForReset = false;
235 waitForConnection = true;
239 char resetSequence[] = {SLIP_CONNECTION, 1, 2, 3, 4, 5, 6, 7, ctr};
240 target->write( resetSequence, 9 );
241 header = {1, 2, 3, 4, 5, 6, 7, ctr};
243 waitForConnection = true;
244 logger::note( "Resetting SLIP layer" );
248 } else if( cmod == BIO_CTRL_FLUSH ) {
250 logger::note( "flush requested " );
254 return target->ctrl( cmod, arg1, arg2 );
257 const char* SlipBIO::getName() {
261 // 1 success, data avail, 0 need moar data (see that decodeTarget is still 0),
262 // -1: fail... connection needs resetting
263 int SlipBIO::unmask() {
266 std::ostringstream conv;
267 conv << "unmasking starting, decodeTarget: " << decodeTarget << " decodePos: " << decodePos << " rawPos: " << rawPos << "bytes stored";
268 logger::note( conv.str() );
270 logger::note( "unmasking" );
273 if( waitForConnection ) {
275 logger::note( "scanning for connection" );
281 logger::note( "on server site, waiting for CONNECTION-byte" );
284 while( decodePos < rawPos ) {
285 if( buffer[decodePos] == SLIP_CONNECTION ) {
288 logger::note( "got connection byte" );
290 } else if( resetCounter >= 0 ) {
291 header[resetCounter] = buffer[decodePos];
297 if( resetCounter >= ( ( int ) header.size() ) ) {
298 waitForConnection = false;
299 char data[] = { SLIP_CONNECTION };
300 target->write( data, 1 );
302 logger::notef( "SLIP, initing connection with ping-seq %s:", toHex( header.data(), header.size() ) );
304 target->write( header.data(), header.size() );
309 if( decodePos >= rawPos ) {
312 return 0; // no package
316 while( decodePos < rawPos ) {
317 if( buffer[decodePos] == SLIP_CONNECTION ) {
319 logger::note( "got connbyte" );
322 } else if( resetCounter >= 0 ) {
324 logger::note( "got head-byte" );
327 if( buffer[decodePos] == header[resetCounter] ) {
336 if( resetCounter >= ( ( int ) header.size() ) ) {
337 waitForConnection = false;
339 logger::note( "connection found! :-)!" );
345 if( decodePos >= rawPos ) {
348 return 0; // no package
353 unsigned int j = decodeTarget;
355 for( unsigned int i = decodePos; i < rawPos; i++ ) {
356 if( waitForConnection && buffer[i] != SLIP_CONNECTION ) {
360 if( buffer[i] == SLIP_ESCAPE_CHAR ) {
365 buffer[decodeTarget] = buffer[i - 1];
366 decodePos = decodeTarget;
367 rawPos = decodePos + 1;
368 return 0;// no packet
369 } else if( buffer[i] == ( char )0xdc ) {
370 buffer[j++] = SLIP_CONNECTION;
371 } else if( buffer[i] == ( char )0xdd ) {
372 buffer[j++] = SLIP_ESCAPE_CHAR;
373 } else if( buffer[i] == SLIP_ESCAPE_CHAR
374 || buffer[i] == SLIP_CONNECTION ) {
380 waitForConnection = true;
385 return -1; // we don't have a pkg, set all appropriately to wait for a pkg start for next pkg.
387 } else if( buffer[i] == SLIP_CONNECTION ) {
391 // copy rest to bufferfer i to len
392 if( !waitForConnection ) {
395 waitForConnection = true;
398 logger::note( "error connection failed" );
402 logger::note( "got package border; slip re-validated SHOULD NEVER HAPPEN!!" );
404 waitForConnection = false;
406 buffer[j++] = buffer[i];
411 std::ostringstream conv;
412 conv << "unmasking paused, 0 remaining, " << j << "bytes stored";
413 logger::note( conv.str() );
418 return decodeTarget > 0;