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:
+115
-104
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user