/* Copyright (C) 2006-2007 Werner Dittmann 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, see . */ /** * @author Werner Dittmann */ #include #include #include #include #include using namespace std; state_t states[numberOfStates] = { {Initial, &ZrtpStateClass::evInitial }, {Detect, &ZrtpStateClass::evDetect }, {AckDetected, &ZrtpStateClass::evAckDetected }, {WaitCommit, &ZrtpStateClass::evWaitCommit }, {CommitSent, &ZrtpStateClass::evCommitSent }, {WaitDHPart2, &ZrtpStateClass::evWaitDHPart2 }, {WaitConfirm1, &ZrtpStateClass::evWaitConfirm1 }, {WaitConfirm2, &ZrtpStateClass::evWaitConfirm2 }, {WaitConfAck, &ZrtpStateClass::evWaitConfAck }, {WaitClearAck, &ZrtpStateClass::evWaitClearAck }, {SecureState, &ZrtpStateClass::evSecureState }, {WaitErrorAck, &ZrtpStateClass::evWaitErrorAck } }; static char* sendErrorText = "Cannot send data via RTP - connection or peer down?"; static char* sendErrorTextSrtp = "Cannot send data via SRTP - connection or peer down?"; static char* timerError = "Cannot start a timer - internal resources exhausted?"; static char* resendError = "Too much retries during ZRTP negotiation - connection or peer down?"; static char* internalProtocolError = "Internal protocol error occured!"; static char* zrtpClosed = "No more security for this session"; static char* goClearReceived = "Received a GoClear message - no security processing!"; ZrtpStateClass::ZrtpStateClass(ZRtp *p) { parent = p; engine = new ZrtpStates(states, numberOfStates, Initial); // Set up timers according to ZRTP spec T1.start = 50; T1.maxResend = 20; T1.capping = 200; T2.start = 150; T2.maxResend = 10; T2.capping = 600; } ZrtpStateClass::~ZrtpStateClass(void) { if (engine != NULL) { delete engine; } } int32_t ZrtpStateClass::processEvent(Event_t *ev) { /* * Ignore any events except Initial if we are not really * started yet. */ if (inState(Initial) && !(ev->type == ZrtpInitial)) { return (Done); } event = ev; char *msg, first, last; uint8_t *pkt; if (event->type == ZrtpPacket) { pkt = event->data.packet; msg = (char *)pkt + 4; first = tolower(*msg); last = tolower(*(msg+4)); // Check if this is an Error packet. if (first == 'e' && last =='r') { /* * Process a received Error packet. * * Use callback method to prepare and get an ErrorAck packet. Send this * to our peer and reset to protocol engine to Initial state. */ ZrtpPacketError* epkt = new ZrtpPacketError(pkt); ZrtpPacketErrorAck* eapkt = parent->prepareErrorAck(epkt); delete epkt; parent->sendPacketZRTP(static_cast(eapkt)); nextState(Initial); return (Done); } } return engine->processEvent(*this); } int32_t ZrtpStateClass::evInitial(void) { DEBUGOUT((cout << "Checking for match in Initial.\n")); if (event->type == ZrtpInitial) { ZrtpPacketHello *hello = parent->prepareHello(); // remember packet for easy resend in case timer triggers sentPacket = static_cast(hello); if (!parent->sendPacketZRTP(static_cast(hello)) || (startTimer(&T1) <= 0)) { nextState(Initial); parent->sendInfo(Error, sendErrorText); return(Fail); } nextState(Detect); } return (Done); } /** * Detect state. * * When in this state the protocol engine sent an Hello packet to the peer. * When entering this state transition function then: * - Assume Initiator mode, mode may change later on peer reaction * - Instance variable sentPacket contains the sent Hello packet * - Hello timer T1 is active * * Possible events in this state are: * timeout for sent Hello packet - causes a resend check an possible resend of * Hello packet * received a Commit - stop active timer, prepare a DHPart1 packet, switch to * Resonder mode * received a HelloAck - stop active timer, prepare and send Hello packet. * received a Hello - stop active timer, prepare and send Commit packet. * * Refer to state event diagram to see which are valid next states. */ int32_t ZrtpStateClass::evDetect(void) { DEBUGOUT((cout << "Checking for match in Detect.\n")); char *msg, first, last; uint8_t *pkt; uint32_t errorCode = 0; /* * First check the general event type, then discrimnate * the real event. */ if (event->type == ZrtpPacket) { pkt = event->data.packet; msg = (char *)pkt + 4; first = tolower(*msg); last = tolower(*(msg+7)); /* * Commit: * The peer answers with Commit to our Hello, thus switch to * responder mode. * - prepare and send our DHPart1 * - switch to state WaitDHPart2 and wait for peer's DHPart2 * - don't start timer, we are responder */ if (first == 'c') { ZrtpPacketCommit *cpkt = new ZrtpPacketCommit(pkt); // Only if ZRTP CRC is ok then accept packet and process event cancelTimer(); // stop Hello timer processing, don't delete a Hello packet sentPacket = NULL; // TODO: check for multistream request ZrtpPacketDHPart* dhPart1 = parent->prepareDHPart1(cpkt, &errorCode); delete cpkt; // Something went wrong during processing of the commit packet if (dhPart1 == NULL) { sendErrorPacket(errorCode); return (Done); } nextState(WaitDHPart2); if (!parent->sendPacketZRTP(static_cast(dhPart1))) { delete dhPart1; nextState(Initial); parent->sendInfo(Error, sendErrorText); return(Fail); } // remember packet for easy resend in new state sentPacket = static_cast(dhPart1); return (Done); } /* * HelloAck: * - stop resending Hello, * - switch to state AckDetected, wait for peer's Hello (F3) */ if (first == 'h' && last =='k') { cancelTimer(); // stop Hello timer processing, don't delete my Hello packet sentPacket = NULL; nextState(AckDetected); return (Done); } /* * Hello: * - stop Hello timer * - prepare and send my Commit, * - switch state to CommitSent, start Commit timer, assume Initiator */ if (first == 'h' && last ==' ') { ZrtpPacketHello *hpkt = new ZrtpPacketHello(pkt); cancelTimer(); parent->sendPacketZRTP(sentPacket); // just resend Hello in case peer missed ours sentPacket = NULL; ZrtpPacketCommit* commit = parent->prepareCommit(hpkt, &errorCode); delete hpkt; // Something went wrong during processing of the Hello packet if (commit == NULL) { sendErrorPacket(errorCode); return (Done); } nextState(CommitSent); // remember packet for easy resend in case timer triggers // Timer trigger received in new state CommitSend sentPacket = static_cast(commit); if (!parent->sendPacketZRTP(static_cast(commit)) || (startTimer(&T2) <= 0)) { delete sentPacket; sentPacket = NULL; nextState(Initial); parent->zrtpNegotiationFailed(Error, sendErrorText); return(Fail); } return (Done); } return (Done); // unknown packet for this state - Just ignore it } // Timer event triggered - this is Timer T1 to resend Hello else if (event->type == Timer) { if (sentPacket != NULL) { if ((nextTimer(&T1)) <= 0 || !parent->sendPacketZRTP(sentPacket)) { parent->zrtpNotSuppOther(); sentPacket = NULL; // Stay in state Detect to be prepared get an hello from // other peer any time later nextState(Detect); return (Fail); } } return (Done); } else { // unknown Event type for this state parent->sendInfo(Error, internalProtocolError); sentPacket = NULL; nextState(Initial); return (Fail); } } /* * When entering this transition function * - sentPacket contains NULL, Hello timer stopped */ int32_t ZrtpStateClass::evAckDetected(void) { DEBUGOUT((cout << "Checking for match in AckDetected.\n")); char *msg, first, last; uint8_t *pkt; uint32_t errorCode = 0; if (event->type == ZrtpPacket) { pkt = event->data.packet; msg = (char *)pkt + 4; first = tolower(*msg); last = tolower(*(msg+7)); /* * Hello: * - Acknowledge my peers Hello, sending HelloACK (F4) * - switch to state WaitCommit, wait for peer's Commit * - we are going to be in the Responder role */ if (first == 'h') { // NOTE: may be useful if protocol state engine changes (preshared mode) // ZrtpPacketHello *hpkt = new ZrtpPacketHello(pkt); ZrtpPacketHelloAck *helloAck = parent->prepareHelloAck(); // delete hpkt; nextState(WaitCommit); if (!parent->sendPacketZRTP(static_cast(helloAck))) { nextState(Initial); sentPacket = NULL; parent->sendInfo(Error, sendErrorText); return(Fail); } // remember packet for easy resend sentPacket = static_cast(helloAck); return (Done); } /* * Commit: * - act as Responder * - send our DHPart1 * - switch to state WaitDHPart2, wait for peer's DHPart2 * - don't start timer, we are responder */ if (first == 'c') { ZrtpPacketCommit *cpkt = new ZrtpPacketCommit(pkt); ZrtpPacketDHPart* dhPart1 = parent->prepareDHPart1(cpkt, &errorCode); delete cpkt; // Something went wrong during processing of the Commit packet if (dhPart1 == NULL) { sendErrorPacket(errorCode); return (Done); } nextState(WaitDHPart2); if (!parent->sendPacketZRTP(static_cast(dhPart1))) { delete dhPart1; sentPacket = NULL; nextState(Initial); parent->sendInfo(Error, sendErrorText); return(Fail); } // remember packet for easy resend in new state sentPacket = static_cast(dhPart1); return (Done); } return (Done); // unknown packet for this state - Just ignore it } else { parent->sendInfo(Error, internalProtocolError); sentPacket = NULL; nextState(Initial); return (Fail); } } /* * When entering this transition function * - Responder mode * - sentPacket contains a HelloAck packet */ int32_t ZrtpStateClass::evWaitCommit(void) { DEBUGOUT((cout << "Checking for match in WaitCommit.\n")); char *msg, first, last; uint8_t *pkt; uint32_t errorCode = 0; if (event->type == ZrtpPacket) { pkt = event->data.packet; msg = (char *)pkt + 4; first = tolower(*msg); last = tolower(*(msg+7)); /* * Hello: * - resend HelloAck * - stay in WaitCommit */ if (first == 'h') { ZrtpPacketHello *hpkt = new ZrtpPacketHello(pkt); delete hpkt; if (!parent->sendPacketZRTP(sentPacket)) { nextState(Initial); sentPacket = NULL; // don't delete HelloAck, it's preconfigured parent->sendInfo(Error, sendErrorText); return(Fail); } return (Done); } /* * Commit: * - prepare DH1Part packet * - send it to peer * - switch state to WaitDHPart2 * - don't start timer, we are responder */ if (first == 'c') { ZrtpPacketCommit *cpkt = new ZrtpPacketCommit(pkt); sentPacket = NULL; ZrtpPacketDHPart* dhPart1 = parent->prepareDHPart1(cpkt, &errorCode); delete cpkt; // Something went wrong during processing of the Commit packet if (dhPart1 == NULL) { sendErrorPacket(errorCode); return (Done); } nextState(WaitDHPart2); if (!parent->sendPacketZRTP(static_cast(dhPart1))){ delete dhPart1; nextState(Initial); parent->sendInfo(Error, sendErrorText); return(Fail); } sentPacket = static_cast(dhPart1); return (Done); } return (Done); // unknown packet for this state - Just ignore it } else { parent->sendInfo(Error, internalProtocolError); sentPacket = NULL; // Don't delet sent packet - it's a fixed helloack nextState(Initial); return (Fail); } } /* * When entering this transition function * - assume Initiator mode, may change if we reveice a Commit here * - sentPacket contains Commit packet, Hello timer stopped, Commit timer active */ int32_t ZrtpStateClass::evCommitSent(void) { DEBUGOUT((cout << "Checking for match in CommitSend.\n")); char *msg, first, last; uint8_t *pkt; uint32_t errorCode = 0; if (event->type == ZrtpPacket) { pkt = event->data.packet; msg = (char *)pkt + 4; first = tolower(*msg); last = tolower(*(msg+7)); /* * HelloAck: * - late "helloAck", maybe due to network latency, just ignore it * - no switch in state, leave timer as it is */ if (first == 'h' && last =='k') { return (Done); } /* * Commit: * We have a "Commit" clash. Resolve it. * * - switch off resending Commit * - compare my hvi with peer's hvi * - if my hvi is greater * - we are Initiator, stay in state, wait for peer's DHPart1 packet * - else * - we are Responder, stop timer * - prepare and send DH1Packt, * - switch to state WaitDHPart2, implies Responder path */ if (first == 'c') { ZrtpPacketCommit *zpCo = new ZrtpPacketCommit(pkt); sentPacket = NULL; cancelTimer(); // this cancels the Commit timer T2 // if our hvi is less then peer's hvi - we are Responder and need // to send DHPart1 packet. Peer (as Initiator) will retrigger if // necessary if (parent->compareHvi(zpCo) < 0) { delete sentPacket; // delete our sent Commit packet sentPacket = NULL; ZrtpPacketDHPart* dhPart1 = parent->prepareDHPart1(zpCo, &errorCode); // Something went wrong during processing of the Commit packet if (dhPart1 == NULL) { sendErrorPacket(errorCode); return (Done); } nextState(WaitDHPart2); if (!parent->sendPacketZRTP(static_cast(dhPart1))){ delete dhPart1; delete zpCo; nextState(Initial); parent->sendInfo(Error, sendErrorText); return(Fail); } sentPacket = static_cast(dhPart1); } // Stay in state, we are Initiator, wait for DHPart1 packet from peer. // Resend Commit after timeout until we get a DHPart1 else { if (startTimer(&T2) <= 0) { // restart the Commit timer, gives peer more time to react delete sentPacket; sentPacket = NULL; nextState(Initial); parent->sendInfo(Error, timerError); return(Fail); } } delete zpCo; return (Done); } /* * DHPart1: * - switch off resending Commit * - Prepare and send DHPart2 * - switch to WaitConfirm1 * - start timer to resend DHPart2 if necessary, we are Initiator * - switch on SRTP */ if (first == 'd') { ZrtpPacketDHPart* dpkt = new ZrtpPacketDHPart(pkt); cancelTimer(); delete sentPacket; // deletes the Commit packet sentPacket = NULL; ZrtpPacketDHPart* dhPart2 = parent->prepareDHPart2(dpkt, &errorCode); delete dpkt; // Something went wrong during processing of the DHPart1 packet if (dhPart2 == NULL) { sendErrorPacket(errorCode); return (Done); } nextState(WaitConfirm1); sentPacket = static_cast(dhPart2); if (!parent->sendPacketZRTP(static_cast(dhPart2)) || (startTimer(&T2) <= 0) ){ delete sentPacket; sentPacket = NULL; nextState(Initial); parent->sendInfo(Error, sendErrorText); return(Fail); } return (Done); } return (Done); // unknown packet for this state - Just ignore it } // Timer event triggered, resend the Commit packet else if (event->type == Timer) { if (sentPacket != NULL) { if ((nextTimer(&T2) <= 0) || !parent->sendPacketZRTP(sentPacket)) { parent->sendInfo(Error, resendError); delete sentPacket; sentPacket = NULL; nextState(Initial); return (Fail); } } return (Done); } else { // unknown Event type for this state parent->sendInfo(Error, internalProtocolError); delete sentPacket; sentPacket = NULL; nextState(Initial); return (Fail); } } /* * When entering this transition function * - sentPacket contains DHPart1 packet, no timer active */ int32_t ZrtpStateClass::evWaitDHPart2(void) { DEBUGOUT((cout << "Checking for match in DHPart2.\n")); char *msg, first, last; uint8_t *pkt; uint32_t errorCode = 0; if (event->type == ZrtpPacket) { pkt = event->data.packet; msg = (char *)pkt + 4; first = tolower(*msg); last = tolower(*(msg+7)); /* * Commit: * - resend DHPart1 * - stay in state */ if (first == 'c') { // ZrtpPacketCommit *zpCo = new ZrtpPacketCommit(pkt); TODO if (!parent->sendPacketZRTP(sentPacket)) { delete sentPacket; sentPacket = NULL; nextState(Initial); parent->sendInfo(Error, sendErrorText); return(Fail); } return (Done); } /* * DHPart2: * - prepare Confirm1 packet * - switch to WaitConfirm2 * - switch on SRTP * - No timer, we are responder */ if (first == 'd') { ZrtpPacketDHPart* dpkt = new ZrtpPacketDHPart(pkt); delete sentPacket; // delete DHPart1 packet sentPacket = NULL; ZrtpPacketConfirm* confirm = parent->prepareConfirm1(dpkt, &errorCode); delete dpkt; if (confirm == NULL) { sendErrorPacket(errorCode); return (Done); } nextState(WaitConfirm2); if (!parent->sendPacketZRTP(static_cast(confirm))){ delete confirm; nextState(Initial); parent->sendInfo(Error, sendErrorTextSrtp); return(Fail); } sentPacket = static_cast(confirm); return (Done); } return (Done); // unknown packet for this state - Just ignore it } else { // unknown Event type for this state parent->sendInfo(Error, internalProtocolError); delete sentPacket; sentPacket = NULL; nextState(Initial); return (Fail); } } /* * When entering this transition function * - Initiator mode * - sentPacket contains DHPart2 packet, DHPart2 timer active */ int32_t ZrtpStateClass::evWaitConfirm1(void) { DEBUGOUT((cout << "Checking for match in WaitConfirm1.\n")); char *msg, first, last; uint8_t *pkt; uint32_t errorCode = 0; if (event->type == ZrtpPacket) { pkt = event->data.packet; msg = (char *)pkt + 4; first = tolower(*msg); last = tolower(*(msg+7)); /* * Confirm1: * - Switch off resending DHPart2 * - prepare a Confirm2 packet * - switch to state WaitConfAck * - set timer to monitor Confirm2 packet, we are initiator */ if (first == 'c' && last == '1') { ZrtpPacketConfirm* cpkt = new ZrtpPacketConfirm(pkt); cancelTimer(); delete sentPacket; // delete DHPart2 packet sentPacket = NULL; ZrtpPacketConfirm* confirm = parent->prepareConfirm2(cpkt, &errorCode); delete cpkt; // Something went wrong during processing of the Confirm1 packet if (confirm == NULL) { sendErrorPacket(errorCode); return (Done); } nextState(WaitConfAck); sentPacket = static_cast(confirm); if (!parent->sendPacketZRTP(static_cast(confirm)) || (startTimer(&T2) <= 0)){ delete sentPacket; sentPacket = NULL; nextState(Initial); parent->sendInfo(Error, sendErrorText); return(Fail); } return (Done); } return (Done); // unknown packet for this state - Just ignore it } else if (event->type == Timer) { if (sentPacket != NULL) { if ((nextTimer(&T2) <= 0) || !parent->sendPacketZRTP(sentPacket)) { parent->sendInfo(Error, resendError); delete sentPacket; sentPacket = NULL; nextState(Initial); return (Fail); } } return (Done); } else { // unknown Event type for this state parent->sendInfo(Error, internalProtocolError); delete sentPacket; sentPacket = NULL; nextState(Initial); return (Fail); } } /* * When entering this transition function * - Responder mode * - sentPacket contains Confirm1 packet, no timer active * - Security switched on */ int32_t ZrtpStateClass::evWaitConfirm2(void) { DEBUGOUT((cout << "Checking for match in WaitConfirm2.\n")); char *msg, first, last; uint8_t *pkt; uint32_t errorCode = 0; if (event->type == ZrtpPacket) { pkt = event->data.packet; msg = (char *)pkt + 4; first = tolower(*msg); last = tolower(*(msg+7)); /* * DHPart2: * - resend Confirm1 packet via SRTP * - stay in state */ if (first == 'd') { if (!parent->sendPacketZRTP(sentPacket)) { delete sentPacket; sentPacket = NULL; nextState(Initial); parent->sendInfo(Error, sendErrorText); return(Fail); } return (Done); } /* * Confirm2: * - prepare ConfAck * - switch on security * - switch to SecureState */ if (first == 'c' && last == '2') { // send ConfAck via SRTP ZrtpPacketConfirm* cpkt = new ZrtpPacketConfirm(pkt); delete sentPacket; // delete Confirm1 packet sentPacket = NULL; ZrtpPacketConf2Ack* confack = parent->prepareConf2Ack(cpkt, &errorCode); delete cpkt; // Something went wrong during processing of the confirm2 packet if (confack == NULL) { sendErrorPacket(errorCode); return (Done); } nextState(SecureState); if (!parent->sendPacketZRTP(static_cast(confack))){ sentPacket = NULL; // don't delete conf2Ack packet, it's preconfigured nextState(Initial); parent->sendInfo(Error, sendErrorTextSrtp); return(Fail); } sentPacket = static_cast(confack); parent->sendInfo(Info, "Switching to secure state"); // TODO: error handling here parent->srtpSecretsReady(ForSender); parent->srtpSecretsReady(ForReceiver); return (Done); } return (Done); // unknown packet for this state - Just ignore it } else { // unknown Event type for this state parent->sendInfo(Error, internalProtocolError); delete sentPacket; sentPacket = NULL; nextState(Initial); return (Fail); } } /* * When entering this transition function * - Initiator mode * - sentPacket contains Confirm2 packet, Confirm2 timer active * - sender and receiver security switched on */ int32_t ZrtpStateClass::evWaitConfAck(void) { DEBUGOUT((cout << "Checking for match in WaitConfAck.\n")); char *msg, first, last; uint8_t *pkt; if (event->type == ZrtpPacket) { pkt = event->data.packet; msg = (char *)pkt + 4; first = tolower(*msg); last = tolower(*(msg+7)); /* * ConfAck: * - Switch off resending Confirm2 * - switch to SecureState */ if (first == 'c') { cancelTimer(); delete sentPacket; sentPacket = NULL; parent->sendInfo(Info, "Switching to secure state"); nextState(SecureState); // TODO: error handling here parent->srtpSecretsReady(ForSender); parent->srtpSecretsReady(ForReceiver); return (Done); } return (Done); // unknown packet for this state - Just ignore it } else if (event->type == Timer) { if (sentPacket != NULL) { if ((nextTimer(&T2) <= 0) || !parent->sendPacketZRTP(sentPacket)) { parent->sendInfo(Error, resendError); delete sentPacket; sentPacket = NULL; nextState(Initial); parent->srtpSecretsOff(ForSender); parent->srtpSecretsOff(ForReceiver); return (Fail); } } return (Done); } else { // another Event type for this state parent->sendInfo(Error, internalProtocolError); delete sentPacket; sentPacket = NULL; nextState(Initial); return (Fail); } } /* * When entering this transition function * - sentPacket contains GoClear packet, GoClear timer active * The GoClear packet should no be deleted because it is a static packet. */ int32_t ZrtpStateClass::evWaitClearAck(void) { DEBUGOUT((cout << "Checking for match in ClearAck.\n")); char *msg, first, last; uint8_t *pkt; if (event->type == ZrtpPacket) { pkt = event->data.packet; msg = (char *)pkt + 4; first = tolower(*msg); last = tolower(*(msg+7)); /* * ClearAck: * - stop resending GoClear, * - switch to state AckDetected, wait for peer's Hello */ if (first == 'c' && last =='k') { cancelTimer(); // stop send go clear timer processing, don't delete this GoClear packet sentPacket = NULL; nextState(Initial); } return (Done); // unknown packet for this state - Just ignore it } // Timer event triggered - this is Timer T2 to resend GoClear w/o HMAC else if (event->type == Timer) { if (sentPacket != NULL) { if ((nextTimer(&T2)) <= 0 || !parent->sendPacketZRTP(sentPacket)) { parent->sendInfo(Error, resendError); sentPacket = NULL; nextState(Initial); return (Fail); } } return (Done); } else { // unknown Event type for this state parent->sendInfo(Error, internalProtocolError); sentPacket = NULL; nextState(Initial); return (Fail); } } /* * When entering this transition function * - sentPacket contains Error packet, Error timer active ?? TODO * The Error packet should no be deleted because it is a static packet. */ int32_t ZrtpStateClass::evWaitErrorAck(void) { DEBUGOUT((cout << "Checking for match in ErrorAck.\n")); char *msg, first, last; uint8_t *pkt; if (event->type == ZrtpPacket) { pkt = event->data.packet; msg = (char *)pkt + 4; first = tolower(*msg); last = tolower(*(msg+7)); /* * ClearAck: * - stop resending GoClear, * - switch to state AckDetected, wait for peer's Hello */ if (first == 'e' && last =='k') { cancelTimer(); // stop send Error timer processing, don't delete Error packet sentPacket = NULL; nextState(Initial); } return (Done); } // Timer event triggered - this is Timer T2 to resend Error. else if (event->type == Timer) { if (sentPacket != NULL) { if ((nextTimer(&T2)) <= 0 || !parent->sendPacketZRTP(sentPacket)) { parent->sendInfo(Error, resendError); sentPacket = NULL; nextState(Initial); return (Fail); } } return (Done); } else { // unknown Event type for this state parent->sendInfo(Error, internalProtocolError); sentPacket = NULL; nextState(Initial); return (Fail); } } int32_t ZrtpStateClass::evSecureState(void) { DEBUGOUT((cout << "Checking for match in SecureState.\n")); char *msg, first, last; uint8_t *pkt; if (event->type == ZrtpPacket) { pkt = event->data.packet; msg = (char *)pkt + 4; first = tolower(*msg); last = tolower(*(msg+7)); /* * Confirm2: * - resend ConfAck packet * - stay in state * - don't delete this confAck packet - it's preconfigured */ if (first == 'c' && last == '2') { if (sentPacket != NULL && !parent->sendPacketZRTP(sentPacket)) { sentPacket = NULL; // don't delete confAck packet, it's preconfigured nextState(Initial); parent->srtpSecretsOff(ForSender); parent->srtpSecretsOff(ForReceiver); parent->sendInfo(Error, sendErrorTextSrtp); return(Fail); } return (Done); } /* * GoClear received, handle it. TODO fix go clear handling */ if (first == 'g' && last == 'r') { ZrtpPacketGoClear* gpkt = new ZrtpPacketGoClear(pkt); ZrtpPacketClearAck* clearAck = parent->prepareClearAck(gpkt); delete gpkt; if (!parent->sendPacketZRTP(static_cast(clearAck))) { return(Done); } // TODO Timeout to resend clear ack until user user confirmation } } else { sentPacket = NULL; parent->srtpSecretsOff(ForSender); parent->srtpSecretsOff(ForReceiver); nextState(Initial); parent->sendInfo(Info, zrtpClosed); } return (Done); } int32_t ZrtpStateClass::startTimer(zrtpTimer_t *t) { t->time = t->start; t->counter = 0; return parent->activateTimer(t->time); } int32_t ZrtpStateClass::nextTimer(zrtpTimer_t *t) { t->time += t->time; t->time = (t->time > t->capping)? t->capping : t->time; t->counter++; if (t->counter > t->maxResend) { return -1; } return parent->activateTimer(t->time); } int32_t ZrtpStateClass::sendErrorPacket(uint32_t errorCode) { ZrtpPacketError* err = parent->prepareError(errorCode); if (!parent->sendPacketZRTP(static_cast(err)) || (startTimer(&T2) <= 0)) { nextState(Initial); parent->sendInfo(Error, sendErrorText); return (Fail); } sentPacket = static_cast(err); nextState(WaitErrorAck); return (Done); } /** EMACS ** * Local variables: * mode: c++ * c-default-style: ellemtel * c-basic-offset: 4 * End: */