// Read DLMS Data frame from the device. int CGXCommunication::ReadDLMSPacket(CGXByteBuffer& data, CGXReplyData& reply) { int ret, pos; CGXByteBuffer bb; std::string tmp; if (data.GetSize() == 0) { return DLMS_ERROR_CODE_OK; } Now(tmp); tmp = "TX: " + tmp; tmp += "\t" + data.ToHexString(); if (m_Trace > GX_TRACE_LEVEL_INFO) { printf("%s\r\n", tmp.c_str()); } GXHelpers::Write("trace.txt", tmp + "\r\n"); int len = data.GetSize(); //Send data. for (pos = 0; pos != data.GetSize(); ++pos) { pc.putc(data.GetData()[pos]); } // Loop until whole DLMS packet is received. tmp = ""; do { if (Read(0x7E, bb) != 0) { return DLMS_ERROR_CODE_SEND_FAILED; } if (tmp.size() == 0) { Now(tmp); tmp = "RX: " + tmp + "\t"; } else { tmp += " "; } tmp += bb.ToHexString(); } while ((ret = m_Parser->GetData(bb, reply)) == DLMS_ERROR_CODE_FALSE); tmp += "\r\n"; if (m_Trace > GX_TRACE_LEVEL_INFO) { printf("%s", tmp.c_str()); } GXHelpers::Write("trace.txt", tmp); if (ret == DLMS_ERROR_CODE_REJECTED) { ret = ReadDLMSPacket(data, reply); } return ret; }
int CGXCommunication::ReadDataBlock(CGXByteBuffer& data, CGXReplyData& reply) { //If ther is no data to send. if (data.GetSize() == 0) { return DLMS_ERROR_CODE_OK; } int ret; CGXByteBuffer bb; //Send data. if ((ret = ReadDLMSPacket(data, reply)) != DLMS_ERROR_CODE_OK) { return ret; } while (reply.IsMoreData()) { bb.Clear(); if ((ret = m_Parser->ReceiverReady(reply.GetMoreData(), bb)) != 0) { return ret; } if ((ret = ReadDLMSPacket(bb, reply)) != DLMS_ERROR_CODE_OK) { return ret; } } return DLMS_ERROR_CODE_OK; }
CGXDLMSVariant::CGXDLMSVariant(CGXByteBuffer& value) { vt = DLMS_DATA_TYPE_OCTET_STRING; size = value.GetSize(); if (size != 0) { byteArr = (unsigned char*) malloc(size); memcpy(byteArr, value.GetData(), size); } else { byteArr = NULL; } }
int CGXCommunication::Read(unsigned char eop, CGXByteBuffer& reply) { bool bFound = false; int pos, lastReadIndex = 0; do { reply.SetUInt8(pc.getc()); if (reply.GetSize() > 5) { //Some optical strobes can return extra bytes. for (pos = reply.GetSize() - 1; pos != lastReadIndex; --pos) { if (reply.GetData()[pos] == eop) { bFound = true; break; } } lastReadIndex = pos; } } while (!bFound); return DLMS_ERROR_CODE_OK; }
DLMS_SOURCE_DIAGNOSTIC CGXDLMSBase::ValidateAuthentication( DLMS_AUTHENTICATION authentication, CGXByteBuffer& password) { if (authentication == DLMS_AUTHENTICATION_NONE) { //Uncomment this if authentication is always required. //return DLMS_SOURCE_DIAGNOSTIC_AUTHENTICATION_MECHANISM_NAME_REQUIRED; } if (authentication == DLMS_AUTHENTICATION_LOW) { CGXByteBuffer expected; std::string name = "0.0.40.0.0.255"; if (GetUseLogicalNameReferencing()) { CGXDLMSAssociationLogicalName* ln = (CGXDLMSAssociationLogicalName*)GetItems().FindByLN( DLMS_OBJECT_TYPE_ASSOCIATION_LOGICAL_NAME, name); expected = ln->GetSecret(); } else { CGXDLMSAssociationShortName* sn = (CGXDLMSAssociationShortName*)GetItems().FindByLN( DLMS_OBJECT_TYPE_ASSOCIATION_SHORT_NAME, name); expected = sn->GetSecret(); } if (expected.Compare(password.GetData(), password.GetSize())) { return DLMS_SOURCE_DIAGNOSTIC_NONE; } return DLMS_SOURCE_DIAGNOSTIC_AUTHENTICATION_FAILURE; } // Other authentication levels are check on phase two. return DLMS_SOURCE_DIAGNOSTIC_NONE; }
/** * Chipher text. * * @param auth * Authentication level. * @param data * Text to chipher. * @param secret * Secret. * @return Chiphered text. */ int CGXSecure::Secure( CGXDLMSSettings& settings, CGXCipher* cipher, unsigned long ic, CGXByteBuffer& data, CGXByteBuffer& secret, CGXByteBuffer& reply) { int ret = 0, pos; reply.Clear(); if (settings.GetAuthentication() == DLMS_AUTHENTICATION_HIGH) { CGXByteBuffer s; int len = data.GetSize(); if (len % 16 != 0) { len += (16 - (data.GetSize() % 16)); } if (secret.GetSize() > data.GetSize()) { len = secret.GetSize(); if (len % 16 != 0) { len += (16 - (secret.GetSize() % 16)); } } s.Set(&secret); s.Zero(s.GetSize(), len - s.GetSize()); reply.Set(&data); reply.Zero(reply.GetSize(), len - reply.GetSize()); for (pos = 0; pos < len / 16; ++pos) { CGXCipher::Aes1Encrypt(reply, pos * 16, s); } return 0; } // Get server Challenge. CGXByteBuffer challenge; // Get shared secret if (settings.GetAuthentication() != DLMS_AUTHENTICATION_HIGH_GMAC) { challenge.Set(&data); challenge.Set(&secret); } if (settings.GetAuthentication() == DLMS_AUTHENTICATION_HIGH_MD5) { return CGXDLMSMD5::Encrypt(challenge, reply); } else if (settings.GetAuthentication() == DLMS_AUTHENTICATION_HIGH_SHA1) { return CGXDLMSSha1::Encrypt(challenge, reply); } else if (settings.GetAuthentication() == DLMS_AUTHENTICATION_HIGH_SHA256) { return CGXDLMSSha256::Encrypt(challenge, reply); } else if (settings.GetAuthentication() == DLMS_AUTHENTICATION_HIGH_GMAC) { CGXByteBuffer tmp; CGXByteBuffer& key = settings.GetCipher()->GetBlockCipherKey(); ret = cipher->Encrypt(DLMS_SECURITY_AUTHENTICATION, DLMS_COUNT_TYPE_TAG, ic, 0, secret, key, data, tmp); if (ret == 0) { reply.SetUInt8(DLMS_SECURITY_AUTHENTICATION); reply.SetUInt32(ic); reply.Set(&tmp); } } return ret; }
void ListenerThread(void* pVoid) { CGXByteBuffer reply; CGXDLMSBase* server = (CGXDLMSBase*)pVoid; sockaddr_in add = { 0 }; int ret; char tmp[10]; CGXByteBuffer bb; bb.Capacity(2048); #if defined(_WIN32) || defined(_WIN64)//If Windows int len; int AddrLen = sizeof(add); SOCKET socket; #else //If Linux socklen_t len; socklen_t AddrLen = sizeof(add); int socket; #endif struct sockaddr_in client; memset(&client, 0, sizeof(client)); //Get buffer data basic_string<char> senderInfo; while (server->IsConnected()) { len = sizeof(client); senderInfo.clear(); socket = accept(server->GetSocket(), (struct sockaddr*)&client, &len); server->Reset(); if (server->IsConnected()) { server->Reset(); if ((ret = getpeername(socket, (sockaddr*)&add, &AddrLen)) == -1) { closesocket(socket); #if defined(_WIN32) || defined(_WIN64)//If Windows socket = INVALID_SOCKET; #else //If Linux socket = -1; #endif continue; //Notify error. } senderInfo = inet_ntoa(add.sin_addr); senderInfo.append(":"); #if _MSC_VER > 1000 _ltoa_s(add.sin_port, tmp, 10, 10); #else sprintf(tmp, "%d", add.sin_port); #endif senderInfo.append(tmp); while (server->IsConnected()) { //If client is left wait for next client. if ((ret = recv(socket, (char*) bb.GetData() + bb.GetSize(), bb.Capacity() - bb.GetSize(), 0)) == -1) { //Notify error. server->Reset(); #if defined(_WIN32) || defined(_WIN64)//If Windows closesocket(socket); socket = INVALID_SOCKET; #else //If Linux close(socket); socket = -1; #endif break; } //If client is closed the connection. if (ret == 0) { server->Reset(); #if defined(_WIN32) || defined(_WIN64)//If Windows closesocket(socket); socket = INVALID_SOCKET; #else //If Linux close(socket); socket = -1; #endif break; } bb.SetSize(bb.GetSize() + ret); if (server->m_Trace == GX_TRACE_LEVEL_VERBOSE) { printf("RX:\t%s\r\n", bb.ToHexString().c_str()); } if (server->HandleRequest(bb, reply) != 0) { #if defined(_WIN32) || defined(_WIN64)//If Windows closesocket(socket); socket = INVALID_SOCKET; #else //If Linux close(socket); socket = -1; #endif } bb.SetSize(0); if (reply.GetSize() != 0) { if (server->m_Trace == GX_TRACE_LEVEL_VERBOSE) { printf("TX:\t%s\r\n", reply.ToHexString().c_str()); } if (send(socket, (const char*)reply.GetData(), reply.GetSize() - reply.GetPosition(), 0) == -1) { //If error has occured server->Reset(); #if defined(_WIN32) || defined(_WIN64)//If Windows closesocket(socket); socket = INVALID_SOCKET; #else //If Linux close(socket); socket = -1; #endif } reply.Clear(); } } server->Reset(); } } }