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;
}
}
}