1111#define FILE_TRANSFER_HEADER_SIZE 11
1212#define FILE_TRANSFER_STAT_SIZE 7
1313
14+ /* Wire-protocol status codes carried in struct osdp_cmd_file_stat::status */
1415#define OSDP_FILE_TX_STATUS_ACK 0
1516#define OSDP_FILE_TX_STATUS_CONTENTS_PROCESSED 1
1617#define OSDP_FILE_TX_STATUS_PD_RESET 2
@@ -30,16 +31,64 @@ static inline void file_state_reset(struct osdp_file *f)
3031 f -> length = 0 ;
3132 f -> errors = 0 ;
3233 f -> size = 0 ;
33- f -> state = OSDP_FILE_IDLE ;
34+ f -> state = OSDP_FILE_TX_STATE_IDLE ;
35+ f -> outcome = OSDP_FILE_TX_OUTCOME_OK ;
36+ f -> is_open = false;
3437 f -> file_id = 0 ;
3538 f -> tstamp = 0 ;
3639 f -> wait_time_ms = 0 ;
3740 f -> cancel_req = false;
3841}
3942
40- static inline bool file_tx_in_progress (struct osdp_file * f )
43+ static inline void file_close_if_open (struct osdp_pd * pd )
4144{
42- return f && f -> state == OSDP_FILE_INPROG ;
45+ struct osdp_file * f = TO_FILE (pd );
46+
47+ if (f -> is_open ) {
48+ if (f -> ops .close (f -> ops .arg ) < 0 ) {
49+ LOG_ERR ("File close failed; continuing" );
50+ }
51+ f -> is_open = false;
52+ }
53+ }
54+
55+ /* Converge every terminal path here: close the file, emit the
56+ * notification (CP only), reset to IDLE. */
57+ static void file_transition_done (struct osdp_pd * pd ,
58+ enum osdp_file_tx_outcome outcome )
59+ {
60+ struct osdp_file * f = TO_FILE (pd );
61+ int file_id = f -> file_id ;
62+
63+ file_close_if_open (pd );
64+ f -> outcome = outcome ;
65+ f -> state = OSDP_FILE_TX_STATE_DONE ;
66+
67+ if (is_cp_mode (pd )) {
68+ if (outcome == OSDP_FILE_TX_OUTCOME_OK_REBOOTING ) {
69+ make_request (pd , CP_REQ_OFFLINE );
70+ }
71+ osdp_file_tx_notify_done (pd , file_id , outcome );
72+ }
73+
74+ file_state_reset (f );
75+ }
76+
77+ static enum osdp_file_tx_outcome file_outcome_from_wire_status (int16_t status )
78+ {
79+ switch (status ) {
80+ case OSDP_FILE_TX_STATUS_CONTENTS_PROCESSED :
81+ return OSDP_FILE_TX_OUTCOME_OK ;
82+ case OSDP_FILE_TX_STATUS_PD_RESET :
83+ return OSDP_FILE_TX_OUTCOME_OK_REBOOTING ;
84+ case OSDP_FILE_TX_STATUS_ERR_UNKNOWN :
85+ return OSDP_FILE_TX_OUTCOME_UNRECOGNIZED ;
86+ case OSDP_FILE_TX_STATUS_ERR_INVALID :
87+ return OSDP_FILE_TX_OUTCOME_INVALID ;
88+ case OSDP_FILE_TX_STATUS_ERR_ABORT :
89+ default :
90+ return OSDP_FILE_TX_OUTCOME_ABORTED ;
91+ }
4392}
4493
4594/* --- Sender CMD/RESP Handers --- */
@@ -61,12 +110,11 @@ int osdp_file_cmd_tx_build(struct osdp_pd *pd, uint8_t *buf, int max_len)
61110 struct osdp_file * f = TO_FILE (pd );
62111 uint8_t * data = buf + FILE_TRANSFER_HEADER_SIZE ;
63112
64- /**
65- * We should never reach this function if a valid file transfer as in
66- * progress.
67- */
68- BUG_ON (f == NULL );
69- BUG_ON (f -> state != OSDP_FILE_INPROG && f -> state != OSDP_FILE_KEEP_ALIVE );
113+ /* Reached only once a transfer is live; osdp_file_tx_get_command()
114+ * has already gated on pd->file and state. */
115+ assert (f != NULL );
116+ assert (f -> state == OSDP_FILE_TX_STATE_INPROG ||
117+ f -> state == OSDP_FILE_TX_STATE_WAIT );
70118
71119 if ((size_t )max_len <= FILE_TRANSFER_HEADER_SIZE ) {
72120 LOG_ERR ("TX_Build: insufficient space; need:%d have:%d" ,
@@ -78,7 +126,7 @@ int osdp_file_cmd_tx_build(struct osdp_pd *pd, uint8_t *buf, int max_len)
78126 LOG_WRN ("TX_Build: Ignoring plaintext file transfer request" );
79127 }
80128
81- if (f -> state == OSDP_FILE_KEEP_ALIVE ) {
129+ if (f -> state == OSDP_FILE_TX_STATE_WAIT ) {
82130 LOG_DBG ("TX_Build: keep-alive" );
83131 write_file_tx_header (f , buf );
84132 return FILE_TRANSFER_HEADER_SIZE ;
@@ -113,14 +161,13 @@ int osdp_file_cmd_tx_build(struct osdp_pd *pd, uint8_t *buf, int max_len)
113161
114162reply_abort :
115163 LOG_ERR ("TX_Build: Aborting file transfer due to unrecoverable error!" );
116- file_state_reset ( f );
164+ file_transition_done ( pd , OSDP_FILE_TX_OUTCOME_ABORTED );
117165 return -1 ;
118166}
119167
120168int osdp_file_cmd_stat_decode (struct osdp_pd * pd , uint8_t * buf , int len )
121169{
122170 int pos = 0 ;
123- bool do_close = false;
124171 struct osdp_file * f = TO_FILE (pd );
125172 struct osdp_cmd_file_stat stat ;
126173
@@ -129,7 +176,8 @@ int osdp_file_cmd_stat_decode(struct osdp_pd *pd, uint8_t *buf, int len)
129176 return -1 ;
130177 }
131178
132- if (f -> state != OSDP_FILE_INPROG && f -> state != OSDP_FILE_KEEP_ALIVE ) {
179+ if (f -> state != OSDP_FILE_TX_STATE_INPROG &&
180+ f -> state != OSDP_FILE_TX_STATE_WAIT ) {
133181 LOG_ERR ("Stat_Decode: File transfer is not in progress!" );
134182 return -1 ;
135183 }
@@ -154,41 +202,33 @@ int osdp_file_cmd_stat_decode(struct osdp_pd *pd, uint8_t *buf, int len)
154202 SET_FLAG_V (f , OSDP_FILE_TX_FLAG_POLL_RESP , stat .control & 0x04 )
155203
156204 f -> offset += f -> length ;
157- do_close = f -> length && (f -> offset == f -> size );
158205 f -> wait_time_ms = stat .delay ;
159206 f -> tstamp = osdp_millis_now ();
160207 f -> length = 0 ;
161208 f -> errors = 0 ;
162209
163- if (f -> offset != f -> size ) {
164- /* Transfer is in progress */
165- return 0 ;
210+ if (stat .status < 0 ) {
211+ LOG_ERR ("Stat_Decode: File transfer error; "
212+ "status:%d offset:%d" , stat .status , f -> offset );
213+ file_transition_done (pd ,
214+ file_outcome_from_wire_status (stat .status ));
215+ return -1 ;
166216 }
167217
168- /* File transfer complete; close file and end file transfer */
169-
170- if (do_close && f -> ops .close (f -> ops .arg ) < 0 ) {
171- LOG_ERR ("Stat_Decode: Close failed! ... continuing" );
218+ if (f -> offset != f -> size ) {
219+ /* Transfer still in progress. */
220+ return 0 ;
172221 }
173222
174- switch (stat .status ) {
175- case OSDP_FILE_TX_STATUS_KEEP_ALIVE :
176- f -> state = OSDP_FILE_KEEP_ALIVE ;
223+ if (stat .status == OSDP_FILE_TX_STATUS_KEEP_ALIVE ) {
224+ f -> state = OSDP_FILE_TX_STATE_WAIT ;
177225 LOG_INF ("Stat_Decode: File transfer done; keep alive" );
178226 return 0 ;
179- case OSDP_FILE_TX_STATUS_PD_RESET :
180- make_request (pd , CP_REQ_OFFLINE );
181- __fallthrough ;
182- case OSDP_FILE_TX_STATUS_CONTENTS_PROCESSED :
183- f -> state = OSDP_FILE_DONE ;
184- LOG_INF ("Stat_Decode: File transfer complete" );
185- return 0 ;
186- default :
187- LOG_ERR ("Stat_Decode: File transfer error; "
188- "status:%d offset:%d" , stat .status , f -> offset );
189- f -> errors ++ ;
190- return -1 ;
191227 }
228+
229+ LOG_INF ("Stat_Decode: File transfer complete" );
230+ file_transition_done (pd , file_outcome_from_wire_status (stat .status ));
231+ return 0 ;
192232}
193233
194234/* --- Receiver CMD/RESP Handler --- */
@@ -220,18 +260,17 @@ int osdp_file_cmd_tx_decode(struct osdp_pd *pd, uint8_t *buf, int len)
220260 assert (pos == sizeof (struct osdp_cmd_file_xfer ));
221261 assert (xfer .length + pos == len );
222262
223- if (f -> state == OSDP_FILE_IDLE || f -> state == OSDP_FILE_DONE ) {
263+ if (f -> state == OSDP_FILE_TX_STATE_IDLE ) {
224264 if (pd -> command_callback ) {
225- /**
226- * Notify app of this command and make sure
227- * we can proceed
228- */
265+ /* Notify app of this command and make sure we can
266+ * proceed */
229267 cmd .id = OSDP_CMD_FILE_TX ;
230268 cmd .file_tx .flags = f -> flags ;
231269 cmd .file_tx .id = xfer .type ;
232270 rc = pd -> command_callback (pd -> command_callback_arg , & cmd );
233- if (rc < 0 )
271+ if (rc < 0 ) {
234272 return -1 ;
273+ }
235274 }
236275
237276 /* new file write request */
@@ -245,10 +284,11 @@ int osdp_file_cmd_tx_decode(struct osdp_pd *pd, uint8_t *buf, int len)
245284 file_state_reset (f );
246285 f -> file_id = xfer .type ;
247286 f -> size = xfer .size ;
248- f -> state = OSDP_FILE_INPROG ;
287+ f -> is_open = true;
288+ f -> state = OSDP_FILE_TX_STATE_INPROG ;
249289 }
250290
251- if (f -> state != OSDP_FILE_INPROG ) {
291+ if (f -> state != OSDP_FILE_TX_STATE_INPROG ) {
252292 LOG_ERR ("TX_Decode: File transfer is not in progress!" );
253293 return -1 ;
254294 }
@@ -278,7 +318,7 @@ int osdp_file_cmd_stat_build(struct osdp_pd *pd, uint8_t *buf, int max_len)
278318 return -1 ;
279319 }
280320
281- if (f -> state != OSDP_FILE_INPROG ) {
321+ if (f -> state != OSDP_FILE_TX_STATE_INPROG ) {
282322 LOG_ERR ("Stat_Build: File transfer is not in progress!" );
283323 return -1 ;
284324 }
@@ -298,13 +338,9 @@ int osdp_file_cmd_stat_build(struct osdp_pd *pd, uint8_t *buf, int max_len)
298338 f -> length = 0 ;
299339 assert (f -> offset <= f -> size );
300340 if (f -> offset == f -> size ) { /* EOF */
301- if (f -> ops .close (f -> ops .arg ) < 0 ) {
302- LOG_ERR ("Stat_Build: Close failed!" );
303- return -1 ;
304- }
305- f -> state = OSDP_FILE_DONE ;
306341 stat .status = OSDP_FILE_TX_STATUS_CONTENTS_PROCESSED ;
307342 LOG_INF ("TX_Decode: File receive complete" );
343+ file_transition_done (pd , OSDP_FILE_TX_OUTCOME_OK );
308344 }
309345
310346 /* fill the packet buffer (layout: struct osdp_cmd_file_stat) */
@@ -321,11 +357,8 @@ int osdp_file_cmd_stat_build(struct osdp_pd *pd, uint8_t *buf, int max_len)
321357
322358void osdp_file_tx_abort (struct osdp_pd * pd )
323359{
324- struct osdp_file * f = TO_FILE (pd );
325-
326- if (file_tx_in_progress (f )) {
327- f -> ops .close (f -> ops .arg );
328- file_state_reset (f );
360+ if (osdp_file_tx_is_active (pd )) {
361+ file_transition_done (pd , OSDP_FILE_TX_OUTCOME_ABORTED );
329362 }
330363}
331364
@@ -341,13 +374,13 @@ int osdp_file_tx_get_command(struct osdp_pd *pd)
341374{
342375 struct osdp_file * f = TO_FILE (pd );
343376
344- if (!f || f -> state == OSDP_FILE_IDLE || f -> state == OSDP_FILE_DONE ) {
377+ if (!osdp_file_tx_is_active ( pd ) ) {
345378 return 0 ;
346379 }
347380
348381 if (f -> errors > OSDP_FILE_ERROR_RETRY_MAX || f -> cancel_req ) {
349382 LOG_ERR ("Aborting transfer of file fd:%d" , f -> file_id );
350- osdp_file_tx_abort (pd );
383+ file_transition_done (pd , OSDP_FILE_TX_OUTCOME_ABORTED );
351384 return CMD_ABORT ;
352385 }
353386
@@ -376,7 +409,7 @@ int osdp_file_tx_command(struct osdp_pd *pd, int file_id, uint32_t flags)
376409 return -1 ;
377410 }
378411
379- if (file_tx_in_progress ( f )) {
412+ if (osdp_file_tx_is_active ( pd )) {
380413 if (flags & OSDP_CMD_FILE_TX_FLAG_CANCEL ) {
381414 if (file_id == f -> file_id ) {
382415 f -> cancel_req = true;
@@ -410,7 +443,8 @@ int osdp_file_tx_command(struct osdp_pd *pd, int file_id, uint32_t flags)
410443 f -> flags = flags ;
411444 f -> file_id = file_id ;
412445 f -> size = size ;
413- f -> state = OSDP_FILE_INPROG ;
446+ f -> is_open = true;
447+ f -> state = OSDP_FILE_TX_STATE_INPROG ;
414448 return 0 ;
415449}
416450
@@ -464,7 +498,8 @@ int osdp_get_file_tx_status(const osdp_t *ctx, int pd_idx,
464498 input_check (ctx , pd_idx );
465499 struct osdp_file * f = TO_FILE (osdp_to_pd (ctx , pd_idx ));
466500
467- if (f -> state != OSDP_FILE_INPROG && f -> state != OSDP_FILE_DONE ) {
501+ if (!f || (f -> state != OSDP_FILE_TX_STATE_INPROG &&
502+ f -> state != OSDP_FILE_TX_STATE_WAIT )) {
468503 LOG_PRINT ("File TX not in progress" );
469504 return -1 ;
470505 }
0 commit comments