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
+58 -47
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,19 +173,20 @@ 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(
BACNET_ADDRESS * src, BACNET_ADDRESS * src,
@@ -191,15 +194,15 @@ 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;
@@ -209,19 +212,20 @@ void MyAbortHandler(
else else
Last_Error_Code = ERROR_CODE_ABORT_OTHER; Last_Error_Code = ERROR_CODE_ABORT_OTHER;
} }
}
void MyRejectHandler( void MyRejectHandler(
BACNET_ADDRESS * src, BACNET_ADDRESS * src,
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;
@@ -231,6 +235,7 @@ void MyRejectHandler(
else else
Last_Error_Code = ERROR_CODE_REJECT_OTHER; Last_Error_Code = ERROR_CODE_REJECT_OTHER;
} }
}
void MyReadPropertyAckHandler( void MyReadPropertyAckHandler(
uint8_t * service_request, uint8_t * service_request,
@@ -241,7 +246,8 @@ 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) &&
(service_data->invoke_id == Request_Invoke_ID)) {
rp_data = calloc(1, sizeof(BACNET_READ_ACCESS_DATA)); rp_data = calloc(1, sizeof(BACNET_READ_ACCESS_DATA));
if (rp_data) { if (rp_data) {
len = len =
@@ -259,6 +265,7 @@ void MyReadPropertyAckHandler(
free(rp_data); free(rp_data);
} }
} }
}
void MyReadPropertyMultipleAckHandler( void MyReadPropertyMultipleAckHandler(
uint8_t * service_request, uint8_t * service_request,
@@ -269,7 +276,8 @@ 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) &&
(service_data->invoke_id == Request_Invoke_ID)) {
rpm_data = calloc(1, sizeof(BACNET_READ_ACCESS_DATA)); rpm_data = calloc(1, sizeof(BACNET_READ_ACCESS_DATA));
if (rpm_data) { if (rpm_data) {
len = len =
@@ -288,6 +296,7 @@ void MyReadPropertyMultipleAckHandler(
free(rpm_data); free(rpm_data);
} }
} }
}
static void Init_Service_Handlers( static void Init_Service_Handlers(
void) void)
@@ -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 ==
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. */ /* Try again, just to get a list of properties. */
else if (myState == GET_ALL_RESPONSE)
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) {