]> WPIA git - cassiopeia.git/commitdiff
add: Basic BIO implementation for SLIP
authorFelix Dörre <felix@dogcraft.de>
Sun, 30 Nov 2014 16:13:01 +0000 (17:13 +0100)
committerBenny Baumann <BenBE@geshi.org>
Sat, 24 Jan 2015 16:39:35 +0000 (17:39 +0100)
src/slipBio.cpp [new file with mode: 0644]
src/slipBio.h [new file with mode: 0644]
test/src/slipBioTest.cpp [new file with mode: 0644]

diff --git a/src/slipBio.cpp b/src/slipBio.cpp
new file mode 100644 (file)
index 0000000..6f1105c
--- /dev/null
@@ -0,0 +1,185 @@
+#include "slipBio.h"
+
+#include <iostream>
+
+char hexDigit( char c ) {
+    if( c < 0 ) {
+        return 'x';
+    }
+
+    if( c < 10 ) {
+        return '0' + c;
+    }
+
+    if( c < 16 ) {
+        return 'A' + c - 10;
+    }
+
+    return 'x';
+}
+
+std::string toHex( const char* buf, int len ) {
+    char* c = ( char* ) malloc( len * 2 );
+
+    if( !c ) {
+        return "<malloc fail>";
+    }
+
+    std::shared_ptr<char> mem = std::shared_ptr<char>( c, free );
+
+    for( int i = 0; i < len; i++ ) {
+        c[i * 2] = hexDigit( ( buf[i] >> 4 ) & 0xF );
+        c[i * 2 + 1] = hexDigit( buf[i] & 0xF );
+    }
+
+    return std::string( mem.get(), len * 2 );
+}
+
+SlipBIO::SlipBIO( std::shared_ptr<OpensslBIO> target ) {
+    this->target = target;
+
+    this->buffer = std::vector<char>( 4096 );
+    this->decodeTarget = 0;
+    this->decodePos = 0;
+    this->rawPos = 0;
+
+    this->failed = false;
+}
+
+SlipBIO::~SlipBIO() {}
+
+int SlipBIO::write( const char* buf, int num ) {
+    int badOnes = 0;
+
+    for( int i = 0; i < num; i++ ) {
+        if( ( buf[i] == ( char )0xc0 ) || ( buf[i] == ( char )0xDB ) ) {
+            badOnes++;
+        }
+    }
+
+    int totalLen = num + badOnes + 2;
+    char* targetPtr = ( char* ) malloc( totalLen );
+
+    if( !targetPtr ) {
+        return -1;
+    }
+
+    std::shared_ptr<char> t = std::shared_ptr<char>( targetPtr, free );
+    int j = 0;
+    targetPtr[j++] = ( char )0xC0;
+
+    for( int i = 0; i < num; i++ ) {
+        if( buf[i] == ( char )0xc0 ) {
+            targetPtr[j++] = ( char )0xDB;
+            targetPtr[j++] = ( char )0xDC;
+        } else if( buf[i] == ( char )0xDB ) {
+            targetPtr[j++] = ( char )0xDB;
+            targetPtr[j++] = ( char )0xDD;
+        } else {
+            targetPtr[j++] = buf[i];
+        }
+    }
+
+    targetPtr[j++] = ( char )0xC0;
+
+    if( target->write( targetPtr, j ) != j ) {
+        throw "Error, target write failed";
+    }
+
+    std::cout << toHex( targetPtr, j ) << std::endl;
+    return num;
+}
+
+int SlipBIO::read( char* buf, int size ) {
+    if( ( unsigned int ) size < buffer.capacity() ) {
+        // fail...
+    }
+
+    // while we have no data to decode or unmasking does not yield a full package
+    while( decodePos >= rawPos || !unmask() ) {
+
+        // we have no data, read more
+        if( buffer.size() - rawPos < 64 ) {
+            // not enough space... package is too big
+            decodeTarget = 0;
+            failed = true;
+        }
+
+        int len = target->read( buffer.data() + rawPos, buffer.capacity() - rawPos );
+
+        if( len > 0 ) {
+            rawPos += len;
+        } else {
+            decodeTarget = 0;
+            failed = true;
+        }
+
+    }
+
+    // a package finished, return it
+    std::copy( buffer.data(), buffer.data() + decodeTarget, buf );
+    // move the buffer contents back
+
+    int len = decodeTarget;
+    decodeTarget = 0;
+
+    return len;
+}
+
+long SlipBIO::ctrl( int cmod, long arg1, void* arg2 ) {
+    ( void ) cmod;
+    ( void ) arg1;
+    ( void ) arg2;
+
+    return 0;
+}
+
+const char* SlipBIO::getName() {
+    return "SlipBIO";
+}
+
+bool SlipBIO::unmask() {
+    unsigned int j = decodeTarget;
+
+    for( unsigned int i = decodePos; i < rawPos; i++ ) {
+        if( buffer[i] == ( char ) 0xDB ) {
+            i++;
+
+            if( i >= rawPos ) {
+                decodeTarget = j;
+                buffer[decodeTarget] = buffer[i - 1];
+                decodePos = decodeTarget;
+                rawPos = decodePos + 1;
+                return 0;// no packet
+            } else if( buffer[i] == ( char )0xdc ) {
+                buffer[j++] = ( char ) 0xc0;
+            } else if( buffer[i] == ( char )0xdd ) {
+                buffer[j++] = ( char ) 0xdb;
+            } else {
+                decodeTarget = 0;
+                failed = true;
+                // failed package
+                // error
+            }
+        } else if( buffer[i] == ( char ) 0xc0 ) {
+            decodePos = i + 1;
+            decodeTarget = j;
+
+            // copy rest to bufferfer i to len
+            if( !failed ) {
+                return 1;
+            }
+
+            decodeTarget = 0;
+            failed = false;
+        } else {
+            buffer[j++] = buffer[i];
+        }
+    }
+
+    decodePos = j;
+    rawPos = j;
+    decodeTarget = j;
+
+    return 0;
+}
diff --git a/src/slipBio.h b/src/slipBio.h
new file mode 100644 (file)
index 0000000..76403c5
--- /dev/null
@@ -0,0 +1,32 @@
+#pragma once
+
+#include <memory>
+#include <vector>
+
+#include "bios.h"
+
+class SlipBIO : public OpensslBIO {
+private:
+    std::shared_ptr<OpensslBIO> target;
+
+    std::vector<char> buffer;
+
+    unsigned int decodeTarget;
+    unsigned int decodePos;
+    unsigned int rawPos;
+
+    bool failed;
+
+private:
+    bool unmask();
+
+public:
+    SlipBIO( std::shared_ptr<OpensslBIO> target );
+    ~SlipBIO();
+
+    virtual int write( const char* buf, int num );
+    virtual int read( char* buf, int size );
+    virtual long ctrl( int cmod, long arg1, void* arg2 );
+
+    static const char* getName();
+};
diff --git a/test/src/slipBioTest.cpp b/test/src/slipBioTest.cpp
new file mode 100644 (file)
index 0000000..a54637f
--- /dev/null
@@ -0,0 +1,108 @@
+#include <iostream>
+#include <cstring>
+
+#include <boost/test/unit_test.hpp>
+
+#include "bios.h"
+#include "slipBio.h"
+
+class OpensslBIOVector : public OpensslBIO {
+private:
+    std::vector<std::vector<char>>::iterator it, end;
+    std::vector<std::vector<char>> input;
+
+public:
+    std::vector<std::vector<char>> result = std::vector<std::vector<char>>();
+    OpensslBIOVector( std::vector<std::vector<char>> data ) {
+        input = data;
+        it = input.begin();
+        end = input.end();
+    }
+
+    int write( const char* buf, int num );
+    int read( char* buf, int size );
+    long ctrl( int cmod, long arg1, void* arg2 );
+
+    static const char* getName();
+};
+
+int OpensslBIOVector::write( const char* buf, int num ) {
+    result.push_back( std::vector<char>( buf, buf + num ) );
+    return num;
+}
+
+int OpensslBIOVector::read( char* buf, int size ) {
+    if( it == end ) {
+        return -1;
+    }
+
+    if( ( unsigned int ) size < it->size() ) {
+        throw "Error, to small buffer";
+    }
+
+    std::copy( it->begin(), it->end(), buf );
+    auto result = it->size();
+    it++;
+    return result;
+}
+
+long OpensslBIOVector::ctrl( int cmod, long arg1, void* arg2 ) {
+    ( void ) cmod;
+    ( void ) arg1;
+    ( void ) arg2;
+    return 0;
+}
+
+const char* OpensslBIOVector::getName() {
+    return "dummyBIO";
+}
+
+BOOST_AUTO_TEST_SUITE( TestSLIPBioWrapper )
+
+BOOST_AUTO_TEST_CASE( TestMockup ) {
+    std::vector<std::vector<char>> source = {{1, 2}, {1, 2, 3}, {1, 2, 3, 4}, {1, 2, 3, 4, 5}};
+
+    OpensslBIOVector* data = new OpensslBIOVector( source );
+
+    char buf[4096];
+
+    for( auto it = source.begin(); it != source.end(); it++ ) {
+        auto len = data->read( buf, sizeof( buf ) );
+        BOOST_CHECK_EQUAL( len, it->size() );
+        BOOST_CHECK_EQUAL_COLLECTIONS( buf, buf + len, it->begin(), it->end() );
+        BOOST_CHECK_EQUAL( data->write( buf, len ), len );
+    }
+
+    BOOST_CHECK_EQUAL( data->read( buf, sizeof( buf ) ), -1 );
+
+    for( unsigned int i = 0; i < source.size(); i++ ) {
+        BOOST_CHECK_EQUAL_COLLECTIONS( data->result[i].begin(), data->result[i].end(), source[i].begin(), source[i].end() );
+    }
+
+    delete data;
+}
+
+BOOST_AUTO_TEST_CASE( TestSLIP ) {
+    std::vector<std::vector<char>> source = { {1, 2, 3, 4, 5, ( char ) 0xc0, 1, ( char ) 0xc0}, {1, 2}, {( char ) 0xc0}, {1, ( char ) 0xdb}, {( char ) 0xdc}, {( char ) 0xc0, ( char )0xdb}, {( char ) 0xdd, 2}, {( char ) 0xc0}};
+    std::shared_ptr<OpensslBIOVector> data = std::shared_ptr<OpensslBIOVector>( new OpensslBIOVector( source ) );
+    char buf[4096];
+    SlipBIO* slip = new SlipBIO( data );
+    int res = slip->read( buf, sizeof( buf ) );
+    BOOST_CHECK_EQUAL( res, 5 );
+    res = slip->read( buf, sizeof( buf ) );
+    BOOST_CHECK_EQUAL( res, 1 );
+    res = slip->read( buf, sizeof( buf ) );
+    BOOST_CHECK_EQUAL( res, 2 );
+
+    res = slip->read( buf, sizeof( buf ) );
+    BOOST_CHECK_EQUAL( res, 2 );
+    char res2[] = {1, ( char ) 0xc0};
+    BOOST_CHECK_EQUAL_COLLECTIONS( buf, buf + 2, res2, res2 + 2 );
+
+    res = slip->read( buf, sizeof( buf ) );
+    BOOST_CHECK_EQUAL( res, 2 );
+    char res3[] = {( char ) 0xdb, 2};
+    BOOST_CHECK_EQUAL_COLLECTIONS( buf, buf + 2, res3, res3 + 2 );
+}
+
+BOOST_AUTO_TEST_SUITE_END()