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