@@ -36,6 +36,11 @@ static int coap_get_current_from_response_pkt(const struct coap_packet *cpkt)
3636 return GET_BLOCK_NUM (block ) << (GET_BLOCK_SIZE (block ) + 4 );
3737}
3838
39+ static bool has_pending (struct download_client * client )
40+ {
41+ return client -> coap .pending .timeout > 0 ;
42+ }
43+
3944int coap_block_init (struct download_client * client , size_t from )
4045{
4146 coap_block_transfer_init (& client -> coap .block_ctx ,
@@ -44,8 +49,47 @@ int coap_block_init(struct download_client *client, size_t from)
4449 return 0 ;
4550}
4651
47- int coap_block_update (struct download_client * client , struct coap_packet * pkt ,
48- size_t * blk_off )
52+ int coap_get_recv_timeout (struct download_client * dl )
53+ {
54+ int timeout ;
55+
56+ if (!has_pending (dl )) {
57+ LOG_ERR ("Must have coap pending" );
58+ return -1 ;
59+ }
60+
61+ /* Retransmission is cycled in case recv() times out. In case sending request
62+ * blocks, the time that is used for sending request must be substracted next time
63+ * recv() is called.
64+ */
65+ timeout = dl -> coap .pending .t0 + dl -> coap .pending .timeout - k_uptime_get_32 ();
66+ if (timeout < 0 ) {
67+ /* All time is spent when sending request and time this
68+ * method is called, there is no time left for receiving;
69+ * skip over recv() and initiate retransmission on next
70+ * cycle
71+ */
72+ return 0 ;
73+ }
74+
75+ return timeout ;
76+ }
77+
78+ int coap_initiate_retransmission (struct download_client * dl )
79+ {
80+ if (dl -> coap .pending .timeout == 0 ) {
81+ return - EINVAL ;
82+ }
83+
84+ if (!coap_pending_cycle (& dl -> coap .pending )) {
85+ LOG_ERR ("CoAP max-retransmissions exceeded" );
86+ return -1 ;
87+ }
88+
89+ return 0 ;
90+ }
91+
92+ int coap_block_update (struct download_client * client , struct coap_packet * pkt , size_t * blk_off )
4993{
5094 int err , new_current ;
5195 bool more ;
@@ -100,17 +144,33 @@ int coap_parse(struct download_client *client, size_t len)
100144 const uint8_t * payload ;
101145 struct coap_packet response ;
102146
147+ /* TODO: currently we stop download on every error, but this is mostly not necessary
148+ * and we can just request the same block again using retry mechanism
149+ */
150+
103151 err = coap_packet_parse (& response , client -> buf , len , NULL , 0 );
104152 if (err ) {
105153 LOG_ERR ("Failed to parse CoAP packet, err %d" , err );
106154 return -1 ;
107155 }
108156
157+ coap_pending_clear (& client -> coap .pending );
158+
109159 err = coap_block_update (client , & response , & blk_off );
110160 if (err ) {
111161 return err ;
112162 }
113163
164+ if (coap_header_get_id (& response ) != client -> coap .pending .id ) {
165+ LOG_ERR ("Response is not pending" );
166+ return -1 ;
167+ }
168+
169+ if (coap_header_get_type (& response ) != COAP_TYPE_ACK ) {
170+ LOG_ERR ("Response must be of coap type ACK" );
171+ return -1 ;
172+ }
173+
114174 response_code = coap_header_get_code (& response );
115175 if (response_code != COAP_RESPONSE_CODE_OK &&
116176 response_code != COAP_RESPONSE_CODE_CONTENT ) {
@@ -143,23 +203,28 @@ int coap_parse(struct download_client *client, size_t len)
143203int coap_request_send (struct download_client * client )
144204{
145205 int err ;
206+ uint16_t id ;
146207 char file [FILENAME_SIZE ];
147208 char * path_elem ;
148209 char * path_elem_saveptr ;
149210 struct coap_packet request ;
150211
151- err = coap_packet_init (
152- & request , client -> buf , CONFIG_DOWNLOAD_CLIENT_BUF_SIZE ,
153- COAP_VER , COAP_TYPE_CON , 8 , coap_next_token (),
154- COAP_METHOD_GET , coap_next_id ()
155- );
212+ if (has_pending (client )) {
213+ id = client -> coap .pending .id ;
214+ } else {
215+ id = coap_next_id ();
216+ }
217+
218+ err = coap_packet_init (& request , client -> buf , CONFIG_DOWNLOAD_CLIENT_BUF_SIZE , COAP_VER ,
219+ COAP_TYPE_CON , 8 , coap_next_token (), COAP_METHOD_GET , id );
156220 if (err ) {
157221 LOG_ERR ("Failed to init CoAP message, err %d" , err );
158222 return err ;
159223 }
160224
161225 err = url_parse_file (client -> file , file , sizeof (file ));
162226 if (err ) {
227+ LOG_ERR ("Unable to parse url" );
163228 return err ;
164229 }
165230
@@ -185,9 +250,19 @@ int coap_request_send(struct download_client *client)
185250 return err ;
186251 }
187252
253+ if (!has_pending (client )) {
254+ err = coap_pending_init (& client -> coap .pending , & request , & client -> remote_addr ,
255+ CONFIG_DOWNLOAD_CLIENT_COAP_MAX_RETRANSMIT_REQUEST_COUNT );
256+ if (err < 0 ) {
257+ return - EINVAL ;
258+ }
259+
260+ coap_pending_cycle (& client -> coap .pending );
261+ }
262+
188263 LOG_DBG ("CoAP next block: %d" , client -> coap .block_ctx .current );
189264
190- err = socket_send (client , request .offset , 0 );
265+ err = socket_send (client , request .offset , client -> coap . pending . timeout );
191266 if (err ) {
192267 LOG_ERR ("Failed to send CoAP request, errno %d" , errno );
193268 return err ;
0 commit comments