* #35924: added zrtp module build instructions
diff --git a/jni/libzrtp/demo/zrtptestMulti.cpp b/jni/libzrtp/demo/zrtptestMulti.cpp
new file mode 100644
index 0000000..39e20a7
--- /dev/null
+++ b/jni/libzrtp/demo/zrtptestMulti.cpp
@@ -0,0 +1,715 @@
+// Test ZRTP extension for ccRTP
+//
+// Copyright (C) 2008 Werner Dittmann <Werner.Dittmann@t-online.de>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+#include <cstdlib>
+#include <map>
+#include <libzrtpcpp/zrtpccrtp.h>
+#include <libzrtpcpp/ZrtpUserCallback.h>
+#include <libzrtpcpp/ZrtpConfigure.h>
+
+using namespace ost;
+using namespace std;
+using namespace GnuZrtpCodes;
+
+/* maybe should be by special define...
+static void hexdump(const char* title, const unsigned char *s, int l) {
+    int n=0;
+
+    if (s == NULL) return;
+
+    fprintf(stderr, "%s",title);
+    for( ; n < l ; ++n)
+    {
+        if((n%16) == 0)
+            fprintf(stderr, "\n%04x",n);
+        fprintf(stderr, " %02x",s[n]);
+    }
+    fprintf(stderr, "\n");
+}
+*/
+
+class PacketsPattern
+{
+public:
+    inline const InetHostAddress&
+    getDestinationAddress() const
+    {
+        return destinationAddress;
+    }
+
+    inline const tpport_t
+    getDestinationPort() const
+    {
+        return destinationPort;
+    }
+
+    uint32
+    getPacketsNumber() const
+    {
+        return packetsNumber;
+    }
+
+    uint32
+    getSsrc() const
+    {
+        return 0xdeadbeef;
+    }
+
+    const unsigned char*
+    getPacketData(uint32 i)
+    {
+        return data[i%2];
+    }
+
+    const size_t
+    getPacketSize(uint32 i)
+    {
+        return strlen((char*)data[i%2]) + 1 ;
+    }
+
+private:
+    static const InetHostAddress destinationAddress;
+    static const uint16 destinationPort = 5002;
+    static const uint32 packetsNumber = 10;
+    static const uint32 packetsSize = 12;
+    static const unsigned char* data[];
+};
+
+const InetHostAddress PacketsPattern::destinationAddress =
+    InetHostAddress("localhost");
+
+const unsigned char* PacketsPattern::data[] = {
+    (unsigned char*)"0123456789\n",
+    (unsigned char*)"987654321\n"
+};
+
+PacketsPattern pattern;
+
+class ZrtpRecvPacketTransmissionTestCB;
+class ZrtpSendPacketTransmissionTestCB;
+class MyUserCallback;
+class MyUserCallbackMulti;
+
+static ZrtpRecvPacketTransmissionTestCB* zrxcb = NULL;
+static ZrtpSendPacketTransmissionTestCB* ztxcb = NULL;
+
+static ZrtpRecvPacketTransmissionTestCB* zrxcbMulti = NULL;
+static ZrtpSendPacketTransmissionTestCB* ztxcbMulti = NULL;
+
+static bool enroll = false;
+static bool mitm = false;
+static bool untrusted = false;
+static bool sender = false;
+static bool recver = false;
+static bool signsas = false;
+
+
+/**
+ * SymmetricZRTPSession in security mode and using a callback class.
+ *
+ * The next two classes show how to use <code>SymmetricZRTPSession</code>
+ * using the standard ZRTP handshake an switching to encrypted (SRTP) mode.
+ * The application enables this by calling <code>initialize(...)</code>.
+ * In addition the application sets a callback class (see above). ZRTP calls
+ * the methods of the callback class and the application may implement
+ * appropriate methods to deal with these triggers.
+ */
+
+class
+            ZrtpSendPacketTransmissionTestCB : public Thread, public TimerPort {
+
+private:
+    SymmetricZRTPSession* tx;
+    string multiParams;
+    string prefix;
+
+public:
+
+    ZrtpSendPacketTransmissionTestCB(): tx(NULL), multiParams("") {};
+
+    void run() {
+        doTest();
+    }
+
+    int doTest();
+
+    string getMultiStrParams() {
+        return tx->getMultiStrParams();
+    }
+
+    void setMultiStrParams(string params) {
+        multiParams = params;
+        return;
+    }
+};
+
+
+class
+            ZrtpRecvPacketTransmissionTestCB: public Thread {
+
+private:
+    SymmetricZRTPSession* rx;
+    string multiParams;
+    string prefix;
+
+public:
+    ZrtpRecvPacketTransmissionTestCB(): rx(NULL), multiParams("") {};
+
+    void run() {
+        doTest();
+    }
+
+    int doTest();
+
+    string getMultiStrParams() {
+        return rx->getMultiStrParams();
+    }
+
+    void setMultiStrParams(string params) {
+        multiParams = params;
+        return;
+    }
+};
+
+/**
+ * Simple User Callback class
+ *
+ * This class overwrite some methods from ZrtpUserCallback to get information
+ * about ZRTP processing and information about ZRTP results. The standard
+ * implementation of this class just perform return, thus effectively
+ * supressing any callback or trigger.
+ */
+class MyUserCallback: public ZrtpUserCallback {
+
+protected:
+    static map<int32, std::string*> infoMap;
+    static map<int32, std::string*> warningMap;
+    static map<int32, std::string*> severeMap;
+    static map<int32, std::string*> zrtpMap;
+    static map<int32, std::string*> enrollMap;
+
+
+    static bool initialized;
+
+    SymmetricZRTPSession* session;
+
+    std::string prefix;
+
+public:
+    MyUserCallback(SymmetricZRTPSession* s): session(s), prefix("default: ") {
+
+        if (initialized) {
+            return;
+        }
+        infoMap.insert(pair<int32, std::string*>(InfoHelloReceived, new string("Hello received, preparing a Commit")));
+        infoMap.insert(pair<int32, std::string*>(InfoCommitDHGenerated, new string("Commit: Generated a public DH key")));
+        infoMap.insert(pair<int32, std::string*>(InfoRespCommitReceived, new string("Responder: Commit received, preparing DHPart1")));
+        infoMap.insert(pair<int32, std::string*>(InfoDH1DHGenerated, new string("DH1Part: Generated a public DH key")));
+        infoMap.insert(pair<int32, std::string*>(InfoInitDH1Received, new string("Initiator: DHPart1 received, preparing DHPart2")));
+        infoMap.insert(pair<int32, std::string*>(InfoRespDH2Received, new string("Responder: DHPart2 received, preparing Confirm1")));
+        infoMap.insert(pair<int32, std::string*>(InfoInitConf1Received, new string("Initiator: Confirm1 received, preparing Confirm2")));
+        infoMap.insert(pair<int32, std::string*>(InfoRespConf2Received, new string("Responder: Confirm2 received, preparing Conf2Ack")));
+        infoMap.insert(pair<int32, std::string*>(InfoRSMatchFound, new string("At least one retained secrets matches - security OK")));
+        infoMap.insert(pair<int32, std::string*>(InfoSecureStateOn, new string("Entered secure state")));
+        infoMap.insert(pair<int32, std::string*>(InfoSecureStateOff, new string("No more security for this session")));
+
+        warningMap.insert(pair<int32, std::string*>(WarningDHAESmismatch,
+                          new string("Commit contains an AES256 cipher but does not offer a Diffie-Helman 4096")));
+        warningMap.insert(pair<int32, std::string*>(WarningGoClearReceived, new string("Received a GoClear message")));
+        warningMap.insert(pair<int32, std::string*>(WarningDHShort,
+                          new string("Hello offers an AES256 cipher but does not offer a Diffie-Helman 4096")));
+        warningMap.insert(pair<int32, std::string*>(WarningNoRSMatch, new string("No retained secret matches - verify SAS")));
+        warningMap.insert(pair<int32, std::string*>(WarningCRCmismatch, new string("Internal ZRTP packet checksum mismatch - packet dropped")));
+        warningMap.insert(pair<int32, std::string*>(WarningSRTPauthError, new string("Dropping packet because SRTP authentication failed!")));
+        warningMap.insert(pair<int32, std::string*>(WarningSRTPreplayError, new string("Dropping packet because SRTP replay check failed!")));
+        warningMap.insert(pair<int32, std::string*>(WarningNoExpectedRSMatch,
+                          new string("Valid retained shared secrets availabe but no matches found - must verify SAS")));
+
+        severeMap.insert(pair<int32, std::string*>(SevereHelloHMACFailed, new string("Hash HMAC check of Hello failed!")));
+        severeMap.insert(pair<int32, std::string*>(SevereCommitHMACFailed, new string("Hash HMAC check of Commit failed!")));
+        severeMap.insert(pair<int32, std::string*>(SevereDH1HMACFailed, new string("Hash HMAC check of DHPart1 failed!")));
+        severeMap.insert(pair<int32, std::string*>(SevereDH2HMACFailed, new string("Hash HMAC check of DHPart2 failed!")));
+        severeMap.insert(pair<int32, std::string*>(SevereCannotSend, new string("Cannot send data - connection or peer down?")));
+        severeMap.insert(pair<int32, std::string*>(SevereProtocolError, new string("Internal protocol error occured!")));
+        severeMap.insert(pair<int32, std::string*>(SevereNoTimer, new string("Cannot start a timer - internal resources exhausted?")));
+        severeMap.insert(pair<int32, std::string*>(SevereTooMuchRetries,
+                         new string("Too much retries during ZRTP negotiation - connection or peer down?")));
+
+        zrtpMap.insert(pair<int32, std::string*>(MalformedPacket, new string("Malformed packet (CRC OK, but wrong structure)")));
+        zrtpMap.insert(pair<int32, std::string*>(CriticalSWError, new string("Critical software error")));
+        zrtpMap.insert(pair<int32, std::string*>(UnsuppZRTPVersion, new string("Unsupported ZRTP version")));
+        zrtpMap.insert(pair<int32, std::string*>(HelloCompMismatch, new string("Hello components mismatch")));
+        zrtpMap.insert(pair<int32, std::string*>(UnsuppHashType, new string("Hash type not supported")));
+        zrtpMap.insert(pair<int32, std::string*>(UnsuppCiphertype, new string("Cipher type not supported")));
+        zrtpMap.insert(pair<int32, std::string*>(UnsuppPKExchange, new string("Public key exchange not supported")));
+        zrtpMap.insert(pair<int32, std::string*>(UnsuppSRTPAuthTag, new string("SRTP auth. tag not supported")));
+        zrtpMap.insert(pair<int32, std::string*>(UnsuppSASScheme, new string("SAS scheme not supported")));
+        zrtpMap.insert(pair<int32, std::string*>(NoSharedSecret, new string("No shared secret available, DH mode required")));
+        zrtpMap.insert(pair<int32, std::string*>(DHErrorWrongPV, new string("DH Error: bad pvi or pvr ( == 1, 0, or p-1)")));
+        zrtpMap.insert(pair<int32, std::string*>(DHErrorWrongHVI, new string("DH Error: hvi != hashed data")));
+        zrtpMap.insert(pair<int32, std::string*>(SASuntrustedMiTM, new string("Received relayed SAS from untrusted MiTM")));
+        zrtpMap.insert(pair<int32, std::string*>(ConfirmHMACWrong, new string("Auth. Error: Bad Confirm pkt HMAC")));
+        zrtpMap.insert(pair<int32, std::string*>(NonceReused, new string("Nonce reuse")));
+        zrtpMap.insert(pair<int32, std::string*>(EqualZIDHello, new string("Equal ZIDs in Hello")));
+        zrtpMap.insert(pair<int32, std::string*>(GoCleatNotAllowed, new string("GoClear packet received, but not allowed")));
+
+        enrollMap.insert(pair<int32, std::string*>(EnrollmentRequest, new string("Trusted MitM enrollment requested")));
+        enrollMap.insert(pair<int32, std::string*>(EnrollmentCanceled, new string("Trusted MitM enrollment canceled by user")));
+        enrollMap.insert(pair<int32, std::string*>(EnrollmentFailed, new string("Trusted MitM enrollment failed")));
+        enrollMap.insert(pair<int32, std::string*>(EnrollmentOk, new string("Trusted MitM enrollment OK")));
+
+        initialized = true;
+    }
+
+    void showMessage(GnuZrtpCodes::MessageSeverity sev, int32_t subCode) {
+        string* msg;
+        uint8_t sasHash[32];
+
+        if (sev == Info) {
+            msg = infoMap[subCode];
+            if (msg != NULL) {
+                cout << prefix << *msg << endl;
+            }
+            // this sets up and starts off the multi-stream test
+            if (subCode == InfoSecureStateOn) {
+                if (zrxcbMulti != NULL) {
+                    zrxcbMulti->setMultiStrParams(session->getMultiStrParams());
+                    zrxcbMulti->start();
+                }
+                if (ztxcbMulti != NULL) {
+                    ztxcbMulti->setMultiStrParams(session->getMultiStrParams());
+                    ztxcbMulti->start();
+                }
+                if (sender) {
+                    if (mitm && !enroll) {  // sender now acts as trusted PBX in normal mode, not in enrollement service
+                        std::string render = session->getSasType();
+                        for (int i = 0; i < 32; i++) {
+                            sasHash[i] = 0;
+                        }
+                        if (untrusted) {    // treat receiver as non-enrolled receiver
+                            cout << prefix << "send SAS relay to non-enrolled receiver" << endl;
+                            session->sendSASRelayPacket(sasHash, render);
+                        }
+                        else {
+                            sasHash[0] = 0x11;
+                            sasHash[1] = 0x22;
+                            sasHash[2] = 0x33;
+                            sasHash[4] = 0x44;
+                            cout << prefix << "send SAS relay to enrolled receiver" << endl;
+                            session->sendSASRelayPacket(sasHash, render);
+                        }
+                    }
+                }
+            }
+        }
+        if (sev == Warning) {
+            msg = warningMap[subCode];
+            if (msg != NULL) {
+                cout << prefix << *msg << endl;
+            }
+        }
+        if (sev == Severe) {
+            msg = severeMap[subCode];
+            if (msg != NULL) {
+                cout << prefix << *msg << endl;
+            }
+        }
+        if (sev == ZrtpError) {
+            if (subCode < 0) {  // received an error packet from peer
+                subCode *= -1;
+                cout << prefix << "Received error packet: ";
+            }
+            else {
+                cout << prefix << "Sent error packet: ";
+            }
+            msg = zrtpMap[subCode];
+            if (msg != NULL) {
+                cout << prefix << *msg << endl;
+            }
+        }
+    }
+
+    void zrtpNegotiationFailed(GnuZrtpCodes::MessageSeverity sev, int32_t subCode) {
+        string* msg;
+        if (sev == ZrtpError) {
+            if (subCode < 0) {  // received an error packet from peer
+                subCode *= -1;
+                cout << prefix << "Received error packet: ";
+            }
+            else {
+                cout << prefix << "Sent error packet: ";
+            }
+            msg = zrtpMap[subCode];
+            if (msg != NULL) {
+                cout << prefix << *msg << endl;
+            }
+        }
+        else {
+            msg = severeMap[subCode];
+            cout << prefix << *msg << endl;
+        }
+    }
+
+    void zrtpAskEnrollment(GnuZrtpCodes::InfoEnrollment info) {
+        string* msg = enrollMap[info];
+        cout << prefix << *msg << endl;
+        session->acceptEnrollment(true);
+    }
+
+    void zrtpInformEnrollment(GnuZrtpCodes::InfoEnrollment info) {
+        string* msg = enrollMap[info];
+        cout << prefix << *msg << endl;
+    }
+
+    void secureOn(std::string cipher) {
+        cout << prefix << "Using cipher:" << cipher << endl;
+        cout << prefix << "peer hello hash: " << session->getPeerHelloHash() << endl;
+    }
+
+    void showSAS(std::string sas, bool verified) {
+        cout << prefix << "SAS is: " << sas << endl;
+
+    }
+
+    void signSAS(uint8_t* sasHash) {
+        cout << prefix << "SAS to sign" << endl;
+        uint8_t sign[12];
+        sign[0] = sasHash[0];
+        sign[1] = sasHash[1];
+        sign[2] = sasHash[2];
+        sign[3] = sasHash[3];
+        if (recver) {
+            sign[4] = 'R';
+            sign[5] = 'E';
+            sign[6] = 'C';
+            sign[7] = 'E';
+            sign[8] = 'I';
+            sign[9] = 'V';
+            sign[10] = 'E';
+            sign[11] = 'R';
+        }
+        else {
+            sign[4] = 'T';
+            sign[5] = 'R';
+            sign[6] = 'A';
+            sign[7] = 'N';
+            sign[8] = 'S';
+            sign[9] = 'M';
+            sign[10] = 'I';
+            sign[11] = 'T';
+        }
+        cout << prefix << "set signature data result: " << session->setSignatureData(sign, 12) << endl;
+    }
+
+    bool checkSASSignature(uint8_t* sasHash) {
+        cout << prefix << "check signature" << endl;
+        const uint8_t* sign = session->getSignatureData();
+        cout << prefix << "signature: " << sign << endl;
+        return true;
+    }
+
+    void setPrefix(std::string p) {
+        prefix = p;
+    }
+};
+
+map<int32, std::string*>MyUserCallback::infoMap;
+map<int32, std::string*>MyUserCallback::warningMap;
+map<int32, std::string*>MyUserCallback::severeMap;
+map<int32, std::string*>MyUserCallback::zrtpMap;
+map<int32, std::string*>MyUserCallback::enrollMap;
+
+bool MyUserCallback::initialized = false;
+
+
+class MyUserCallbackMulti: public MyUserCallback {
+
+public:
+
+    MyUserCallbackMulti(SymmetricZRTPSession* s): MyUserCallback(s) {
+    }
+
+    void showMessage(GnuZrtpCodes::MessageSeverity sev, int32_t subCode) {
+        string* msg;
+        if (sev == Info) {
+            msg = infoMap[subCode];
+            if (msg != NULL) {
+                cout << prefix << *msg << endl;
+            }
+        }
+        if (sev == Warning) {
+            msg = warningMap[subCode];
+            if (msg != NULL) {
+                cout << prefix << *msg << endl;
+            }
+        }
+        if (sev == Severe) {
+            msg = severeMap[subCode];
+            if (msg != NULL) {
+                cout << prefix << *msg << endl;
+            }
+        }
+        if (sev == ZrtpError) {
+            if (subCode < 0) {  // received an error packet from peer
+                subCode *= -1;
+                cout << prefix << "Received error packet: ";
+            }
+            else {
+                cout << prefix << "Sent error packet: ";
+            }
+            msg = zrtpMap[subCode];
+            if (msg != NULL) {
+                cout << prefix << *msg << endl;
+            }
+        }
+    }
+};
+
+int ZrtpSendPacketTransmissionTestCB::doTest() {
+
+    ZrtpConfigure config;
+
+    MyUserCallback* mcb;
+    if (!multiParams.empty()) {
+        tx = new SymmetricZRTPSession(pattern.getDestinationAddress(),
+                                      pattern.getDestinationPort()+2+10);
+//            tx->initialize("test_t.zid", true, &config);
+        tx->initialize("test_t.zid", true);
+        tx->setMultiStrParams(multiParams);
+
+        prefix = "TX Multi: ";
+        mcb = new MyUserCallbackMulti(tx);
+        mcb->setPrefix(prefix);
+    }
+    else {
+        tx = new SymmetricZRTPSession(pattern.getDestinationAddress(),
+                                      pattern.getDestinationPort()+2);
+        //config.addHashAlgo(Sha384);
+//            tx->initialize("test_t.zid", true, &config);
+        if (mitm) {                      // Act as trusted MitM - could be enrolled
+            tx->setMitmMode(true);
+        }
+
+        tx->setSignSas(signsas);
+        tx->initialize("test_t.zid", true);
+
+        if (enroll)                     // act as PBX enrollement service
+            tx->setEnrollmentMode(true);
+
+        prefix = "TX: ";
+        mcb = new MyUserCallback(tx);
+        mcb->setPrefix(prefix);
+    }
+    // At this point the Hello hash is available. See ZRTP specification
+    // chapter 9.1 for further information when an how to use the Hello
+    // hash.
+    cout << prefix << "Hello hash: " << tx->getHelloHash() << endl;
+    cout << prefix << "Hello hash length: " << tx->getHelloHash().length() << endl;
+    tx->setUserCallback(mcb);
+    tx->setSchedulingTimeout(10000);
+    tx->setExpireTimeout(1000000);
+
+    tx->startRunning();
+
+    tx->setPayloadFormat(StaticPayloadFormat(sptPCMU));
+
+    if (!multiParams.empty()) {
+        if (!tx->addDestination(pattern.getDestinationAddress(),
+                                pattern.getDestinationPort()+10) ) {
+            return 1;
+        }
+    }
+    else {
+        if (!tx->addDestination(pattern.getDestinationAddress(),
+                                pattern.getDestinationPort()) ) {
+            return 1;
+        }
+    }
+    tx->startZrtp();
+
+    // 2 packets per second (packet duration of 500ms)
+    uint32 period = 500;
+    uint16 inc = tx->getCurrentRTPClockRate()/2;
+    TimerPort::setTimer(period);
+    uint32 i;
+    for (i = 0; i < pattern.getPacketsNumber(); i++ ) {
+        tx->putData(i*inc,
+                    pattern.getPacketData(i),
+                    pattern.getPacketSize(i));
+        cout << prefix << "Sent some data: " << i << endl;
+        Thread::sleep(TimerPort::getTimer());
+        TimerPort::incTimer(period);
+    }
+    tx->putData(i*inc, (unsigned char*)"exit", 5);
+    Thread::sleep(TimerPort::getTimer());
+    delete tx;
+    return 0;
+}
+
+
+int ZrtpRecvPacketTransmissionTestCB::doTest() {
+
+    ZrtpConfigure config;
+
+    MyUserCallback* mcb;
+    if (!multiParams.empty()) {
+        rx = new SymmetricZRTPSession(pattern.getDestinationAddress(),
+                                      pattern.getDestinationPort()+10);
+
+//            rx->initialize("test_r.zid", true, &config);
+        rx->initialize("test_r.zid", true);
+        rx->setMultiStrParams(multiParams);
+
+        prefix = "RX Multi: ";
+        mcb = new MyUserCallbackMulti(rx);
+        mcb->setPrefix(prefix);
+    }
+    else {
+        rx = new SymmetricZRTPSession(pattern.getDestinationAddress(),
+                                      pattern.getDestinationPort());
+        config.setStandardConfig();
+        if (enroll)
+            config.setTrustedMitM(true);                // allow a trusted MitM to start enrollment process
+
+        rx->setSignSas(signsas);
+
+        // config.addHashAlgo(Sha384);
+        rx->initialize("test_r.zid", true, &config);
+//            rx->initialize("test_r.zid", true);
+
+        prefix = "RX: ";
+        mcb = new MyUserCallback(rx);
+        mcb->setPrefix(prefix);
+    }
+    // At this point the Hello hash is available. See ZRTP specification
+    // chapter 9.1 for further information when an how to use the Hello
+    // hash.
+    cout << prefix << "Hello hash: " << rx->getHelloHash() << endl;
+    cout << prefix << "Hello hash length: " << rx->getHelloHash().length() << endl;
+    rx->setUserCallback(mcb);
+    rx->setSchedulingTimeout(10000);
+    rx->setExpireTimeout(1000000);
+
+    rx->startRunning();
+    rx->setPayloadFormat(StaticPayloadFormat(sptPCMU));
+    // arbitrary number of loops to provide time to start transmitter
+    if (!multiParams.empty()) {
+        if (!rx->addDestination(pattern.getDestinationAddress(),
+                                pattern.getDestinationPort()+2+10) ) {
+            return 1;
+        }
+    }
+    else {
+        if (!rx->addDestination(pattern.getDestinationAddress(),
+                                pattern.getDestinationPort()+2) ) {
+            return 1;
+        }
+    }
+//        rx->startZrtp();
+
+    for ( int i = 0; i < 5000 ; i++ ) {
+        const AppDataUnit* adu;
+        while ( (adu = rx->getData(rx->getFirstTimestamp())) ) {
+            cerr << prefix << "got some data: " << adu->getData() << endl;
+            if (*adu->getData() == 'e') {
+                delete adu;
+                delete rx;
+                return 0;
+            }
+            delete adu;
+        }
+        Thread::sleep(70);
+    }
+    delete rx;
+    return 0;
+}
+
+
+int main(int argc, char *argv[])
+{
+    int result = 0;
+
+    char c;
+
+    /* check args */
+    while (1) {
+        c = getopt(argc, argv, "rsSmeu");
+        if (c == -1) {
+            break;
+        }
+        switch (c) {
+        case 'r':
+            recver = true;
+            break;
+        case 's':
+            sender = true;
+            break;
+        case 'm':
+            mitm = true;
+            break;
+        case 'e':
+            enroll = true;
+            break;
+        case 'u':
+            untrusted = true;
+            break;
+        case 'S':
+            signsas = true;
+            break;
+        default:
+            cerr << "Wrong Arguments, only -s and -r are accepted" << endl;
+        }
+    }
+
+    if (sender || recver) {
+        if (sender) {
+            cout << "Running as sender" << endl;
+        }
+        else {
+            cout << "Running as receiver" << endl;
+        }
+    }
+    else {
+        cerr << "No send or receive argument specificied" << endl;
+        exit(1);
+    }
+
+    if ( sender ) {
+        ztxcb = new ZrtpSendPacketTransmissionTestCB();
+        ztxcbMulti = new ZrtpSendPacketTransmissionTestCB();
+        ztxcb->start();
+        ztxcb->join();
+        ztxcbMulti->join();
+    } else if ( recver ) {
+        zrxcb = new ZrtpRecvPacketTransmissionTestCB();
+        zrxcbMulti = new ZrtpRecvPacketTransmissionTestCB();
+        zrxcb->start();
+        zrxcb->join();
+        zrxcbMulti->join();
+    }
+
+    exit(result);
+}
+
+/** EMACS **
+ * Local variables:
+ * mode: c++
+ * c-default-style: ellemtel
+ * c-basic-offset: 4
+ * End:
+ */