Added checks in Error, Abort, Reject, and Acks for matching address and invoke ID so that out-of-order messages would not foul up the state machine and only the reply matching the request would be honored.

Changed request so that an error message of segmentation-not-supported would trigger the read-property fallback mechanism.
This commit is contained in:
skarg
2012-02-21 21:56:18 +00:00
parent 48c756bc11
commit 1c19bf7d09
+115 -104
View File
@@ -75,6 +75,8 @@ static uint8_t Rx_Buf[MAX_MPDU] = { 0 };
/* target information converted from command line */
static uint32_t Target_Device_Object_Instance = BACNET_MAX_INSTANCE;
static BACNET_ADDRESS Target_Address;
/* the invoke id is needed to filter incoming messages */
static uint8_t Request_Invoke_ID = 0;
/* loopback address to talk to myself */
/* = { 6, { 127, 0, 0, 1, 0xBA, 0xC0, 0 }, 0 }; */
#if defined(BACDL_BIP)
@@ -171,18 +173,19 @@ static void MyErrorHandler(
BACNET_ERROR_CLASS error_class,
BACNET_ERROR_CODE error_code)
{
/* FIXME: verify src and invoke id */
(void) src;
(void) invoke_id;
if (address_match(&Target_Address, src) &&
(invoke_id == Request_Invoke_ID)) {
#if PRINT_ERRORS
if (ShowValues)
fprintf(stderr, "-- BACnet Error: %s: %s\r\n",
bactext_error_class_name(error_class),
bactext_error_code_name(error_code));
if (ShowValues) {
fprintf(stderr, "-- BACnet Error: %s: %s\r\n",
bactext_error_class_name(error_class),
bactext_error_code_name(error_code));
}
#endif
Error_Detected = true;
Last_Error_Class = error_class;
Last_Error_Code = error_code;
Error_Detected = true;
Last_Error_Class = error_class;
Last_Error_Code = error_code;
}
}
void MyAbortHandler(
@@ -191,23 +194,24 @@ void MyAbortHandler(
uint8_t abort_reason,
bool server)
{
/* FIXME: verify src and invoke id */
(void) src;
(void) invoke_id;
(void) server;
if (address_match(&Target_Address, src) &&
(invoke_id == Request_Invoke_ID)) {
#if PRINT_ERRORS
/* It is normal for this to fail, so don't print. */
if ((myState != GET_ALL_RESPONSE) && !IsLongArray && ShowValues)
fprintf(stderr, "-- BACnet Abort: %s \r\n",
bactext_abort_reason_name(abort_reason));
/* It is normal for this to fail, so don't print. */
if ((myState != GET_ALL_RESPONSE) && !IsLongArray && ShowValues) {
fprintf(stderr, "-- BACnet Abort: %s \r\n",
bactext_abort_reason_name(abort_reason));
}
#endif
Error_Detected = true;
Last_Error_Class = ERROR_CLASS_SERVICES;
if (abort_reason < MAX_BACNET_ABORT_REASON)
Last_Error_Code =
(ERROR_CODE_ABORT_BUFFER_OVERFLOW - 1) + abort_reason;
else
Last_Error_Code = ERROR_CODE_ABORT_OTHER;
Error_Detected = true;
Last_Error_Class = ERROR_CLASS_SERVICES;
if (abort_reason < MAX_BACNET_ABORT_REASON)
Last_Error_Code =
(ERROR_CODE_ABORT_BUFFER_OVERFLOW - 1) + abort_reason;
else
Last_Error_Code = ERROR_CODE_ABORT_OTHER;
}
}
void MyRejectHandler(
@@ -215,21 +219,22 @@ void MyRejectHandler(
uint8_t invoke_id,
uint8_t reject_reason)
{
/* FIXME: verify src and invoke id */
(void) src;
(void) invoke_id;
if (address_match(&Target_Address, src) &&
(invoke_id == Request_Invoke_ID)) {
#if PRINT_ERRORS
if (ShowValues)
fprintf(stderr, "BACnet Reject: %s\r\n",
bactext_reject_reason_name(reject_reason));
if (ShowValues) {
fprintf(stderr, "BACnet Reject: %s\r\n",
bactext_reject_reason_name(reject_reason));
}
#endif
Error_Detected = true;
Last_Error_Class = ERROR_CLASS_SERVICES;
if (reject_reason < MAX_BACNET_REJECT_REASON)
Last_Error_Code =
(ERROR_CODE_REJECT_BUFFER_OVERFLOW - 1) + reject_reason;
else
Last_Error_Code = ERROR_CODE_REJECT_OTHER;
Error_Detected = true;
Last_Error_Class = ERROR_CLASS_SERVICES;
if (reject_reason < MAX_BACNET_REJECT_REASON)
Last_Error_Code =
(ERROR_CODE_REJECT_BUFFER_OVERFLOW - 1) + reject_reason;
else
Last_Error_Code = ERROR_CODE_REJECT_OTHER;
}
}
void MyReadPropertyAckHandler(
@@ -241,22 +246,24 @@ void MyReadPropertyAckHandler(
int len = 0;
BACNET_READ_ACCESS_DATA *rp_data;
(void) src;
rp_data = calloc(1, sizeof(BACNET_READ_ACCESS_DATA));
if (rp_data) {
len =
rp_ack_fully_decode_service_request(service_request, service_len,
rp_data);
}
if (len > 0) {
memmove(&Read_Property_Multiple_Data.service_data, service_data,
sizeof(BACNET_CONFIRMED_SERVICE_ACK_DATA));
Read_Property_Multiple_Data.rpm_data = rp_data;
Read_Property_Multiple_Data.new_data = true;
} else {
if (len < 0) /* Eg, failed due to no segmentation */
Error_Detected = true;
free(rp_data);
if (address_match(&Target_Address, src) &&
(service_data->invoke_id == Request_Invoke_ID)) {
rp_data = calloc(1, sizeof(BACNET_READ_ACCESS_DATA));
if (rp_data) {
len =
rp_ack_fully_decode_service_request(service_request, service_len,
rp_data);
}
if (len > 0) {
memmove(&Read_Property_Multiple_Data.service_data, service_data,
sizeof(BACNET_CONFIRMED_SERVICE_ACK_DATA));
Read_Property_Multiple_Data.rpm_data = rp_data;
Read_Property_Multiple_Data.new_data = true;
} else {
if (len < 0) /* Eg, failed due to no segmentation */
Error_Detected = true;
free(rp_data);
}
}
}
@@ -269,23 +276,25 @@ void MyReadPropertyMultipleAckHandler(
int len = 0;
BACNET_READ_ACCESS_DATA *rpm_data;
(void) src;
rpm_data = calloc(1, sizeof(BACNET_READ_ACCESS_DATA));
if (rpm_data) {
len =
rpm_ack_decode_service_request(service_request, service_len,
rpm_data);
}
if (len > 0) {
memmove(&Read_Property_Multiple_Data.service_data, service_data,
sizeof(BACNET_CONFIRMED_SERVICE_ACK_DATA));
Read_Property_Multiple_Data.rpm_data = rpm_data;
Read_Property_Multiple_Data.new_data = true;
/* Will process and free the RPM data later */
} else {
if (len < 0) /* Eg, failed due to no segmentation */
Error_Detected = true;
free(rpm_data);
if (address_match(&Target_Address, src) &&
(service_data->invoke_id == Request_Invoke_ID)) {
rpm_data = calloc(1, sizeof(BACNET_READ_ACCESS_DATA));
if (rpm_data) {
len =
rpm_ack_decode_service_request(service_request, service_len,
rpm_data);
}
if (len > 0) {
memmove(&Read_Property_Multiple_Data.service_data, service_data,
sizeof(BACNET_CONFIRMED_SERVICE_ACK_DATA));
Read_Property_Multiple_Data.rpm_data = rpm_data;
Read_Property_Multiple_Data.new_data = true;
/* Will process and free the RPM data later */
} else {
if (len < 0) /* Eg, failed due to no segmentation */
Error_Detected = true;
free(rpm_data);
}
}
}
@@ -1229,7 +1238,6 @@ int main(
time_t last_seconds = 0;
time_t current_seconds = 0;
time_t timeout_seconds = 0;
uint8_t invoke_id = 0;
bool found = false;
BACNET_OBJECT_ID myObject;
uint8_t buffer[MAX_PDU] = { 0 };
@@ -1341,10 +1349,10 @@ int main(
last_seconds = current_seconds;
StartNextObject(rpm_object, &myObject);
BuildPropRequest( rpm_object, &InitIdPropList[0] );
invoke_id =
Request_Invoke_ID =
Send_Read_Property_Multiple_Request(buffer, MAX_PDU,
Target_Device_Object_Instance, rpm_object);
if (invoke_id > 0) {
if (Request_Invoke_ID > 0) {
elapsed_seconds = 0;
} else {
/* We failed. Will hurt the header info we can show. */
@@ -1366,10 +1374,10 @@ int main(
last_seconds = current_seconds;
StartNextObject(rpm_object, &myObject);
invoke_id =
Request_Invoke_ID =
Send_Read_Property_Multiple_Request(buffer, MAX_PDU,
Target_Device_Object_Instance, rpm_object);
if (invoke_id > 0) {
if (Request_Invoke_ID > 0) {
elapsed_seconds = 0;
if (myState == GET_LIST_OF_ALL_REQUEST)
myState = GET_LIST_OF_ALL_RESPONSE;
@@ -1391,38 +1399,41 @@ int main(
}
if ((Read_Property_Multiple_Data.new_data) &&
(invoke_id ==
(Request_Invoke_ID ==
Read_Property_Multiple_Data.service_data.invoke_id)) {
Read_Property_Multiple_Data.new_data = false;
myState =
ProcessRPMData(Read_Property_Multiple_Data.rpm_data,
myState);
if (tsm_invoke_id_free(invoke_id)) {
invoke_id = 0;
if (tsm_invoke_id_free(Request_Invoke_ID)) {
Request_Invoke_ID = 0;
} else {
assert(false); /* How can this be? */
invoke_id = 0;
Request_Invoke_ID = 0;
}
elapsed_seconds = 0;
} else if (tsm_invoke_id_free(invoke_id)) {
} else if (tsm_invoke_id_free(Request_Invoke_ID)) {
elapsed_seconds = 0;
invoke_id = 0;
Request_Invoke_ID = 0;
if ( myState == GET_HEADING_RESPONSE )
myState = PRINT_HEADING;
/* just press ahead without the data */
else if (Error_Detected) {
/* The normal case for Device Object */
/* Was it because the Device can't do RPM? */
if (Last_Error_Code ==
ERROR_CODE_REJECT_UNRECOGNIZED_SERVICE) {
/* The normal case for Device Object */
/* Was it because the Device can't do RPM? */
Has_RPM = false;
myState = GET_PROPERTY_REQUEST;
}
/* Try again, just to get a list of properties. */
else if (myState == GET_ALL_RESPONSE)
} else if (Last_Error_Code ==
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED) {
myState = GET_PROPERTY_REQUEST;
StartNextObject(rpm_object, &myObject);
} else if (myState == GET_ALL_RESPONSE)
/* Try again, just to get a list of properties. */
myState = GET_LIST_OF_ALL_REQUEST;
/* Else drop back to RP. */
else {
/* Else drop back to RP. */
myState = GET_PROPERTY_REQUEST;
StartNextObject(rpm_object, &myObject);
}
@@ -1430,10 +1441,10 @@ int main(
myState = GET_ALL_REQUEST; /* Let's try again */
else
myState = GET_PROPERTY_REQUEST;
} else if (tsm_invoke_id_failed(invoke_id)) {
} else if (tsm_invoke_id_failed(Request_Invoke_ID)) {
fprintf(stderr, "\rError: TSM Timeout!\r\n");
tsm_free_invoke_id(invoke_id);
invoke_id = 0;
tsm_free_invoke_id(Request_Invoke_ID);
Request_Invoke_ID = 0;
elapsed_seconds = 0;
if ( myState == GET_HEADING_RESPONSE )
myState = PRINT_HEADING;
@@ -1443,7 +1454,7 @@ int main(
} else if (Error_Detected) {
/* Don't think we'll ever actually reach this point. */
elapsed_seconds = 0;
invoke_id = 0;
Request_Invoke_ID = 0;
if ( myState == GET_HEADING_RESPONSE )
myState = PRINT_HEADING;
/* just press ahead without the data */
@@ -1460,9 +1471,9 @@ int main(
/* Update times; aids single-step debugging */
last_seconds = current_seconds;
elapsed_seconds = 0;
invoke_id =
Request_Invoke_ID =
Read_Properties(Target_Device_Object_Instance, &myObject);
if (invoke_id == 0) {
if (Request_Invoke_ID == 0) {
/* Reached the end of the list. */
myState = NEXT_OBJECT; /* Move on to the next. */
} else
@@ -1480,7 +1491,7 @@ int main(
}
if ((Read_Property_Multiple_Data.new_data) &&
(invoke_id ==
(Request_Invoke_ID ==
Read_Property_Multiple_Data.service_data.invoke_id)) {
Read_Property_Multiple_Data.new_data = false;
PrintReadPropertyData(Read_Property_Multiple_Data.
@@ -1488,11 +1499,11 @@ int main(
Read_Property_Multiple_Data.rpm_data->object_instance,
Read_Property_Multiple_Data.rpm_data->
listOfProperties);
if (tsm_invoke_id_free(invoke_id)) {
invoke_id = 0;
if (tsm_invoke_id_free(Request_Invoke_ID)) {
Request_Invoke_ID = 0;
} else {
assert(false); /* How can this be? */
invoke_id = 0;
Request_Invoke_ID = 0;
}
elapsed_seconds = 0;
/* Advance the property (or Array List) index */
@@ -1516,8 +1527,8 @@ int main(
/* } */
/* } */
myState = GET_PROPERTY_REQUEST; /* Go fetch next Property */
} else if (tsm_invoke_id_free(invoke_id)) {
invoke_id = 0;
} else if (tsm_invoke_id_free(Request_Invoke_ID)) {
Request_Invoke_ID = 0;
elapsed_seconds = 0;
myState = GET_PROPERTY_REQUEST;
if (Error_Detected) {
@@ -1536,16 +1547,16 @@ int main(
myState = NEXT_OBJECT; /* Give up and move on to the next. */
}
}
} else if (tsm_invoke_id_failed(invoke_id)) {
} else if (tsm_invoke_id_failed(Request_Invoke_ID)) {
fprintf(stderr, "\rError: TSM Timeout!\r\n");
tsm_free_invoke_id(invoke_id);
tsm_free_invoke_id(Request_Invoke_ID);
elapsed_seconds = 0;
invoke_id = 0;
Request_Invoke_ID = 0;
myState = GET_PROPERTY_REQUEST; /* Let's try again, same Property */
} else if (Error_Detected) {
/* Don't think we'll ever actually reach this point. */
elapsed_seconds = 0;
invoke_id = 0;
Request_Invoke_ID = 0;
myState = NEXT_OBJECT; /* Give up and move on to the next. */
Error_Count++;
}
@@ -1598,7 +1609,7 @@ int main(
}
/* Check for timeouts */
if (!found || (invoke_id > 0)) {
if (!found || (Request_Invoke_ID > 0)) {
/* increment timer - exit if timed out */
elapsed_seconds += (current_seconds - last_seconds);
if (elapsed_seconds > timeout_seconds) {