| /*========================================================================= |
| * Copyright (c) 2010-2014 Pivotal Software, Inc. All Rights Reserved. |
| * This product is protected by U.S. and international copyright |
| * and intellectual property laws. Pivotal products are covered by |
| * one or more patents listed at http://www.pivotal.io/patents. |
| *========================================================================= |
| */ |
| |
| #include "ClientProxyMembershipID.hpp" |
| #include <ace/OS.h> |
| #include "../DistributedSystem.hpp" |
| #include "../GemfireTypeIds.hpp" |
| #include "GemfireTypeIdsImpl.hpp" |
| #include "../CacheableBuiltins.hpp" |
| #include "Version.hpp" |
| #include <string> |
| |
| #define ADDRSIZE 4 |
| #define DCPORT 12334 |
| #define VMKIND 13 |
| #define ROLEARRLENGTH 0 |
| static int synch_counter = 2; |
| using namespace gemfire; |
| |
| std::string ClientProxyMembershipID::g_dsName("DSName"); |
| std::string ClientProxyMembershipID::g_randString("GFNative"); |
| #define RAND_STRING_LEN 10 |
| const int ClientProxyMembershipID::VERSION_MASK = 0x8; |
| const int8_t ClientProxyMembershipID::TOKEN_ORDINAL = -1; |
| |
| // initialize random string data and DistributedSystem name |
| void ClientProxyMembershipID::init(const std::string& dsName) |
| { |
| if (dsName.size() > 0) { |
| const char selectChars[] = |
| "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"; |
| const uint32_t numChars = (sizeof(selectChars) / sizeof(char)) - 1; |
| |
| g_dsName = dsName; |
| bool randDone = false; |
| char randString[RAND_STRING_LEN + 1]; |
| int pid = ACE_OS::getpid(); |
| // try /dev/urandom first |
| FILE* urandom = ACE_OS::fopen("/dev/urandom", "rb"); |
| if (urandom) { |
| LOGFINE("Opened /dev/urandom for ClientProxyMembershipID random data"); |
| uint8_t readBytes[RAND_STRING_LEN]; |
| size_t readLen = ACE_OS::fread(readBytes, RAND_STRING_LEN, 1, urandom); |
| if (readLen == 1) { |
| for (uint32_t index = 0; index < RAND_STRING_LEN; ++index) { |
| randString[index] = selectChars[readBytes[index] % numChars]; |
| } |
| randString[RAND_STRING_LEN] = '\0'; |
| randDone = true; |
| } |
| ACE_OS::fclose(urandom); |
| } |
| if (!randDone) { |
| // if urandom is not available then using current time and |
| // processor time would be good enough for our purpose |
| unsigned long seed = pid + ACE_OS::gettimeofday().msec() + |
| clock(); |
| seed += ACE_OS::gettimeofday().usec(); |
| //LOGINFO("PID %ld seed %ld ACE_OS::gettimeofday().usec() = %ld clock = %ld ACE_OS::gettimeofday().msec() = %ld", pid, seed , ACE_OS::gettimeofday().usec() , clock(), ACE_OS::gettimeofday().msec()); |
| ACE_OS::srand(seed); |
| for (uint32_t index = 0; index < RAND_STRING_LEN; ++index) { |
| randString[index] = selectChars[ACE_OS::rand() % numChars]; |
| } |
| randString[RAND_STRING_LEN] = '\0'; |
| } |
| char ps[15] = {0}; |
| ACE_OS::snprintf(ps, 15, "%d",pid); |
| g_randString = "GFNative_"; |
| g_randString.append(randString).append(ps); |
| LOGINFO("Using %s as random data for ClientProxyMembershipID", g_randString.c_str()); |
| } |
| } |
| const std::string& ClientProxyMembershipID::getRandStringId() |
| { |
| return g_randString; |
| } |
| /* |
| // Commenting this function as this is not getting used anywhere. |
| ClientProxyMembershipID::ClientProxyMembershipID(const char *durableClientId, |
| const uint32_t durableClntTimeOut) |
| { |
| if( durableClientId != NULL && durableClntTimeOut != 0 ) { |
| DataOutput m_memID; |
| m_memID.write((int8_t)GemfireTypeIds::CacheableASCIIString); |
| m_memID.writeASCII(durableClientId); |
| CacheableInt32Ptr int32ptr = CacheableInt32::create(durableClntTimeOut); |
| int32ptr->toData(m_memID); |
| uint32_t len; |
| char* buf = (char*)m_memID.getBuffer(&len); |
| m_memIDStr.append(buf, len); |
| } |
| } |
| */ |
| ClientProxyMembershipID::ClientProxyMembershipID() |
| :m_hostAddr(NULL) |
| /* adongre - Coverity II |
| * CID 29278: Uninitialized scalar field (UNINIT_CTOR) |
| */ |
| ,m_hostAddrLen(0), |
| m_hostAddrLocalMem(false), |
| m_hostPort(0), |
| m_vmViewId(0) |
| { |
| |
| } |
| |
| ClientProxyMembershipID::~ClientProxyMembershipID() |
| { |
| if (m_hostAddrLocalMem) |
| delete[] m_hostAddr; |
| } |
| |
| ClientProxyMembershipID::ClientProxyMembershipID( const char* hostname, uint32_t hostAddr, uint32_t hostPort, |
| const char *durableClientId, |
| const uint32_t durableClntTimeOut) |
| { |
| int32_t vmPID = ACE_OS::getpid(); |
| |
| initObjectVars (hostname, (uint8_t*)&hostAddr, 4, false, hostPort, durableClientId, durableClntTimeOut , |
| DCPORT, vmPID,VMKIND, 0, g_dsName.c_str(), g_randString.c_str(), 0); |
| |
| } |
| |
| // This is only for unit tests and should not be used for any other purpose. See |
| // testEntriesMapForVersioning.cpp for more details |
| ClientProxyMembershipID::ClientProxyMembershipID( uint8_t* hostAddr, uint32_t hostAddrLen, uint32_t hostPort, |
| const char* dsname, const char* uniqueTag, uint32_t vmViewId) |
| { |
| int32_t vmPID = ACE_OS::getpid(); |
| initObjectVars ("localhost", hostAddr, hostAddrLen, false, hostPort, "", 0, |
| DCPORT, vmPID,VMKIND, 0, dsname, uniqueTag, vmViewId); |
| |
| } |
| void ClientProxyMembershipID::initObjectVars( const char* hostname, uint8_t* hostAddr, uint32_t hostAddrLen, |
| bool hostAddrLocalMem, uint32_t hostPort, const char *durableClientId, |
| const uint32_t durableClntTimeOut, int32_t dcPort, int32_t vPID, |
| int8_t vmkind, int8_t splitBrainFlag, const char* dsname, |
| const char* uniqueTag, uint32_t vmViewId) |
| { |
| DataOutput m_memID; |
| if (dsname == NULL) |
| m_dsname = std::string(""); |
| else |
| m_dsname = std::string(dsname); |
| m_hostPort = hostPort; |
| m_hostAddr = hostAddr; |
| m_hostAddrLen = hostAddrLen; |
| m_hostAddrLocalMem = hostAddrLocalMem; |
| if (uniqueTag == NULL) |
| m_uniqueTag = std::string(""); |
| else |
| m_uniqueTag = std::string(uniqueTag); |
| |
| m_vmViewId = vmViewId; |
| m_memID.write((int8_t)GemfireTypeIdsImpl::FixedIDByte); |
| m_memID.write((int8_t)GemfireTypeIdsImpl::InternalDistributedMember); |
| m_memID.writeArrayLen(ADDRSIZE); |
| // writing first 4 bytes of the address. This will be same until |
| // IPV6 support is added in the client |
| uint32_t temp; |
| memcpy(&temp, hostAddr, 4); |
| m_memID.writeInt((int32_t)temp); |
| //m_memID.writeInt((int32_t)hostPort); |
| m_memID.writeInt((int32_t)synch_counter); |
| m_memID.write((int8_t)GemfireTypeIds::CacheableASCIIString); |
| m_memID.writeASCII( hostname ); |
| m_memID.write(splitBrainFlag); // splitbrain flags |
| |
| m_memID.writeInt(dcPort); |
| |
| m_memID.writeInt(vPID); |
| m_memID.write(vmkind); |
| m_memID.writeArrayLen(ROLEARRLENGTH); |
| m_memID.write((int8_t)GemfireTypeIds::CacheableASCIIString); |
| m_memID.writeASCII(dsname); |
| m_memID.write((int8_t)GemfireTypeIds::CacheableASCIIString); |
| m_memID.writeASCII(uniqueTag); |
| |
| if( durableClientId != NULL && durableClntTimeOut != 0 ) { |
| m_memID.write((int8_t)GemfireTypeIds::CacheableASCIIString); |
| m_memID.writeASCII(durableClientId); |
| CacheableInt32Ptr int32ptr = CacheableInt32::create(durableClntTimeOut); |
| int32ptr->toData(m_memID); |
| } |
| writeVersion(Version::getOrdinal() , m_memID); |
| uint32_t len; |
| char* buf = (char*)m_memID.getBuffer(&len); |
| m_memIDStr.append(buf, len); |
| /* adongre - Coverity II |
| * CID 29206: Calling risky function (SECURE_CODING)[VERY RISKY]. Using "sprintf" can cause a |
| * buffer overflow when done incorrectly. Because sprintf() assumes an arbitrarily long string, |
| * callers must be careful not to overflow the actual space of the destination. |
| * Use snprintf() instead, or correct precision specifiers. |
| * Fix : using ACE_OS::snprintf |
| */ |
| char PID[15] = {0}; |
| char Synch_Counter[15] = {0}; |
| // ACE_OS::snprintf(PID, 15, "%d",vPID); |
| ACE_OS::itoa(vPID,PID, 10); |
| // ACE_OS::snprintf(Synch_Counter, 15, "%d",synch_counter); |
| ACE_OS::itoa(synch_counter,Synch_Counter, 10); |
| clientID.append(hostname); |
| clientID.append("("); |
| clientID.append(PID); |
| clientID.append(":loner):"); |
| clientID.append(Synch_Counter); |
| clientID.append(":"); |
| clientID.append(getUniqueTag()); |
| clientID.append(":"); |
| clientID.append(getDSName()); |
| // Hash key. |
| |
| //int offset = 0; |
| for (uint32_t i = 0; i < getHostAddrLen(); i++) { |
| char hostInfo[16] = {0}; |
| // offset += ACE_OS::snprintf(hostInfo + offset , 255 - offset, ":%x", m_hostAddr[i]); |
| ACE_OS::itoa(m_hostAddr[i],hostInfo, 16); |
| m_hashKey.append(":"); |
| m_hashKey.append(hostInfo); |
| } |
| m_hashKey.append(":"); |
| char hostInfoPort[16] = {0}; |
| ACE_OS::itoa(getHostPort(),hostInfoPort, 10); |
| // offset += ACE_OS::snprintf(hostInfo + offset, 255 - offset , ":%d", getHostPort()); |
| m_hashKey.append(hostInfoPort); |
| m_hashKey.append(":"); |
| m_hashKey.append(getDSName()); |
| m_hashKey.append(":"); |
| if (m_uniqueTag.size() != 0) |
| m_hashKey.append(getUniqueTag()); |
| else |
| { |
| m_hashKey.append(":"); |
| char viewid[16] = {0}; |
| ACE_OS::itoa(m_vmViewId,viewid, 10); |
| //offset += ACE_OS::snprintf(hostInfo + offset , 255 - offset , ":%d", m_vmViewId); |
| m_hashKey.append(viewid); |
| } |
| LOGDEBUG("GethashKey %s client id: %s ", m_hashKey.c_str(), clientID.c_str()); |
| } |
| const char* ClientProxyMembershipID::getDSMemberId(uint32_t& mesgLength) const |
| { |
| mesgLength = (int32_t)m_memIDStr.size(); |
| return m_memIDStr.c_str(); |
| } |
| const char* ClientProxyMembershipID::getDSMemberIdForCS43(uint32_t& mesgLength) const |
| { |
| mesgLength = (int32_t)m_dsmemIDStr.size(); |
| return m_dsmemIDStr.c_str(); |
| |
| } |
| |
| const std::string& ClientProxyMembershipID::getDSMemberIdForThinClientUse() |
| { |
| return clientID; |
| } |
| |
| |
| std::string ClientProxyMembershipID::getHashKey() |
| { |
| return m_hashKey; |
| } |
| |
| void ClientProxyMembershipID::getClientProxyMembershipID(){ |
| // Implement LonerDistributionManager::generateMemberId() and store result in dsMemberId,dsMemberIdLength |
| const char* hex = "0123456789ABCDEF"; |
| std::string DSMemberId=""; |
| ACE_TCHAR host[MAXHOSTNAMELEN]; |
| std::string hostName=" " ; |
| char buf[50]; |
| char dsName[50]; |
| DistributedSystemPtr dsPtr; |
| dsPtr = DistributedSystem::getInstance(); |
| |
| ACE_OS::hostname( host, sizeof(host)-1); |
| hostName= host; |
| pid_t pid; |
| pid = ACE_OS::getpid(); |
| ACE_OS::srand(pid); |
| |
| /* adongre |
| * CID 28814: Resource leak (RESOURCE_LEAK) |
| * Following allocation is not used anywhere |
| * commenting the same. |
| */ |
| |
| /*int* random = new int[8]; |
| for (int i = 0; i < 8; i++) { |
| random[i]=ACE_OS::rand()%16; |
| } */ |
| char* hname=host; |
| |
| //ACE_OS::sprintf(hname,"%s",hostName); |
| uint32_t len = static_cast<uint32_t> (hostName.length()); |
| DataOutput m_dsmemID; |
| m_dsmemID.writeBytesOnly((int8_t*)hname,len); |
| //DSMemberId = DSMemberId.append(host); |
| //DSMemberId= DSMemberId.append("("); |
| m_dsmemID.write((int8_t)'('); |
| int lenPid = ACE_OS::snprintf(buf,50, "%d",pid); |
| //DSMemberId.append(buf); |
| //m_dsmemID.writeInt((int32_t)pid); |
| m_dsmemID.writeBytesOnly((int8_t*)buf,lenPid); |
| //DSMemberId.append("):"); |
| m_dsmemID.write((int8_t)')'); |
| m_dsmemID.write((int8_t)':'); |
| |
| char hexBuf[20]; |
| for (int j=0;j<8;j++){ |
| // ARB: Hardcoding random number for Thin Client |
| //hexBuf[j] = hex[random[j]%16]; |
| hexBuf[j] = hex[1]; |
| } |
| //DSMemberId = DSMemberId.append(hexBuf); |
| m_dsmemID.writeBytesOnly((int8_t*)hexBuf,8); |
| m_dsmemID.write((int8_t)':'); |
| //DSMemberId = DSMemberId.append(":"); |
| ACE_OS::snprintf(dsName,50, "%s",dsPtr->getName()); |
| //DSMemberId.append(dsName); |
| uint32_t dsLen =static_cast<uint32_t> (strlen(dsName)); |
| m_dsmemID.writeBytesOnly((int8_t*)dsName,dsLen); |
| m_dsmemIDStr += (char*)m_dsmemID.getBuffer(); |
| uint32_t strLen; |
| char* strBuf = (char*)m_dsmemID.getBuffer(&strLen); |
| m_dsmemIDStr.append(strBuf, strLen); |
| //dsMemberIdLength = DSMemberId.length(); |
| //dsMemberId= (char*)ACE_OS::malloc(dsMemberIdLength+1); |
| //ACE_OS::strcpy(dsMemberId,DSMemberId.c_str()); |
| //return m_dsmemID; |
| |
| } |
| |
| void ClientProxyMembershipID::toData( DataOutput& output ) const |
| { |
| throw IllegalStateException("Member ID toData() not implemented."); |
| } |
| |
| Serializable* ClientProxyMembershipID::fromData( DataInput& input ) |
| { |
| // deserialization for PR FX HA |
| uint8_t* hostAddr; |
| int32_t len, hostPort, dcport, vPID,durableClntTimeOut; |
| CacheableStringPtr hostname, dsName, uniqueTag, durableClientId; |
| int8_t splitbrain, vmKind; |
| |
| input.readArrayLen(&len); // inetaddress len |
| m_hostAddrLocalMem = true; |
| /* adongre - Coverity II |
| * CID 29184: Out-of-bounds access (OVERRUN_DYNAMIC) |
| */ |
| //hostAddr = new uint8_t(len); |
| hostAddr = new uint8_t[len]; |
| |
| input.readBytesOnly(hostAddr, len); // inetaddress |
| input.readInt(&hostPort); // port |
| input.readObject(hostname); // hostname |
| input.read(&splitbrain); // splitbrain |
| input.readInt(&dcport); // port |
| input.readInt(&vPID); // pid |
| input.read(&vmKind); // vmkind |
| CacheableStringArrayPtr aStringArray(CacheableStringArray::create()); |
| aStringArray->fromData(input); |
| // #925 - currently reading empty string keep watch here, |
| // server might remove even sending this string (https://svn.gemstone.com/trac/gemfire/changeset/44566). |
| input.readObject(dsName); // name |
| input.readObject(uniqueTag); // unique tag |
| input.readObject(durableClientId); // durable client id |
| input.readInt(&durableClntTimeOut); // durable client timeout |
| int32_t vmViewId = 0; |
| readVersion(splitbrain, input); |
| if (vmKind != ClientProxyMembershipID::LONER_DM_TYPE) { |
| vmViewId = atoi(uniqueTag.ptr()->asChar()); |
| initObjectVars (hostname->asChar(), hostAddr, len, true, hostPort, durableClientId->asChar(), durableClntTimeOut , |
| dcport, vPID, vmKind, splitbrain, dsName->asChar(), NULL, vmViewId); |
| } |
| else { |
| // initialize the object |
| initObjectVars (hostname->asChar(), hostAddr, len, true, hostPort, durableClientId->asChar(), durableClntTimeOut , |
| dcport, vPID, vmKind, splitbrain, dsName->asChar(), uniqueTag->asChar(), 0); |
| } |
| |
| return this; |
| } |
| |
| Serializable* ClientProxyMembershipID::readEssentialData( DataInput& input ) |
| { |
| uint8_t* hostAddr; |
| int32_t len, hostPort, vmViewId = 0; |
| CacheableStringPtr hostname, dsName, uniqueTag, vmViewIdstr; |
| int8_t vmKind; |
| uint8_t flag; |
| |
| input.readArrayLen(&len); // inetaddress len |
| m_hostAddrLocalMem = true; |
| /* adongre - Coverity II |
| * CID 29183: Out-of-bounds access (OVERRUN_DYNAMIC) |
| */ |
| //hostAddr = new uint8_t(len); |
| hostAddr = new uint8_t[len]; |
| |
| input.readBytesOnly(hostAddr, len); // inetaddress |
| |
| input.readInt(&hostPort); // port |
| //TODO: RVV get the host name from |
| |
| input.read(&flag); |
| |
| input.read(&vmKind); // vmkind |
| |
| if (vmKind == ClientProxyMembershipID::LONER_DM_TYPE) { |
| input.readObject(uniqueTag); // unique tag |
| } |
| else |
| { |
| input.readObject(vmViewIdstr); |
| vmViewId = atoi(vmViewIdstr.ptr()->asChar()); |
| } |
| |
| // #925 - currently reading empty string keep watch here, |
| // server might remove even sending this string (https://svn.gemstone.com/trac/gemfire/changeset/44566). |
| input.readObject(dsName); // name |
| |
| if (vmKind != ClientProxyMembershipID::LONER_DM_TYPE) { |
| // initialize the object with the values read and some dummy values |
| initObjectVars ("", hostAddr, len, true, hostPort, "", 0 , |
| DCPORT, 0, vmKind, 0, dsName->asChar(), NULL, vmViewId); |
| } |
| else{ |
| // initialize the object with the values read and some dummy values |
| initObjectVars ("", hostAddr, len, true, hostPort, "", 0 , |
| DCPORT, 0, vmKind, 0, dsName->asChar(), uniqueTag->asChar(), vmViewId); |
| } |
| |
| return this; |
| } |
| |
| |
| void ClientProxyMembershipID::increaseSynchCounter() |
| { |
| ++synch_counter; |
| } |
| |
| // Compares two membershipIds. This is based on the compareTo function |
| // of InternalDistributedMember class of Java. |
| // Any change to the java function should be reflected here as well. |
| int16_t ClientProxyMembershipID::compareTo(DSMemberForVersionStampPtr other) |
| { |
| if (other.operator==(this)) { |
| return 0; |
| } |
| if (other.ptr() == NULL) |
| throw ClassCastException("ClientProxyMembershipID.compare(): comparing with a null value"); |
| |
| ClientProxyMembershipIDPtr otherMember = dynCast<ClientProxyMembershipIDPtr>(other); |
| uint32_t myPort = getHostPort(); |
| uint32_t otherPort = otherMember->getHostPort(); |
| |
| if (myPort < otherPort) |
| return -1; |
| if (myPort > otherPort) |
| return 1; |
| |
| uint8_t* myAddr = getHostAddr(); |
| uint8_t* otherAddr = otherMember->getHostAddr(); |
| // Discard null cases |
| if (myAddr == NULL && otherAddr == NULL) { |
| if (myPort < otherPort) |
| return -1; |
| else if (myPort > otherPort) |
| return 1; |
| else |
| return 0; |
| } |
| else if (myAddr == NULL) |
| return -1; |
| else if (otherAddr == NULL) |
| return 1; |
| for (uint32_t i = 0; i < getHostAddrLen(); i++) { |
| if (myAddr[i] < otherAddr[i]) |
| return -1; |
| if (myAddr[i] > otherAddr[i]) |
| return 1; |
| } |
| // #925 - currently reading empty string keep watch here, |
| // server might remove even sending this string (https://svn.gemstone.com/trac/gemfire/changeset/44566). |
| // InternalDistributedMember no longer uses "name" in comparisons. |
| //std::string myDSName = getDSName(); |
| //std::string otherDSName = otherMember->getDSName(); |
| |
| //if (myDSName.empty()&& otherDSName.empty()) { |
| // // do nothing |
| //} else if (myDSName.empty()) { |
| // return -1; |
| //} |
| //else if (otherDSName.empty()) { |
| // return 1; |
| //} |
| //else { |
| // int i = myDSName.compare(otherDSName); |
| // if (i != 0) { |
| // return i; |
| // } |
| //} |
| std::string myUniqueTag = getUniqueTag(); |
| std::string otherUniqueTag = otherMember->getUniqueTag(); |
| if (myUniqueTag.empty() && otherUniqueTag.empty()) |
| { |
| if (m_vmViewId < otherMember->m_vmViewId) { |
| return -1; |
| } else if (m_vmViewId > otherMember->m_vmViewId) { |
| return 1; |
| } // else they're the same, so continue |
| } |
| else if (myUniqueTag.empty()) { |
| return -1; |
| } |
| else if (otherUniqueTag.empty()) { |
| return 1; |
| } |
| else { |
| int i = myUniqueTag.compare(otherUniqueTag); |
| if (i != 0) { |
| return i; |
| } |
| } |
| return 0; |
| } |
| |
| |
| void ClientProxyMembershipID::readVersion(int flags, DataInput& input) |
| { |
| if ((flags & ClientProxyMembershipID::VERSION_MASK) != 0) |
| { |
| int8_t ordinal; |
| input.read(&ordinal); |
| LOGDEBUG("ClientProxyMembershipID::readVersion ordinal = %d ", ordinal); |
| if (ordinal != ClientProxyMembershipID::TOKEN_ORDINAL) |
| { |
| |
| } |
| else |
| { |
| int16_t ordinal; |
| input.readInt(&ordinal); |
| LOGDEBUG("ClientProxyMembershipID::readVersion ordinal = %d ", ordinal); |
| } |
| } |
| } |
| |
| void ClientProxyMembershipID::writeVersion(int16_t ordinal, DataOutput& output) |
| { |
| if (ordinal <= SCHAR_MAX) |
| { |
| output.write((int8_t)ordinal); |
| LOGDEBUG("ClientProxyMembershipID::writeVersion ordinal = %d ", ordinal); |
| } |
| else |
| { |
| output.write(ClientProxyMembershipID::TOKEN_ORDINAL); |
| output.writeInt(ordinal); |
| LOGDEBUG("ClientProxyMembershipID::writeVersion ordinal = %d ", ordinal); |
| } |
| } |
| |