7 #include "log/logger.hpp"
9 static constexpr std::size_t buffer_size = 8192;
11 #define SLIP_ESCAPE_CHAR ( (char) 0xDB)
12 #define SLIP_CONNECTION ( (char) 0xC0)
13 #define SLIP_RESET ( (char) 0xCB )
17 char hexDigit( char c ) {
33 std::string toHex( const char* buf, int len ) {
34 std::string data = "000000";
36 for( int i = 0; i < len; i++ ) {
37 data.append( 1, ' ' );
38 data.append( 1, hexDigit( ( buf[i] >> 4 ) & 0xF ) );
39 data.append( 1, hexDigit( buf[i] & 0xF ) );
45 SlipBIO::SlipBIO() : buffer( std::vector<char>( buffer_size ) ), decodeTarget( 0 ), decodePos( 0 ), rawPos( 0 ) {
48 void SlipBIO::setTarget( std::shared_ptr<OpensslBIO> target, bool server ) {
49 this->target = target;
50 this->server = server;
53 SlipBIO::SlipBIO( std::shared_ptr<OpensslBIO> target ) : target( target ), buffer( std::vector<char>( buffer_size ) ), decodeTarget( 0 ), decodePos( 0 ), rawPos( 0 ) {
56 SlipBIO::~SlipBIO() {}
58 int SlipBIO::write( const char* buf, int num ) {
60 logger::notef( "Out: %s", toHex( buf, num ) );
65 for( int i = 0; i < num; i++ ) {
66 if( ( buf[i] == SLIP_CONNECTION ) || ( buf[i] == SLIP_ESCAPE_CHAR ) ) {
71 int totalLen = num + badOnes; // 2
72 char* targetPtr = ( char* ) malloc( totalLen );
78 std::shared_ptr<char> t = std::shared_ptr<char>( targetPtr, free );
81 for( int i = 0; i < num; i++ ) {
82 if( buf[i] == SLIP_CONNECTION ) {
83 targetPtr[j++] = SLIP_ESCAPE_CHAR;
84 targetPtr[j++] = ( char )0xDC;
85 } else if( buf[i] == SLIP_ESCAPE_CHAR ) {
86 targetPtr[j++] = SLIP_ESCAPE_CHAR;
87 targetPtr[j++] = ( char )0xDD;
89 targetPtr[j++] = buf[i];
98 int dlen = target->write( targetPtr + sent, std::min( 1024, j - sent ) );
99 std::ostringstream debug;
100 debug << "Wrote " << dlen << " bytes ";
101 debug << toHex( targetPtr + sent, dlen );
102 logger::note( debug.str() );
103 target->ctrl( BIO_CTRL_FLUSH, 0, NULL );
106 throw "Error, target write failed";
107 } else if( dlen == 0 ) {
109 logger::note( "waiting for write ability" );
123 int SlipBIO::read( char* buf, int size ) {
124 logger::note( "starting read" );
125 // while we have no data to decode or unmasking does not yield a full package
126 while( decodeTarget == 0 ) {
128 logger::note( "denying read because of reset-need!" );
131 if(decodePos < rawPos) {
134 continue; // probably Packet :-)
135 } else if(res == -1) {
136 logger::note( "sending reset because of malfomed packet" );
140 if( decodeTarget != 0 ){
141 // we have data now, emit it!
144 // we have no data, read more
145 if( buffer.size() - rawPos < 64 ) {
146 // not enough space... package is too big
148 waitForConnection = true;
154 logger::note( "beginning read" );
155 std::ostringstream converter;
156 converter << "rawPos is now: " << rawPos << ", buffer.size():" << buffer.size();
157 logger::note( converter.str() );
158 int len = target->read( buffer.data() + rawPos, buffer.size() - rawPos );
159 logger::note( toHex(buffer.data() + rawPos, len ) );
164 logger::note("Reporting EOS from slip");
171 if( waitForReset ) return -1;
172 logger::note( "emitting data!" );
174 int len = std::min( decodeTarget, ( unsigned int ) size );
175 // a package finished, return it
176 std::copy( buffer.data(), buffer.data() + len, buf );
177 // move the buffer contents back
178 std::copy( buffer.data() + len, buffer.data() + decodeTarget, buffer.data() );
180 std::ostringstream convert;
181 convert << "decodeTarget: " << decodeTarget << ", rawPos: " << rawPos << ", decodePos: " << decodePos;
182 convert << ", requested were: " << size;
183 logger::note( convert.str() );
185 if(decodeTarget == 0 && rawPos <= decodePos + 1){
186 // compact the remaining at most 1 byte of raw data
187 buffer[0] = buffer[decodePos];
193 logger::notef( "in: %s", toHex( buf, len ) );
199 long SlipBIO::ctrl( int cmod, long arg1, void* arg2 ) {
204 if( cmod == BIO_CTRL_RESET ) {
207 waitForReset = false;
208 waitForConnection = true;
212 char resetSequence[] = {SLIP_CONNECTION, 1,2,3,4,5,6,7, ctr};
213 target->write( resetSequence, 9 );
214 logger::note( "wrote 9-byte reset seq" );
215 header = {1, 2, 3, 4, 5, 6, 7, ctr};
217 waitForConnection = true;
218 logger::note( "Resetting SLIP layer" );
221 }else if(cmod == BIO_CTRL_FLUSH ){
222 logger::note( "flush requested ");
225 return target->ctrl( cmod, arg1, arg2 );
228 const char* SlipBIO::getName() {
232 // 1 success, data avail, 0 need moar data (see that decodeTarget is still 0),
233 // -1: fail... connection needs resetting
234 int SlipBIO::unmask() {
236 std::ostringstream conv;
237 conv << "unmasking starting, decodeTarget: " << decodeTarget << " decodePos: " << decodePos << " rawPos: " << rawPos << "bytes stored";
238 logger::note( conv.str() );
240 logger::note( "unmasking" );
241 if( waitForConnection ){
242 logger::note( "scanning for connection" );
245 logger::note( "on server site, waiting for CONNECTION-byte");
246 while(decodePos < rawPos) {
247 if(buffer[decodePos] == SLIP_CONNECTION) {
249 logger::note( "got connection byte" );
250 } else if(resetCounter >= 0) {
251 header[resetCounter] = buffer[decodePos];
255 if( resetCounter >= ((int) header.size()) ){
256 waitForConnection = false;
257 char data[] = { SLIP_CONNECTION };
258 target->write( data, 1);
259 logger::notef( "SLIP, initing connection with ping-seq %s:", toHex(header.data(), header.size()) );
260 target->write( header.data(), header.size() );
264 if( decodePos >= rawPos ){
267 return 0; // no package
271 while(decodePos < rawPos) {
272 if(buffer[decodePos] == SLIP_CONNECTION) {
273 logger::note( "got connbyte" );
275 } else if(resetCounter >= 0) {
276 logger::note( "got head-byte" );
277 if(buffer[decodePos] == header[resetCounter]) {
278 logger::note( "thats correct!!" );
285 if( resetCounter >= ((int) header.size()) ){
286 waitForConnection = false;
287 logger::note("connection found! :-)!");
291 if( decodePos >= rawPos ){
294 return 0; // no package
298 unsigned int j = decodeTarget;
300 for( unsigned int i = decodePos; i < rawPos; i++ ) {
301 if(waitForConnection && buffer[i] != SLIP_CONNECTION ) {
304 if( buffer[i] == SLIP_ESCAPE_CHAR ) {
309 buffer[decodeTarget] = buffer[i - 1];
310 decodePos = decodeTarget;
311 rawPos = decodePos + 1;
312 return 0;// no packet
313 } else if( buffer[i] == ( char )0xdc ) {
314 buffer[j++] = SLIP_CONNECTION;
315 } else if( buffer[i] == ( char )0xdd ) {
316 buffer[j++] = SLIP_ESCAPE_CHAR;
317 } else if( buffer[i] == SLIP_ESCAPE_CHAR
318 || buffer[i] == SLIP_CONNECTION ) {
324 waitForConnection = true;
329 return -1; // we don't have a pkg, set all appropriately to wait for a pkg start for next pkg.
331 } else if( buffer[i] == SLIP_CONNECTION ) {
335 // copy rest to bufferfer i to len
336 if( !waitForConnection ) {
339 waitForConnection = true;
342 logger::note( "error connection failed" );
345 logger::note( "got package border; slip re-validated SHOULD NEVER HAPPEN!!" );
347 waitForConnection = false;
349 buffer[j++] = buffer[i];
353 std::ostringstream conv;
354 conv << "unmasking paused, 0 remaining, " << j << "bytes stored";
355 logger::note( conv.str() );
359 return decodeTarget > 0;