Skip to content

Commit

Permalink
file: Add support for keep alive messages
Browse files Browse the repository at this point in the history
This patch adds support for keep alive messages and handles various
other state management introduced in the latest osdp specification.

Related-to: #191
Signed-off-by: Siddharth Chandrasekaran <[email protected]>
  • Loading branch information
sidcha committed Aug 15, 2024
1 parent 86ee45d commit e8205a0
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 22 deletions.
80 changes: 58 additions & 22 deletions src/osdp_file.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,14 @@
#define FILE_TRANSFER_HEADER_SIZE 11
#define FILE_TRANSFER_STAT_SIZE 7

#define OSDP_FILE_TX_STATUS_ACK 0
#define OSDP_FILE_TX_STATUS_CONTENTS_PROCESSED 1
#define OSDP_FILE_TX_STATUS_PD_RESET 2
#define OSDP_FILE_TX_STATUS_KEEP_ALIVE 3
#define OSDP_FILE_TX_STATUS_ERR_ABORT -1
#define OSDP_FILE_TX_STATUS_ERR_UNKNOWN -2
#define OSDP_FILE_TX_STATUS_ERR_INVALID -3

static inline void file_state_reset(struct osdp_file *f)
{
f->flags = 0;
Expand All @@ -32,9 +40,19 @@ static inline bool file_tx_in_progress(struct osdp_file *f)

/* --- Sender CMD/RESP Handers --- */

int osdp_file_cmd_tx_build(struct osdp_pd *pd, uint8_t *buf, int max_len)
static void write_file_tx_header(struct osdp_file *f, uint8_t *buf)
{
int len = 0;

U8_TO_BYTES_LE(f->file_id, buf, len);
U32_TO_BYTES_LE(f->size, buf, len);
U32_TO_BYTES_LE(f->offset, buf, len);
U16_TO_BYTES_LE(f->length, buf, len);
assert(len == FILE_TRANSFER_HEADER_SIZE);
}

int osdp_file_cmd_tx_build(struct osdp_pd *pd, uint8_t *buf, int max_len)
{
int buf_available;
struct osdp_file *f = TO_FILE(pd);
uint8_t *data = buf + FILE_TRANSFER_HEADER_SIZE;
Expand All @@ -43,14 +61,21 @@ int osdp_file_cmd_tx_build(struct osdp_pd *pd, uint8_t *buf, int max_len)
* We should never reach this function if a valid file transfer as in
* progress.
*/
BUG_ON(f == NULL || f->state != OSDP_FILE_INPROG);
BUG_ON(f == NULL);
BUG_ON(f->state != OSDP_FILE_INPROG && f->state != OSDP_FILE_KEEP_ALIVE);

if ((size_t)max_len <= FILE_TRANSFER_HEADER_SIZE) {
LOG_ERR("TX_Build: insufficient space need:%zu have:%d",
FILE_TRANSFER_HEADER_SIZE, max_len);
goto reply_abort;
}

if (f->state == OSDP_FILE_KEEP_ALIVE) {
LOG_DBG("TX_Build: keep-alive");
write_file_tx_header(f, buf);
return FILE_TRANSFER_HEADER_SIZE;
}

/**
* OSDP File module is a bit different than the rest of LibOSDP: it
* tries to greedily consume all available packet space. We need to
Expand All @@ -74,13 +99,9 @@ int osdp_file_cmd_tx_build(struct osdp_pd *pd, uint8_t *buf, int max_len)
}

/* fill the packet buffer (layout: struct osdp_cmd_file_xfer) */
U8_TO_BYTES_LE(f->file_id, buf, len);
U32_TO_BYTES_LE(f->size, buf, len);
U32_TO_BYTES_LE(f->offset, buf, len);
U16_TO_BYTES_LE(f->length, buf, len);
assert(len == FILE_TRANSFER_HEADER_SIZE);
write_file_tx_header(f, buf);

return len + f->length;
return FILE_TRANSFER_HEADER_SIZE + f->length;

reply_abort:
LOG_ERR("TX_Build: Aborting file transfer due to unrecoverable error!");
Expand All @@ -91,6 +112,7 @@ int osdp_file_cmd_tx_build(struct osdp_pd *pd, uint8_t *buf, int max_len)
int osdp_file_cmd_stat_decode(struct osdp_pd *pd, uint8_t *buf, int len)
{
int pos = 0;
bool do_close = false;
struct osdp_file *f = TO_FILE(pd);
struct osdp_cmd_file_stat stat;

Expand All @@ -115,27 +137,41 @@ int osdp_file_cmd_stat_decode(struct osdp_pd *pd, uint8_t *buf, int len)
BYTES_TO_U16_LE(buf, pos, stat.status);
BYTES_TO_U16_LE(buf, pos, stat.rx_size);
assert(pos == len);

if (stat.status == 0) {
f->offset += f->length;
f->errors = 0;
} else {
f->errors++;
assert(f->offset + f->length <= f->size);

if (stat.status != OSDP_FILE_TX_STATUS_ACK &&
stat.status != OSDP_FILE_TX_STATUS_CONTENTS_PROCESSED &&
stat.status != OSDP_FILE_TX_STATUS_PD_RESET &&
stat.status != OSDP_FILE_TX_STATUS_KEEP_ALIVE) {
LOG_ERR("Stat_Decode: File transfer error; "
"status:%d offset:%d", stat.status, f->offset);
return -1;
}
f->length = 0;

f->offset += f->length;
do_close = f->length && (f->offset == f->size);
f->wait_time_ms = stat.delay;
f->tstamp = osdp_millis_now();
f->length = 0;
f->errors = 0;
if (f->offset != f->size) {
/* Transfer is in progress */
return 0;
}

assert(f->offset <= f->size);
if (f->offset == f->size) { /* EOF */
if (f->ops.close(f->ops.arg) < 0) {
LOG_ERR("Stat_Decode: Close failed!");
return -1;
}
/* File transfer complete; close file and end file transfer */

if (do_close && f->ops.close(f->ops.arg) < 0) {
LOG_ERR("Stat_Decode: Close failed! ... continuing");
}

if (stat.status == OSDP_FILE_TX_STATUS_KEEP_ALIVE) {
f->state = OSDP_FILE_KEEP_ALIVE;
LOG_INF("Stat_Decode: File transfer done; keep alive");
} else {
f->state = OSDP_FILE_DONE;
LOG_INF("Stat_Decode: File transfer complete");
}

return 0;
}

Expand Down
1 change: 1 addition & 0 deletions src/osdp_file.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ enum file_tx_state_e {
OSDP_FILE_IDLE,
OSDP_FILE_INPROG,
OSDP_FILE_DONE,
OSDP_FILE_KEEP_ALIVE,
};

struct osdp_file {
Expand Down

0 comments on commit e8205a0

Please sign in to comment.