/* * Unmarshal an array argument. * * @param msg The message * @param sig The array element signature * @param arg Pointer to the structure to return the array */ static AJ_Status UnmarshalArray(AJ_Message* msg, const char** sig, AJ_Arg* arg, uint8_t pad) { AJ_Status status; AJ_IOBuffer* ioBuf = &msg->bus->sock.rx; char typeId = **sig; uint32_t numBytes; /* * Get the byte count for the array */ status = LoadBytes(ioBuf, 4, pad); if (status != AJ_OK) { return status; } EndianSwap(msg, AJ_ARG_UINT32, ioBuf->readPtr, 1); numBytes = *((uint32_t*)ioBuf->readPtr); ioBuf->readPtr += 4; /* * We are already aligned on 4 byte boundary but there may be padding after the array length if * the array element types align on an 8 byte boundary. */ pad = PadForType(typeId, ioBuf); status = LoadBytes(ioBuf, numBytes, pad); if (status != AJ_OK) { return status; } arg->val.v_data = ioBuf->readPtr; arg->sigPtr = *sig; arg->len = numBytes; if (IsScalarType(typeId)) { /* * For scalar types we do an inplace endian swap (if needed) and return a pointer into the read buffer. */ EndianSwap(msg, typeId, (void*)arg->val.v_data, arg->len); ioBuf->readPtr += numBytes; arg->typeId = typeId; arg->flags = AJ_ARRAY_FLAG; } else { /* * For all other types the elements must be individually unmarshalled. */ arg->typeId = AJ_ARG_ARRAY; } /* * Consume the array element signature. */ *sig += CompleteTypeSigLen(*sig); return status; }
AJ_Status AJ_CloseMsg(AJ_Message* msg) { AJ_Status status = AJ_OK; /* * This function is idempotent */ if (msg->bus) { AJ_IOBuffer* ioBuf = &msg->bus->sock.rx; /* * Skip any unconsumed bytes */ while (msg->bodyBytes) { uint16_t sz = AJ_IO_BUF_AVAIL(ioBuf); sz = min(sz, msg->bodyBytes); if (!sz) { AJ_IO_BUF_RESET(ioBuf); sz = min(msg->bodyBytes, ioBuf->bufSize); } status = LoadBytes(ioBuf, sz, 0); if (status != AJ_OK) { break; } msg->bodyBytes -= sz; ioBuf->readPtr += sz; } memset(msg, 0, sizeof(AJ_Message)); #ifndef NDEBUG currentMsg = NULL; #endif } return status; }
bool ff::LoadBytes(IDataReader *pReader, void *pMem, size_t nBytes) { const BYTE* pData = LoadBytes(pReader, nBytes); assertRetVal(pData && pMem, false); CopyMemory(pMem, pData, nBytes); return true; }
/** * @brief Cargador del buffer * * @param entrada Buffer de entrada para cargar en #buffer * * Se cargan los primeros #buffer_size bytes del buffer de entrada (entrada) en la variable #buffer. * Posteriormente, se cambia el estado del mensaje a lecutra (READING). */ void CNetMessageN::LoadNBytes(char* entrada) { charbuf c; for(uint i = 0; i < buffer_size; i++) c[i] = entrada[i]; LoadBytes(c, buffer_size); finish(); }
bool ff::LoadData<ff::String>(IDataReader *pReader, StringOut data) { DWORD nBytes = 0; assertRetVal(LoadData(pReader, nBytes), false); const BYTE* sz = LoadBytes(pReader, (size_t)nBytes); assertRetVal(sz, false); data.assign((const wchar_t *)sz, (nBytes / sizeof(wchar_t)) - 1); return true; }
/* * Unmarshal a struct or dict entry argument. * * @param msg The message * @param sig The struct signature * @param arg Pointer to the arg structure to return */ static AJ_Status UnmarshalStruct(AJ_Message* msg, const char** sig, AJ_Arg* arg, uint8_t pad) { AJ_IOBuffer* ioBuf = &msg->bus->sock.rx; AJ_Status status = LoadBytes(ioBuf, 0, pad); arg->val.v_data = ioBuf->readPtr; arg->sigPtr = *sig; /* * Consume the entire struct signature. */ *sig -= 1; *sig += CompleteTypeSigLen(*sig); return status; }
static bool InternalLoadValue(ff::IDataReader *reader, ff::Value **value) { assertRetVal(reader && value, false); DWORD type = 0; assertRetVal(ff::LoadData(reader, type), false); ff::Value::Type valueType = (ff::Value::Type)type; switch (valueType) { default: assertRetVal(false, false); case ff::Value::Type::Null: assertRetVal(ff::Value::CreateNull(value), false); break; case ff::Value::Type::Bool: { bool val = false; assertRetVal(ff::LoadData(reader, val), false); assertRetVal(ff::Value::CreateBool(val, value), false); } break; case ff::Value::Type::Double: { double val = 0; assertRetVal(ff::LoadData(reader, val), false); assertRetVal(ff::Value::CreateDouble(val, value), false); } break; case ff::Value::Type::Float: { float val = 0; assertRetVal(ff::LoadData(reader, val), false); assertRetVal(ff::Value::CreateFloat(val, value), false); } break; case ff::Value::Type::Int: { int val = 0; assertRetVal(ff::LoadData(reader, val), false); assertRetVal(ff::Value::CreateInt(val, value), false); } break; case ff::Value::Type::Data: { DWORD valueSize = 0; assertRetVal(ff::LoadData(reader, valueSize), false); ff::ComPtr<ff::IData> valueData; assertRetVal(ff::LoadBytes(reader, valueSize, &valueData), false); assertRetVal(ff::Value::CreateData(valueData, value), false); } break; case ff::Value::Type::Dict: { DWORD valueSize = 0; assertRetVal(ff::LoadData(reader, valueSize), false); ff::ComPtr<ff::IData> valueData; assertRetVal(LoadBytes(reader, valueSize, &valueData), false); ff::ComPtr<ff::IDataReader> valueReader; assertRetVal(CreateDataReader(valueData, 0, &valueReader), false); assertRetVal(ff::Value::CreateDict(value), false); assertRetVal(InternalLoadDict(valueReader, (*value)->AsDict()), false); } break; case ff::Value::Type::String: { ff::String val; assertRetVal(ff::LoadData(reader, val), false); assertRetVal(ff::Value::CreateString(val, value), false); } break; case ff::Value::Type::Guid: { GUID val = GUID_NULL; assertRetVal(ff::LoadData(reader, val), false); assertRetVal(ff::Value::CreateGuid(val, value), false); } break; case ff::Value::Type::Point: { ff::PointInt val(0, 0); assertRetVal(ff::LoadData(reader, val), false); assertRetVal(ff::Value::CreatePoint(val, value), false); } break; case ff::Value::Type::Rect: { ff::RectInt val(0, 0, 0, 0); assertRetVal(ff::LoadData(reader, val), false); assertRetVal(ff::Value::CreateRect(val, value), false); } break; case ff::Value::Type::PointF: { ff::PointFloat val(0, 0); assertRetVal(ff::LoadData(reader, val), false); assertRetVal(ff::Value::CreatePointF(val, value), false); } break; case ff::Value::Type::RectF: { ff::RectFloat val(0, 0, 0, 0); assertRetVal(ff::LoadData(reader, val), false); assertRetVal(ff::Value::CreateRectF(val, value), false); } break; case ff::Value::Type::DoubleVector: { DWORD doubleCount = 0; assertRetVal(ff::LoadData(reader, doubleCount), false); assertRetVal(ff::Value::CreateDoubleVector(value), false); (*value)->AsDoubleVector().Reserve(doubleCount); for (size_t h = 0; h < doubleCount; h++) { double val; assertRetVal(ff::LoadData(reader, val), false); (*value)->AsDoubleVector().Push(val); } } break; case ff::Value::Type::FloatVector: { DWORD floatCount = 0; assertRetVal(ff::LoadData(reader, floatCount), false); assertRetVal(ff::Value::CreateFloatVector(value), false); (*value)->AsFloatVector().Reserve(floatCount); for (size_t h = 0; h < floatCount; h++) { float val; assertRetVal(ff::LoadData(reader, val), false); (*value)->AsFloatVector().Push(val); } } break; case ff::Value::Type::IntVector: { DWORD intCount = 0; assertRetVal(ff::LoadData(reader, intCount), false); assertRetVal(ff::Value::CreateIntVector(value), false); (*value)->AsIntVector().Reserve(intCount); for (size_t h = 0; h < intCount; h++) { int val; assertRetVal(ff::LoadData(reader, val), false); (*value)->AsIntVector().Push(val); } } break; case ff::Value::Type::DataVector: { DWORD dataCount = 0; assertRetVal(ff::LoadData(reader, dataCount), false); assertRetVal(ff::Value::CreateDataVector(value), false); (*value)->AsDataVector().Reserve(dataCount); for (size_t h = 0; h < dataCount; h++) { DWORD dataSize = 0; assertRetVal(ff::LoadData(reader, dataSize), false); ff::ComPtr<ff::IData> valueData; assertRetVal(ff::LoadBytes(reader, dataSize, &valueData), false); (*value)->AsDataVector().Push(valueData); } } break; case ff::Value::Type::StringVector: { DWORD stringCount = 0; assertRetVal(ff::LoadData(reader, stringCount), false); assertRetVal(ff::Value::CreateStringVector(value), false); (*value)->AsStringVector().Reserve(stringCount); for (size_t h = 0; h < stringCount; h++) { ff::String val; assertRetVal(ff::LoadData(reader, val), false); (*value)->AsStringVector().Push(val); } } break; case ff::Value::Type::ValueVector: { DWORD valueCount = 0; assertRetVal(ff::LoadData(reader, valueCount), false); assertRetVal(ff::Value::CreateValueVector(value), false); (*value)->AsValueVector().Reserve(valueCount); for (size_t h = 0; h < valueCount; h++) { ff::ValuePtr nestedValue; assertRetVal(InternalLoadValue(reader, &nestedValue), false); (*value)->AsValueVector().Push(nestedValue); } } break; case ff::Value::Type::Object: // TODO break; } return true; }
AJ_Status AJ_UnmarshalRaw(AJ_Message* msg, const void** data, size_t len, size_t* actual) { AJ_Status status; size_t sz; AJ_IOBuffer* ioBuf = &msg->bus->sock.rx; /* * A soon as we start marshaling raw the header will become invalid so NULL it out */ if (msg->hdr) { uint8_t typeId = msg->signature[msg->sigOffset]; uint8_t pad; /* * There must be arguments to unmarshal */ if (!typeId) { return AJ_ERR_SIGNATURE; } /* * There may be padding before the argument */ pad = PadForType(typeId, ioBuf); if (pad > msg->bodyBytes) { return AJ_ERR_UNMARSHAL; } LoadBytes(ioBuf, 0, pad); msg->bodyBytes -= pad; /* * Standard signature matching is now meaningless */ msg->signature = ""; msg->sigOffset = 0; msg->hdr = NULL; } /* * Return an error if caller is attempting read off the end of the body */ if (len > msg->bodyBytes) { return AJ_ERR_UNMARSHAL; } /* * We want to return the requested data as contiguous bytes if possible */ sz = AJ_IO_BUF_AVAIL(ioBuf); if (sz < len) { AJ_IOBufRebase(ioBuf); } /* * If we try to load more than the buffer size we will get an error */ status = LoadBytes(ioBuf, (uint16_t)min(len, ioBuf->bufSize), 0); if (status == AJ_OK) { sz = AJ_IO_BUF_AVAIL(ioBuf); if (sz < len) { len = sz; } *data = ioBuf->readPtr; *actual = len; ioBuf->readPtr += len; msg->bodyBytes -= (uint16_t)len; } return status; }
AJ_Status AJ_UnmarshalMsg(AJ_BusAttachment* bus, AJ_Message* msg, uint32_t timeout) { AJ_Status status; AJ_IOBuffer* ioBuf = &bus->sock.rx; uint8_t* endOfHeader; uint32_t hdrPad; /* * Clear message then set the bus */ memset(msg, 0, sizeof(AJ_Message)); msg->msgId = AJ_INVALID_MSG_ID; msg->bus = bus; /* * Move any unconsumed data to the start of the I/O buffer */ AJ_IOBufRebase(ioBuf); /* * Load the message header */ while (AJ_IO_BUF_AVAIL(ioBuf) < sizeof(AJ_MsgHeader)) { //#pragma calls = AJ_Net_Recv status = ioBuf->recv(ioBuf, sizeof(AJ_MsgHeader) - AJ_IO_BUF_AVAIL(ioBuf), timeout); if (status != AJ_OK) { /* * If there were no messages to receive check if we have any methods call that have * timed-out and if so generate an internal error message to allow the application to * proceed. */ if ((status == AJ_ERR_TIMEOUT) && AJ_TimedOutMethodCall(msg)) { msg->hdr = (AJ_MsgHeader*)&internalErrorHdr; msg->error = AJ_ErrTimeout; msg->sender = AJ_GetUniqueName(msg->bus); msg->destination = msg->sender; status = AJ_OK; } return status; } } /* * Header was unmarsalled directly into the rx buffer */ msg->hdr = (AJ_MsgHeader*)ioBuf->bufStart; ioBuf->readPtr += sizeof(AJ_MsgHeader); /* * Quick sanity check on the header - unrecoverable error if this check fails */ if ((msg->hdr->endianess != AJ_LITTLE_ENDIAN) && (msg->hdr->endianess != AJ_BIG_ENDIAN)) { return AJ_ERR_READ; } /* * Endian swap header info - conventiently they are contiguous in the header */ EndianSwap(msg, AJ_ARG_INT32, &msg->hdr->bodyLen, 3); msg->bodyBytes = msg->hdr->bodyLen; /* * The header is null padded to an 8 bytes boundary */ hdrPad = (8 - msg->hdr->headerLen) & 7; /* * Load the header */ status = LoadBytes(ioBuf, msg->hdr->headerLen + hdrPad, 0); if (status != AJ_OK) { return status; } #ifndef NDEBUG /* * Check that messages are getting closed */ AJ_ASSERT(!currentMsg); currentMsg = msg; #endif /* * Assume an empty signature */ msg->signature = ""; /* * We have the header in the buffer now we can unmarshal the header fields */ endOfHeader = ioBuf->bufStart + sizeof(AJ_MsgHeader) + msg->hdr->headerLen; while (ioBuf->readPtr < endOfHeader) { const char* fieldSig; uint8_t fieldId; AJ_Arg hdrVal; /* * Custom unmarshal the header field - signature is "(yv)" so starts off with STRUCT aligment. */ status = LoadBytes(ioBuf, 4, PadForType(AJ_ARG_STRUCT, ioBuf)); if (status != AJ_OK) { break; } fieldId = ioBuf->readPtr[0]; fieldSig = (const char*)&ioBuf->readPtr[2]; ioBuf->readPtr += 4; /* * Now unmarshal the field value */ status = Unmarshal(msg, &fieldSig, &hdrVal); if (status != AJ_OK) { break; } /* * Check the field has the type we expect - we ignore fields we don't know */ if ((fieldId <= AJ_HDR_SESSION_ID) && (TypeForHdr[fieldId] != hdrVal.typeId)) { status = AJ_ERR_UNMARSHAL; break; } /* * Set the field value in the message */ switch (fieldId) { case AJ_HDR_OBJ_PATH: msg->objPath = hdrVal.val.v_objPath; break; case AJ_HDR_INTERFACE: msg->iface = hdrVal.val.v_string; break; case AJ_HDR_MEMBER: msg->member = hdrVal.val.v_string; break; case AJ_HDR_ERROR_NAME: msg->error = hdrVal.val.v_string; break; case AJ_HDR_REPLY_SERIAL: msg->replySerial = *(hdrVal.val.v_uint32); break; case AJ_HDR_DESTINATION: msg->destination = hdrVal.val.v_string; break; case AJ_HDR_SENDER: msg->sender = hdrVal.val.v_string; break; case AJ_HDR_SIGNATURE: msg->signature = hdrVal.val.v_signature; break; case AJ_HDR_TIMESTAMP: msg->timestamp = *(hdrVal.val.v_uint32); break; case AJ_HDR_TIME_TO_LIVE: msg->ttl = *(hdrVal.val.v_uint32); break; case AJ_HDR_SESSION_ID: msg->sessionId = *(hdrVal.val.v_uint32); break; case AJ_HDR_HANDLES: case AJ_HDR_COMPRESSION_TOKEN: default: /* Ignored */ break; } } if (status == AJ_OK) { AJ_ASSERT(ioBuf->readPtr == endOfHeader); /* * Consume the header pad bytes. */ ioBuf->readPtr += hdrPad; /* * If the message is encrypted load the entire message body and decrypt it. */ if (msg->hdr->flags & AJ_FLAG_ENCRYPTED) { status = LoadBytes(ioBuf, msg->hdr->bodyLen, 0); if (status == AJ_OK) { status = DecryptMessage(msg); } } /* * Toggle the AUTO_START flag so in the API no flags == 0 * * Note we must do this after decrypting the message or message authentication will fail. */ msg->hdr->flags ^= AJ_FLAG_AUTO_START; /* * If the message looks good try to identify it. */ if (status == AJ_OK) { status = AJ_IdentifyMessage(msg); } } else { /* * Consume entire header */ ioBuf->readPtr = endOfHeader + hdrPad; } if (status == AJ_OK) { AJ_DumpMsg("RECEIVED", msg, FALSE); } else { /* * Silently discard message unless in debug mode */ AJ_ErrPrintf(("Discarding bad message %s\n", AJ_StatusText(status))); AJ_DumpMsg("DISCARDING", msg, FALSE); AJ_CloseMsg(msg); } return status; }
/* * Unmarshal a single argument */ static AJ_Status Unmarshal(AJ_Message* msg, const char** sig, AJ_Arg* arg) { AJ_Status status; AJ_IOBuffer* ioBuf = &msg->bus->sock.rx; char typeId; uint32_t pad; uint32_t sz; memset(arg, 0, sizeof(AJ_Arg)); if (!*sig || !**sig) { return AJ_ERR_END_OF_DATA; } typeId = **sig; *sig += 1; pad = PadForType(typeId, ioBuf); if (IsScalarType(typeId)) { sz = SizeOfType(typeId); status = LoadBytes(ioBuf, sz, pad); if (status != AJ_OK) { return status; } /* * For numeric types we just return a pointer into the buffer */ arg->typeId = typeId; arg->val.v_byte = ioBuf->readPtr; arg->len = 0; ioBuf->readPtr += sz; EndianSwap(msg, typeId, (void*)arg->val.v_data, 1); } else if (TYPE_FLAG(typeId) & (AJ_STRING | AJ_VARIANT)) { /* * Length field for a signature is 1 byte, for regular strings its 4 bytes */ uint32_t lenSize = ALIGNMENT(typeId); /* * Read the string length. Note the length doesn't include the terminating NUL * so an empty string in encoded as two zero bytes. */ status = LoadBytes(ioBuf, lenSize, pad); if (status != AJ_OK) { return status; } if (lenSize == 4) { EndianSwap(msg, AJ_ARG_UINT32, ioBuf->readPtr, 1); sz = *((uint32_t*)ioBuf->readPtr); } else { sz = (uint32_t)(*ioBuf->readPtr); } ioBuf->readPtr += lenSize; status = LoadBytes(ioBuf, sz + 1, 0); if (status != AJ_OK) { return status; } arg->typeId = typeId; arg->len = sz; arg->val.v_string = (char*)ioBuf->readPtr; ioBuf->readPtr += sz + 1; /* * If unmarshalling a variant store offset to start of signature */ if (typeId == AJ_ARG_VARIANT) { msg->varOffset = (uint8_t)(sz + 1); } } else if (typeId == AJ_ARG_ARRAY) { status = UnmarshalArray(msg, sig, arg, pad); } else if ((typeId == AJ_ARG_STRUCT) || (typeId == AJ_ARG_DICT_ENTRY)) { arg->typeId = typeId; status = UnmarshalStruct(msg, sig, arg, pad); } else { status = AJ_ERR_UNMARSHAL; } return status; }