int confirm()

in nanofi/src/sitetosite/CRawSocketProtocol.c [550:689]


int confirm(struct CRawSiteToSiteClient * client, const char * transactionID) {
  if (client->_peer_state != READY) {
    bootstrap(client);
  }

  if (client->_peer_state != READY) {
    return -1;
  }

  CTransaction* transaction = findTransaction(client, transactionID);

  if (!transaction) {
    return -1;
  }

  if (getState(transaction) == TRANSACTION_STARTED && isDataAvailable(transaction) == 0 && getDirection(transaction) == RECEIVE) {
    transaction->_state = TRANSACTION_CONFIRMED;
    return 0;
  }

  if (getState(transaction) != DATA_EXCHANGED)
    return -1;

  if (getDirection(transaction) == RECEIVE) {
    if (isDataAvailable(transaction) != 0)
      return -1;

    // we received a FINISH_TRANSACTION indicator. Send back a CONFIRM_TRANSACTION message
    // to peer so that we can verify that the connection is still open. This is a two-phase commit,
    // which helps to prevent the chances of data duplication. Without doing this, we may commit the
    // session and then when we send the response back to the peer, the peer may have timed out and may not
    // be listening. As a result, it will re-send the data. By doing this two-phase commit, we narrow the
    // Critical Section involved in this transaction so that rather than the Critical Section being the
    // time window involved in the entire transaction, it is reduced to a simple round-trip conversation.
    int64_t crcValue = getCRC(transaction);
    char crc[40];
    sprintf(crc, "%"PRId64, crcValue);

    logc(debug, "Site2Site Send confirm with CRC %"PRId64" to transaction %s", crcValue, transactionID);
    if (writeResponse(client, CONFIRM_TRANSACTION, crc) <= 0) {
      return -1;
    }

    RespondCode code;
    if (readResponse(client, &code) <= 0) {
      return -1;
    }

    RespondCodeContext *resCode = getRespondCodeContext(code);

    if (resCode == NULL) {
      logc(err, "Received invalid respond code: %d", code);
      return -1;
    }

    if (resCode->hasDescription) {
      uint32_t utflen;
      int ret = readUTFLen(&utflen, client->_peer->_stream);
      if (ret <= 0)
        return -1;
      memset(client->_description_buffer, 0, utflen+1);
      ret = readUTF(client->_description_buffer, utflen, client->_peer->_stream);
      if (ret <= 0)
        return -1;
    }

    if (code == CONFIRM_TRANSACTION) {
      logc(debug, "Site2Site transaction %s peer confirm transaction", transactionID);
      transaction->_state = TRANSACTION_CONFIRMED;
      return 0;
    } else if (code == BAD_CHECKSUM) {
      logc(debug, "Site2Site transaction %s peer indicate bad checksum", transactionID);
      return -1;
    } else {
      logc(debug, "Site2Site transaction %s peer unknown response code %d", transactionID, code);
      return -1;
    }
  } else {
    logc(debug, "Site2Site Send FINISH TRANSACTION for transaction %s", transactionID);
    if (writeResponse(client, FINISH_TRANSACTION, "FINISH_TRANSACTION") <= 0) {
      return -1;
    }

    RespondCode code;
    if (readResponse(client, &code) <= 0) {
      return -1;
    }

    RespondCodeContext *resCode = getRespondCodeContext(code);

    if (resCode == NULL) {
      logc(err, "Received invalid respond code: %d", code);
      return -1;
    }

    if (resCode->hasDescription) {
      uint32_t utflen;
      int ret = readUTFLen(&utflen, client->_peer->_stream);
      if (ret <= 0)
        return -1;
      memset(client->_description_buffer, 0, utflen+1);
      ret = readUTF(client->_description_buffer, utflen, client->_peer->_stream);
      if (ret <= 0)
        return -1;
    }

    // we've sent a FINISH_TRANSACTION. Now we'll wait for the peer to send a 'Confirm Transaction' response
    if (code == CONFIRM_TRANSACTION) {
      logc(debug, "Site2Site transaction %s peer confirm transaction with CRC %s", transactionID, client->_description_buffer);

      if (client->_currentVersion > 3) {
        int64_t crcValue = getCRC(transaction);
        char crc[40];
        memset(crc, 0, 40);
        sprintf(crc, "%"PRId64, crcValue);

        if (strcmp(client->_description_buffer, crc) == 0) {
          logc(debug, "Site2Site transaction %s CRC matched", transactionID);
          if (writeResponse(client, CONFIRM_TRANSACTION, "CONFIRM_TRANSACTION") <= 0) {
            return -1;
          }
          transaction->_state = TRANSACTION_CONFIRMED;
          return 0;
        } else {
          logc(warn, "Site2Site transaction %s CRC not matched %s", transactionID, crc);
          writeResponse(client, BAD_CHECKSUM, "BAD_CHECKSUM");
          return -1;
        }
      }
      if (writeResponse(client, CONFIRM_TRANSACTION, "CONFIRM_TRANSACTION") <= 0) {
        return -1;
      }
      transaction->_state = TRANSACTION_CONFIRMED;
      return 0;
    } else {
      logc(debug, "Site2Site transaction %s peer unknown respond code %d", transactionID, code);
      return -1;
    }
  }
}