void handler_atomic_read_file( uint8_t * service_request, uint16_t service_len, BACNET_ADDRESS * src, BACNET_CONFIRMED_SERVICE_DATA * service_data) { BACNET_ATOMIC_READ_FILE_DATA data; int len = 0; int pdu_len = 0; bool error = false; int bytes_sent = 0; BACNET_NPDU_DATA npdu_data; BACNET_ADDRESS my_address; BACNET_ERROR_CLASS error_class = ERROR_CLASS_OBJECT; BACNET_ERROR_CODE error_code = ERROR_CODE_UNKNOWN_OBJECT; #if PRINT_ENABLED fprintf(stderr, "Received Atomic-Read-File Request!\n"); #endif /* encode the NPDU portion of the packet */ datalink_get_my_address(&my_address); npdu_encode_npdu_data(&npdu_data, false, MESSAGE_PRIORITY_NORMAL); pdu_len = npdu_encode_pdu(&Handler_Transmit_Buffer[0], src, &my_address, &npdu_data); if (service_data->segmented_message) { len = abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id, ABORT_REASON_SEGMENTATION_NOT_SUPPORTED, true); #if PRINT_ENABLED fprintf(stderr, "ARF: Segmented Message. Sending Abort!\n"); #endif goto ARF_ABORT; } len = arf_decode_service_request(service_request, service_len, &data); /* bad decoding - send an abort */ if (len < 0) { len = abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id, ABORT_REASON_OTHER, true); #if PRINT_ENABLED fprintf(stderr, "Bad Encoding. Sending Abort!\n"); #endif goto ARF_ABORT; } if (data.object_type == OBJECT_FILE) { if (!bacfile_valid_instance(data.object_instance)) { error = true; } else if (data.access == FILE_STREAM_ACCESS) { if (data.type.stream.requestedOctetCount < octetstring_capacity(&data.fileData[0])) { if (bacfile_read_stream_data(&data)) { #if PRINT_ENABLED fprintf(stderr, "ARF: Stream offset %d, %d octets.\n", data.type.stream.fileStartPosition, data.type.stream.requestedOctetCount); #endif len = arf_ack_encode_apdu(&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id, &data); } else { error = true; error_class = ERROR_CLASS_OBJECT; error_code = ERROR_CODE_FILE_ACCESS_DENIED; } } else { len = abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id, ABORT_REASON_SEGMENTATION_NOT_SUPPORTED, true); #if PRINT_ENABLED fprintf(stderr, "Too Big To Send (%d >= %d). Sending Abort!\n", data.type.stream.requestedOctetCount, octetstring_capacity(&data.fileData[0])); #endif } } else if (data.access == FILE_RECORD_ACCESS) { if (data.type.record.fileStartRecord >= BACNET_READ_FILE_RECORD_COUNT) { error_class = ERROR_CLASS_SERVICES; error_code = ERROR_CODE_INVALID_FILE_START_POSITION; error = true; } else if (bacfile_read_stream_data(&data)) { #if PRINT_ENABLED fprintf(stderr, "ARF: fileStartRecord %d, %u RecordCount.\n", data.type.record.fileStartRecord, data.type.record.RecordCount); #endif len = arf_ack_encode_apdu(&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id, &data); } else { error = true; error_class = ERROR_CLASS_OBJECT; error_code = ERROR_CODE_FILE_ACCESS_DENIED; } } else { error = true; error_class = ERROR_CLASS_SERVICES; error_code = ERROR_CODE_INVALID_FILE_ACCESS_METHOD; #if PRINT_ENABLED fprintf(stderr, "Record Access Requested. Sending Error!\n"); #endif } } else { error = true; error_class = ERROR_CLASS_SERVICES; error_code = ERROR_CODE_INCONSISTENT_OBJECT_TYPE; } if (error) { len = bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id, SERVICE_CONFIRMED_ATOMIC_READ_FILE, error_class, error_code); } ARF_ABORT: pdu_len += len; bytes_sent = datalink_send_pdu(src, &npdu_data, &Handler_Transmit_Buffer[0], pdu_len); #if PRINT_ENABLED if (bytes_sent <= 0) { fprintf(stderr, "Failed to send PDU (%s)!\n", strerror(errno)); } #endif return; }
/* returns true if successful */ bool bacfile_write_property( BACNET_WRITE_PROPERTY_DATA * wp_data) { bool status = false; /* return value */ int len = 0; BACNET_APPLICATION_DATA_VALUE value; if (!bacfile_valid_instance(wp_data->object_instance)) { wp_data->error_class = ERROR_CLASS_OBJECT; wp_data->error_code = ERROR_CODE_UNKNOWN_OBJECT; return false; } /* only array properties can have array options */ if (wp_data->array_index != BACNET_ARRAY_ALL) { wp_data->error_class = ERROR_CLASS_PROPERTY; wp_data->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY; return false; } /* decode the some of the request */ len = bacapp_decode_application_data(wp_data->application_data, wp_data->application_data_len, &value); if (len < 0) { /* error while decoding - a value larger than we can handle */ wp_data->error_class = ERROR_CLASS_PROPERTY; wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; return false; } /* FIXME: len < application_data_len: more data? */ switch (wp_data->object_property) { case PROP_ARCHIVE: /* 12.13.8 Archive This property, of type BOOLEAN, indicates whether the File object has been saved for historical or backup purposes. This property shall be logical TRUE only if no changes have been made to the file data by internal processes or through File Access Services since the last time the object was archived. */ status = WPValidateArgType(&value, BACNET_APPLICATION_TAG_BOOLEAN, &wp_data->error_class, &wp_data->error_code); if (status) { if (value.type.Boolean) { /* FIXME: do something to wp_data->object_instance */ } else { /* FIXME: do something to wp_data->object_instance */ } } break; case PROP_FILE_SIZE: /* If the file size can be changed by writing to the file, and File_Access_Method is STREAM_ACCESS, then this property shall be writable. */ status = WPValidateArgType(&value, BACNET_APPLICATION_TAG_UNSIGNED_INT, &wp_data->error_class, &wp_data->error_code); if (status) { /* FIXME: do something with value.type.Unsigned to wp_data->object_instance */ } break; case PROP_OBJECT_IDENTIFIER: case PROP_OBJECT_NAME: case PROP_OBJECT_TYPE: case PROP_DESCRIPTION: case PROP_FILE_TYPE: case PROP_MODIFICATION_DATE: case PROP_READ_ONLY: case PROP_FILE_ACCESS_METHOD: wp_data->error_class = ERROR_CLASS_PROPERTY; wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED; break; default: wp_data->error_class = ERROR_CLASS_PROPERTY; wp_data->error_code = ERROR_CODE_UNKNOWN_PROPERTY; break; } return status; }