1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "ChecksumCalculator.h" 18 19 #include <string.h> 20 21 // Checklist when implementing new protocol: 22 // 1. update CHECKSUMHELPER_MAX_VERSION 23 // 2. update ChecksumCalculator::Sizes enum 24 // 3. update checksumByteSize() 25 // 4. update addBuffer, writeChecksum, resetChecksum, validate 26 27 // change CHECKSUMHELPER_MAX_VERSION when you want to update the protocol version 28 #define CHECKSUMHELPER_MAX_VERSION 1 29 30 // utility macros to create checksum string at compilation time 31 #define CHECKSUMHELPER_VERSION_STR_PREFIX "ANDROID_EMU_CHECKSUM_HELPER_v" 32 #define CHECKSUMHELPER_MACRO_TO_STR(x) #x 33 #define CHECKSUMHELPER_MACRO_VAL_TO_STR(x) CHECKSUMHELPER_MACRO_TO_STR(x) 34 35 static const uint32_t kMaxVersion = CHECKSUMHELPER_MAX_VERSION; 36 static const char* kMaxVersionStrPrefix = CHECKSUMHELPER_VERSION_STR_PREFIX; 37 static const char* kMaxVersionStr = CHECKSUMHELPER_VERSION_STR_PREFIX CHECKSUMHELPER_MACRO_VAL_TO_STR(CHECKSUMHELPER_MAX_VERSION); 38 39 #undef CHECKSUMHELPER_MAX_VERSION 40 #undef CHECKSUMHELPER_VERSION_STR_PREFIX 41 #undef CHECKSUMHELPER_MACRO_TO_STR 42 #undef CHECKSUMHELPER_MACRO_VAL_TO_STR 43 44 uint32_t ChecksumCalculator::getMaxVersion() {return kMaxVersion;} 45 const char* ChecksumCalculator::getMaxVersionStr() {return kMaxVersionStr;} 46 const char* ChecksumCalculator::getMaxVersionStrPrefix() {return kMaxVersionStrPrefix;} 47 48 bool ChecksumCalculator::setVersion(uint32_t version) { 49 if (version > kMaxVersion) { // unsupported version 50 LOG_CHECKSUMHELPER("%s: ChecksumCalculator Set Unsupported version Version %d\n", 51 __FUNCTION__, m_version); 52 return false; 53 } 54 if (m_isEncodingChecksum) { // setVersion is called in the middle of encoding checksums 55 LOG_CHECKSUMHELPER("%s: called between addBuffer and writeChecksum\n", 56 __FUNCTION__); 57 return false; 58 } 59 m_version = version; 60 LOG_CHECKSUMHELPER("%s: ChecksumCalculator Set Version %d\n", __FUNCTION__, 61 m_version); 62 return true; 63 } 64 65 size_t ChecksumCalculator::checksumByteSize() const { 66 switch (m_version) { 67 case 0: 68 return 0; 69 case 1: 70 return sizeof(uint32_t) + sizeof(m_numWrite); 71 default: 72 return 0; 73 } 74 } 75 76 ChecksumCalculator::ChecksumCalculator() 77 : m_version(0) 78 , m_numRead(0) 79 , m_numWrite(0) 80 , m_isEncodingChecksum(false) 81 , m_v1BufferTotalLength(0) 82 { 83 } 84 85 void ChecksumCalculator::addBuffer(const void* buf, size_t packetLen) { 86 m_isEncodingChecksum = true; 87 switch (m_version) { 88 case 1: 89 m_v1BufferTotalLength += packetLen; 90 break; 91 } 92 } 93 94 bool ChecksumCalculator::writeChecksum(void* outputChecksum, size_t outputChecksumLen) { 95 if (outputChecksumLen < checksumByteSize()) return false; 96 char *checksumPtr = (char *)outputChecksum; 97 switch (m_version) { 98 case 1: { // protocol v1 is to reverse the packetLen and write it at the end 99 uint32_t val = computeV1Checksum(); 100 memcpy(checksumPtr, &val, sizeof(val)); 101 memcpy(checksumPtr+sizeof(val), &m_numWrite, sizeof(m_numWrite)); 102 break; 103 } 104 } 105 resetChecksum(); 106 m_numWrite++; 107 return true; 108 } 109 110 void ChecksumCalculator::resetChecksum() { 111 switch (m_version) { 112 case 1: 113 m_v1BufferTotalLength = 0; 114 break; 115 } 116 m_isEncodingChecksum = false; 117 } 118 119 bool ChecksumCalculator::validate(const void* expectedChecksum, size_t expectedChecksumLen) { 120 size_t checksumSize = checksumByteSize(); 121 if (expectedChecksumLen != checksumSize) { 122 m_numRead++; 123 resetChecksum(); 124 return false; 125 } 126 bool isValid; 127 switch (m_version) { 128 case 1: { 129 const uint32_t val = computeV1Checksum(); 130 isValid = 0 == memcmp(&val, expectedChecksum, sizeof(val)) && 131 0 == memcmp(&m_numRead, 132 static_cast<const char*>(expectedChecksum) + 133 sizeof(val), 134 sizeof(m_numRead)); 135 136 break; 137 } 138 default: 139 isValid = true; // No checksum is a valid checksum. 140 break; 141 } 142 m_numRead++; 143 resetChecksum(); 144 return isValid; 145 } 146 147 uint32_t ChecksumCalculator::computeV1Checksum() { 148 uint32_t revLen = m_v1BufferTotalLength; 149 revLen = (revLen & 0xffff0000) >> 16 | (revLen & 0x0000ffff) << 16; 150 revLen = (revLen & 0xff00ff00) >> 8 | (revLen & 0x00ff00ff) << 8; 151 revLen = (revLen & 0xf0f0f0f0) >> 4 | (revLen & 0x0f0f0f0f) << 4; 152 revLen = (revLen & 0xcccccccc) >> 2 | (revLen & 0x33333333) << 2; 153 revLen = (revLen & 0xaaaaaaaa) >> 1 | (revLen & 0x55555555) << 1; 154 return revLen; 155 } 156