Line data Source code
1 : #include <string.h>
2 :
3 : #include "log.h"
4 : #include "block.h"
5 : #include "buffered.h"
6 : #include "elinktable.h"
7 : #include "unbuffered.h"
8 :
9 :
10 : int submit_subchunk_unbuffered(struct block_decoder* decoder, uint32_t type, void* data, uint32_t len);
11 : int submit_subchunk_buffered(struct block_decoder* decoder, uint32_t type, void* data, uint32_t len);
12 : int submit_chunk_unbuffered(struct block_decoder* decoder, struct iovec* iov, size_t count);
13 : int submit_chunk_buffered(struct block_decoder* decoder, void* data, size_t len);
14 :
15 :
16 : void
17 85 : init_decoder(struct block_decoder* decoder, unsigned elink_idx, struct elink_entry* elink_entry,
18 : unsigned buffered_mode, unsigned block_size, unsigned trailer_size, struct config* cfg)
19 : {
20 85 : decoder->scratch = (uint8_t*)calloc(cfg->max_buf_chunk_size, 1);
21 85 : decoder->iov = (struct iovec*)calloc(MAX_IOV_SIZE, sizeof(struct iovec));
22 85 : decoder->scratch_size = cfg->max_buf_chunk_size;
23 85 : decoder->scratch_pos = 0;
24 85 : decoder->iov_cnt = 0;
25 85 : decoder->error = 0;
26 85 : decoder->state = DEC_STATE_NONE;
27 85 : decoder->elink_idx = elink_idx;
28 85 : decoder->elink_entry = elink_entry;
29 85 : decoder->reentry_n_subchunks = 0;
30 85 : decoder->seqnr_err = 0;
31 85 : decoder->block_address = cfg->dma_buffer_vaddr;
32 85 : if (buffered_mode) {
33 55 : decoder->submit_subchunk = submit_subchunk_buffered;
34 : } else {
35 30 : decoder->submit_subchunk = submit_subchunk_unbuffered;
36 : }
37 85 : decoder->buffered_mode = buffered_mode;
38 85 : decoder->block_size = block_size;
39 85 : decoder->trailer_size = trailer_size;
40 85 : decoder->subchunk_indices = (subchunk_t*)malloc((block_size / trailer_size) * sizeof(subchunk_t));
41 85 : decoder->dma_buffer_vaddr = cfg->dma_buffer_vaddr;
42 85 : }
43 :
44 85 : void free_decoder(struct block_decoder* decoder)
45 : {
46 85 : free(decoder->scratch);
47 85 : free(decoder->iov);
48 85 : free(decoder->subchunk_indices);
49 85 : decoder->subchunk_indices = NULL;
50 85 : }
51 :
52 : int
53 1166453007 : decode_block(struct block_decoder* decoder, struct block* b)
54 : {
55 : /* block address for unbuffered mode */
56 1166453007 : decoder->block_address = ((uint64_t)b - decoder->dma_buffer_vaddr) & 0xFFFFFFFF;
57 :
58 : /* clear out any leftover chunks */
59 1166453007 : if(decoder->state == DEC_STATE_SENDING) {
60 73435 : LOG_TRACE("sending leftover data");
61 73435 : int result;
62 73435 : if(decoder->buffered_mode) {
63 73435 : result = submit_chunk_buffered(decoder, decoder->scratch, decoder->scratch_pos);
64 : } else {
65 0 : result = submit_chunk_unbuffered(decoder, decoder->iov, decoder->iov_cnt);
66 : }
67 73435 : if(0 == result) {
68 36740 : decoder->state = DEC_STATE_NONE;
69 36740 : decoder->iov_cnt = 0;
70 36740 : decoder->scratch_pos = 0;
71 : } else {
72 : return BLOCK_AGAIN;
73 : }
74 : }
75 :
76 1166416312 : unsigned trailer_size = decoder->trailer_size;
77 :
78 1166416312 : unsigned n_subchunks = 0;
79 1166416312 : unsigned start_subchunk = 0;
80 1166416312 : unsigned expected_seqnr;
81 :
82 1166416312 : if(decoder->reentry_n_subchunks == 0) {
83 1164562491 : unsigned block_size = decoder->block_size;
84 1164562491 : uint16_t* raw_block = (uint16_t*)b;
85 :
86 : // Check header
87 1164562491 : if (b->hdr.sob >= 0xC0CE && raw_block[1] != raw_block[0]) { //FLX-1829
88 584021209 : block_size = ((b->hdr.sob >> 8) - 0xC0 + 1) * 1024;
89 584021209 : if (block_size != decoder->block_size) {
90 2 : LOG_ERR("received block header 0x%x with irregular block size %d, expected %d",
91 : b->hdr.sob, block_size, decoder->block_size);
92 2 : return BLOCK_ERROR;
93 : }
94 584021207 : if (trailer_size != 4) {
95 0 : LOG_ERR("received invalid block header 0x%x for trailer size %d", b->hdr.sob, trailer_size);
96 0 : return BLOCK_ERROR;
97 : }
98 580541282 : } else if (b->hdr.sob == 0xABCD) {
99 580476768 : if (block_size != 1024) {
100 2 : LOG_ERR("received invalid block header 0x%x for block size %d", b->hdr.sob, block_size);
101 2 : return BLOCK_ERROR;
102 : }
103 580476766 : if (trailer_size != 2) {
104 2 : LOG_ERR("received invalid block header 0x%x for trailer size %d", b->hdr.sob, trailer_size);
105 2 : return BLOCK_ERROR;
106 : }
107 : }
108 : else {
109 64514 : if (raw_block[1] == raw_block[0] && block_size == 1024 && trailer_size == 2){
110 2 : LOG_DBG("Block header %X %X with constant part overwritten. Not discarded (FLX-1829).",
111 : raw_block[1], raw_block[0]);
112 : }
113 : else{
114 64512 : LOG_ERR("received invalid block header 0x%x, expected 0xABCD or 0xC0CE - 0xFFCE", b->hdr.sob);
115 64512 : return BLOCK_ERROR;
116 : }
117 : }
118 1164497973 : expected_seqnr = (decoder->last_seqnr + 1) % 32;
119 :
120 : // Check sequence number
121 1164497973 : if(b->hdr.seqnr != expected_seqnr) {
122 3082238 : if(!(decoder->seqnr_err++ % 100)){
123 30844 : LOG_DBG("received wrong sequence number: %d instead of %d (E-link: %d)",
124 : b->hdr.seqnr, expected_seqnr, b->hdr.elink);
125 : }
126 : }
127 1164497973 : decoder->last_seqnr = b->hdr.seqnr;
128 :
129 1164497973 : unsigned pos = block_size - BLOCK_HEADER_SIZE;
130 4293656937 : while(pos > 0) {
131 3129158964 : subchunk_trailer_t* t = (subchunk_trailer_t*)(b->data + pos - trailer_size);
132 :
133 3129158964 : unsigned sc_len;
134 : //Block checks:
135 : //spot FE BUSY (0xe05 trailer) and inconsistencies in the data from the firmware
136 3129158964 : if (trailer_size == 2) {
137 1657655591 : if(*(uint16_t*)t == 0xe05c){
138 0 : t = (subchunk_trailer_t*)(b->data + pos - trailer_size - trailer_size);
139 0 : pos-=2;
140 : }
141 1657655591 : sc_len = t->data16b.length;
142 1657655591 : if (sc_len > block_size - BLOCK_HEADER_SIZE - trailer_size) {
143 0 : LOG_WARN("Block discarded due to inconsistent subchunk length %u", sc_len);
144 0 : return BLOCK_ERROR;
145 : }
146 : } else {
147 1471503373 : sc_len = t->data32b.length;
148 1471503373 : if (sc_len > block_size - BLOCK_HEADER_SIZE - trailer_size) {
149 0 : LOG_WARN("Block discarded due to inconsistent subchunk length. Subchunk length %u", sc_len);
150 0 : return BLOCK_ERROR;
151 : }
152 : }
153 :
154 3129158964 : unsigned pad = (trailer_size - sc_len % trailer_size) % trailer_size;
155 3129158964 : pos -= sc_len + trailer_size + pad;
156 3129158964 : if(pos > block_size - BLOCK_HEADER_SIZE) {
157 0 : LOG_WARN("Block read ptr outside block. Pos 0x%x pad %u sc_len %u. Hdr 0x%x, seqnr %u elink 0x%x",
158 : pos, pad, sc_len, b->hdr.sob, b->hdr.seqnr, b->hdr.elink);
159 0 : return BLOCK_TRUNCATED;
160 : }
161 :
162 3129158964 : decoder->subchunk_indices[n_subchunks].pos = pos;
163 3129158964 : decoder->subchunk_indices[n_subchunks].trailer.value = t->value;
164 3129158964 : n_subchunks++;
165 : }
166 : } else {
167 1853821 : LOG_TRACE("Reentry");
168 1853821 : n_subchunks = decoder->reentry_n_subchunks;
169 1853821 : start_subchunk = decoder->reentry_i;
170 1853821 : expected_seqnr = decoder->last_seqnr;
171 : }
172 :
173 : // walk subchunks in-order
174 4295474018 : for(unsigned i=start_subchunk; i < n_subchunks; i++) {
175 3130976045 : subchunk_t sc = decoder->subchunk_indices[n_subchunks - i - 1];
176 :
177 3130976045 : uint32_t len;
178 3130976045 : uint32_t type;
179 :
180 3130976045 : if (trailer_size == 2) {
181 1658850370 : len = sc.trailer.data16b.length;
182 1658850370 : type = sc.trailer.data16b.type;
183 1658850370 : decoder->error = sc.trailer.data16b.trunc // CHUNK_FW_TRUNC
184 1658850370 : | (sc.trailer.data16b.err << 2) // CHUNK_FW_MALF
185 1658850370 : | (sc.trailer.data16b.crcerr << 3); // CHUNK_FW_CRC
186 : } else {
187 1472125675 : len = sc.trailer.data32b.length;
188 1472125675 : type = sc.trailer.data32b.type;
189 1472125675 : decoder->error = sc.trailer.data32b.trunc // CHUNK_FW_TRUNC
190 1472125675 : | (sc.trailer.data32b.err << 2) // CHUNK_FW_MALF
191 1472125675 : | (sc.trailer.data32b.crcerr << 3); // CHUNK_FW_CRC
192 : }
193 :
194 : // if current subchunk could not be sent, return AGAIN so it will be resent later
195 3130976045 : int result = decoder->submit_subchunk(decoder, type, b->data + sc.pos, len);
196 3130976045 : if(result == BLOCK_AGAIN) {
197 : // CAREFUL THAT BUFFERED HAS A SCRATCH SPACE UNBUFFERED DOESN'T AND IT RETURNS AGAIN
198 : // If decoder is in the DEC_STATE_SENDING then the scratch already contains the current subchunk
199 1853821 : decoder->reentry_i = i + (decoder->buffered_mode && decoder->state == DEC_STATE_SENDING);
200 1853821 : decoder->reentry_n_subchunks = n_subchunks;
201 1853821 : return BLOCK_AGAIN;
202 : }
203 : }
204 :
205 1164497973 : if(decoder->elink_entry->type == TTC){
206 6639786 : flush_ttc2h_buffer(decoder->elink_entry, decoder->block_address);
207 : }
208 :
209 1164497973 : decoder->reentry_n_subchunks = 0;
210 1164497973 : decoder->reentry_i = 0;
211 1164497973 : return BLOCK_OK;
212 : }
213 :
214 : void
215 209224 : update_decoder_counters(struct block_decoder* decoder)
216 : {
217 209224 : if(decoder->error & CHUNK_SW_TRUNC){decoder->counters.sw_trunc_chunks++;}
218 209224 : if(decoder->error & CHUNK_FW_TRUNC){decoder->counters.fw_trunc_chunks++;}
219 209224 : if(decoder->error & CHUNK_SW_MALF) {decoder->counters.sw_error_chunks++;}
220 209224 : if(decoder->error & CHUNK_FW_MALF) {decoder->counters.fw_error_chunks++;}
221 209224 : if(decoder->error & CHUNK_FW_CRC) {decoder->counters.fw_crc_chunks++;}
222 209224 : }
223 :
224 :
225 : /* Returns BLOCK_AGAIN if a subchunk could not be sent and the block needs to
226 : be reprocessed at a later time. */
227 : int
228 556883157 : submit_subchunk_unbuffered(struct block_decoder* decoder, uint32_t type, void* data, uint32_t len)
229 : {
230 556883157 : LOG_TRACE("subchunk type=%d, len=%u", type, len);
231 :
232 556883157 : switch(type) {
233 77099366 : case CHUNK_FIRST:
234 77099366 : if(decoder->state == DEC_STATE_CONSUMING) {
235 272385 : decoder->error |= CHUNK_SW_TRUNC;
236 : // TODO count error chunk or send out truncated data
237 : }
238 77099366 : decoder->iov[0].iov_base = data;
239 77099366 : decoder->iov[0].iov_len = len;
240 77099366 : decoder->iov_cnt = 1;
241 77099366 : decoder->state = DEC_STATE_CONSUMING;
242 77099366 : return BLOCK_OK;
243 :
244 :
245 78438754 : case CHUNK_LAST:
246 78438754 : if(decoder->state != DEC_STATE_CONSUMING) {
247 : //Decoder in wrong state
248 209224 : decoder->error |= CHUNK_SW_MALF;
249 : }
250 78438754 : if(decoder->iov_cnt >= MAX_IOV_SIZE) {
251 : //mark truncation and send what you have
252 0 : LOG_TRACE("Exceeding max. iov len (CHUNK_LAST)");
253 0 : decoder->error |= CHUNK_SW_TRUNC;
254 0 : if(0 == submit_chunk_unbuffered(decoder, decoder->iov, MAX_IOV_SIZE-1)) { //-1 to fit into limits
255 0 : decoder->state = DEC_STATE_NONE;
256 0 : decoder->iov_cnt = 0;
257 0 : return BLOCK_OK;
258 : }
259 : else{
260 : return BLOCK_AGAIN;
261 : }
262 : }
263 : //normal operation
264 78438754 : decoder->iov[decoder->iov_cnt].iov_base = data;
265 78438754 : decoder->iov[decoder->iov_cnt].iov_len = len;
266 78438754 : decoder->iov_cnt++;
267 78438754 : LOG_TRACE("sending fm chunk (state=DEC_STATE_SENDING)");
268 78438754 : if(0 == submit_chunk_unbuffered(decoder, decoder->iov, decoder->iov_cnt)) {
269 77034544 : decoder->state = DEC_STATE_NONE;
270 77034544 : decoder->iov_cnt = 0;
271 77034544 : LOG_TRACE("setting state to NONE");
272 77034544 : return BLOCK_OK;
273 : } else {
274 1404210 : decoder->iov_cnt--; // because the last subchunk will be supplied again
275 1404210 : return BLOCK_AGAIN;
276 : }
277 :
278 :
279 3134925 : case CHUNK_WHOLE:
280 3134925 : if(decoder->state == DEC_STATE_CONSUMING) {
281 0 : decoder->state = DEC_STATE_NONE;
282 0 : decoder->iov_cnt = 0;
283 0 : decoder->error |= CHUNK_SW_TRUNC;
284 : //Decoder had truncated data
285 : }
286 3134925 : decoder->iov[0].iov_base = data;
287 3134925 : decoder->iov[0].iov_len = len;
288 3134925 : decoder->iov_cnt = 1;
289 3134925 : if(submit_chunk_unbuffered(decoder, decoder->iov, decoder->iov_cnt)) {
290 : return BLOCK_AGAIN;
291 : }
292 : return BLOCK_OK;
293 :
294 :
295 182546401 : case CHUNK_MIDDLE:
296 182546401 : if(decoder->state != DEC_STATE_CONSUMING) {
297 : //Decoder was in wrong state
298 219 : decoder->error |= CHUNK_SW_MALF;
299 : }
300 182546401 : if(decoder->iov_cnt >= MAX_IOV_SIZE) {
301 : //mark truncation and send what you have
302 0 : LOG_TRACE("Exceeding max. iov len (CHUNK_MIDDLE)");
303 0 : decoder->error |= CHUNK_SW_TRUNC;
304 : //Don't reset the iov_cnt nor change the decoder status
305 : //The idea is to reach CHUNK_LAST and send
306 : //decoder->iov_cnt = 0;
307 : //decoder->state = NONE;
308 0 : return BLOCK_OK;
309 : }
310 182546401 : decoder->iov[decoder->iov_cnt].iov_base = data;
311 182546401 : decoder->iov[decoder->iov_cnt].iov_len = len;
312 182546401 : decoder->iov_cnt++;
313 182546401 : decoder->state = DEC_STATE_CONSUMING;
314 182546401 : return BLOCK_OK;
315 :
316 :
317 48310459 : case CHUNK_TIMEOUT:
318 : //Only if the truncation flag is set.
319 48310459 : if(decoder->error & CHUNK_FW_TRUNC){
320 :
321 : //if a LAST is expected, TIMEOUT = LAST
322 0 : if(decoder->state == DEC_STATE_CONSUMING) {
323 0 : LOG_TRACE("CHUNK_TIMEOUT with truncation: forwarding as LAST");
324 0 : if(decoder->iov_cnt >= MAX_IOV_SIZE) {
325 : //mark truncation and send what you have
326 0 : decoder->error |= CHUNK_SW_TRUNC;
327 0 : LOG_TRACE("CHUNK_TIMEOUT with truncation: forwarding as LAST");
328 0 : if(0 == submit_chunk_unbuffered(decoder, decoder->iov, MAX_IOV_SIZE-1)) { //-1 to fit into limits
329 0 : decoder->state = DEC_STATE_NONE;
330 0 : decoder->iov_cnt = 0;
331 0 : return BLOCK_OK;
332 : }
333 : else{ return BLOCK_AGAIN; }
334 : }
335 : //normal operation
336 0 : decoder->iov[decoder->iov_cnt].iov_base = data;
337 0 : decoder->iov[decoder->iov_cnt].iov_len = len;
338 0 : decoder->iov_cnt++;
339 0 : LOG_TRACE("sending fm chunk (state=DEC_STATE_SENDING)");
340 0 : if(0 == submit_chunk_unbuffered(decoder, decoder->iov, decoder->iov_cnt)) {
341 0 : decoder->state = DEC_STATE_NONE;
342 0 : decoder->iov_cnt = 0;
343 0 : LOG_TRACE("setting state to NONE");
344 0 : return BLOCK_OK;
345 : } else {
346 0 : decoder->iov_cnt--; // because the last subchunk will be supplied again
347 0 : return BLOCK_AGAIN;
348 : }
349 : }
350 : //if a LAST is not expected, TIMEOUT = WHOLE
351 : else {
352 0 : LOG_TRACE("CHUNK_TIMEOUT with truncation: forwarding as WHOLE");
353 0 : decoder->iov[0].iov_base = data;
354 0 : decoder->iov[0].iov_len = len;
355 0 : decoder->iov_cnt = 1;
356 0 : if(submit_chunk_unbuffered(decoder, decoder->iov, decoder->iov_cnt)) {
357 : return BLOCK_AGAIN;
358 : };
359 : return BLOCK_OK;
360 : }
361 : }
362 : //no truncation flag
363 : else {return BLOCK_OK;}
364 :
365 : case CHUNK_NULL:
366 : case CHUNK_OOB:
367 : return BLOCK_OK;
368 : }
369 0 : LOG_ERR("invalid subchunk type=%d", type);
370 0 : return BLOCK_OK;
371 : }
372 :
373 : /* Returns BLOCK_AGAIN if a subchunk could not be sent and the block needs to
374 : be reprocessed at a later time. */
375 2574092888 : int submit_subchunk_buffered(struct block_decoder* decoder, uint32_t type, void* data, uint32_t len)
376 : {
377 2574092888 : int ret = BLOCK_OK;
378 2574092888 : unsigned scratch_space_available = decoder->scratch_size - decoder->scratch_pos - (type == CHUNK_FIRST);
379 :
380 2574092888 : LOG_TRACE("subchunk type=%d", type);
381 :
382 2574092888 : switch(type) {
383 :
384 34309453 : case CHUNK_FIRST:
385 34309453 : if(decoder->state == DEC_STATE_CONSUMING) {
386 53309 : LOG_DBG("CHUNK_FIRST: decoder was in wrong state %d", decoder->state);
387 53309 : if (decoder->scratch_pos) {
388 53309 : decoder->scratch[0] |= CHUNK_FW_MALF | CHUNK_SW_TRUNC;
389 53309 : decoder->state = DEC_STATE_SENDING;
390 53309 : if(0 == submit_chunk_buffered(decoder, decoder->scratch, decoder->scratch_pos)) {
391 52898 : decoder->state = DEC_STATE_NONE;
392 52898 : decoder->scratch_pos = 0;
393 52898 : LOG_TRACE("setting state to NONE");
394 : } else {
395 : ret = BLOCK_AGAIN;
396 : break;
397 : }
398 : } else {
399 0 : decoder->state = DEC_STATE_NONE;
400 : }
401 : }
402 34309042 : if(len > scratch_space_available) {
403 : //Truncate data to fit MAX_CHUNK_SIZE. Data will be sent at CHUNK_LAST.
404 0 : LOG_TRACE("received subchunk type FIRST with length > MAX_CHUNK_SIZE. Truncating data.");
405 0 : decoder->error |= CHUNK_SW_TRUNC;
406 0 : len = scratch_space_available;
407 : }
408 : //normal operation: copy chunk header and first sub-chunk
409 34309042 : decoder->scratch[0] = decoder->error;
410 34309042 : memcpy(decoder->scratch+1, data, len);
411 34309042 : decoder->state = DEC_STATE_CONSUMING;
412 34309042 : decoder->scratch_pos = len+1;
413 34309042 : break;
414 :
415 :
416 34245448 : case CHUNK_LAST:
417 34245448 : if(decoder->state != DEC_STATE_CONSUMING) {
418 0 : LOG_DBG("CHUNK_LAST: decoder was in wrong state %d", decoder->state);
419 : //edit the chunk header to report the error
420 0 : decoder->scratch[0] |= CHUNK_FW_MALF;
421 0 : decoder->scratch_pos = 1;
422 0 : scratch_space_available = decoder->scratch_size - 1;
423 : }
424 34245448 : if(len > scratch_space_available) {
425 : //Trucate the subchunk changing len. This should fill all the available scratch space
426 : //No need to return in this block. Data will be sent anyway at the end of it.
427 0 : LOG_TRACE("received subchunk type LAST with length > available scratch space");
428 0 : decoder->scratch[0] |= CHUNK_SW_TRUNC;
429 0 : len = scratch_space_available;
430 : }
431 34245448 : memcpy(decoder->scratch + decoder->scratch_pos, data, len);
432 34245448 : decoder->state = DEC_STATE_SENDING;
433 34245448 : decoder->scratch_pos += len;
434 34245448 : decoder->scratch[0] |= decoder->error;
435 34245448 : if(0 == submit_chunk_buffered(decoder, decoder->scratch, decoder->scratch_pos)) {
436 34209119 : decoder->state = DEC_STATE_NONE;
437 34209119 : decoder->scratch_pos = 0;
438 34209119 : LOG_TRACE("setting state to NONE");
439 : } else {
440 : ret = BLOCK_AGAIN;
441 : }
442 : break;
443 :
444 :
445 803916470 : case CHUNK_WHOLE:
446 803916470 : if(decoder->state == DEC_STATE_CONSUMING) {
447 10687 : LOG_DBG("CHUNK_WHOLE: decoder was in wrong state %d", decoder->state);
448 10687 : if (decoder->scratch_pos) {
449 10687 : decoder->scratch[0] |= CHUNK_FW_MALF | CHUNK_SW_TRUNC;
450 10687 : decoder->state = DEC_STATE_SENDING;
451 10687 : if(0 == submit_chunk_buffered(decoder, decoder->scratch, decoder->scratch_pos)) {
452 10687 : decoder->state = DEC_STATE_NONE;
453 10687 : decoder->scratch_pos = 0;
454 10687 : LOG_TRACE("setting state to NONE");
455 : } else {
456 : ret = BLOCK_AGAIN;
457 : break;
458 : }
459 : } else {
460 0 : decoder->state = DEC_STATE_NONE;
461 : }
462 : }
463 : // This is ugly but it must always work as the first subchunk in the block is preceded by
464 : // the block header and each subsequent one is preceded by the trailer of the previous subchunk
465 803916470 : uint8_t* d = (uint8_t*)data - 1;
466 803916470 : uint8_t old = *d;
467 803916470 : *d = decoder->error;
468 803916470 : if(0 == submit_chunk_buffered(decoder, d, len+1)) {
469 803561224 : decoder->state = DEC_STATE_NONE;
470 : } else {
471 : ret = BLOCK_AGAIN;
472 : }
473 803916470 : *d = old; // restore the old value
474 803916470 : break;
475 :
476 :
477 31082403 : case CHUNK_MIDDLE:
478 31082403 : if(decoder->state != DEC_STATE_CONSUMING) {
479 411 : LOG_DBG("CHUNK_MIDDLE: decoder was in wrong state %d", decoder->state);
480 : //edit the chunk header to report the error
481 411 : decoder->scratch[0] |= CHUNK_FW_MALF | CHUNK_SW_TRUNC;
482 411 : decoder->scratch_pos = 1;
483 411 : scratch_space_available = decoder->scratch_size - 1;
484 : }
485 31082403 : if(len > scratch_space_available) {
486 : //Fill until the buffer is full. Data will be sent when CHUNK_LAST will be reached
487 : //and no free space will be found.
488 0 : LOG_TRACE("received subchunk type MIDDLE with length > available scratch space");
489 0 : decoder->scratch[0] |= CHUNK_SW_TRUNC;
490 0 : len = scratch_space_available;
491 : }
492 31082403 : memcpy(decoder->scratch + decoder->scratch_pos, data, len);
493 31082403 : decoder->state = DEC_STATE_CONSUMING;
494 31082403 : decoder->scratch_pos += len;
495 31082403 : break;
496 :
497 :
498 882503165 : case CHUNK_TIMEOUT:
499 882503165 : if(decoder->state == DEC_STATE_CONSUMING) {
500 : // The scratch space must not be empty
501 0 : if (decoder->error & CHUNK_FW_TRUNC) {
502 : // The subchunk contains some real data
503 : // The current chunk must be closed
504 : ret = submit_subchunk_buffered(decoder, CHUNK_LAST, data, len);
505 : } else {
506 : // This indicates an error - according to the spec timeout
507 : // without truncation cannot happen in the middle of a chunk
508 : // We do nothing now, the current chunk will be closed when
509 : // the next block arrives
510 0 : LOG_DBG("CHUNK_TIMEOUT: decoder was in wrong state %d", decoder->state);
511 : }
512 : } else {
513 : // The scratch space must be empty
514 882503165 : if (decoder->error & CHUNK_FW_TRUNC) {
515 : // This indicates an error - according to the spec
516 : // timeout with truncation cannot happen in between chunks
517 : // However, as the current subchunk must contain some data
518 : // we send it as a malformed chunk
519 0 : decoder->error |= CHUNK_FW_MALF;
520 0 : LOG_DBG("CHUNK_TIMEOUT: decoder was in wrong state %d", decoder->state);
521 0 : ret = submit_subchunk_buffered(decoder, CHUNK_WHOLE, data, len);
522 : } else {
523 : // Normal timeout that we just ignore
524 : break;
525 : }
526 : }
527 : break;
528 :
529 :
530 : case CHUNK_NULL:
531 : case CHUNK_OOB:
532 : break;
533 :
534 0 : default:
535 0 : LOG_ERR("invalid subchunk type=%d", type);
536 0 : break;
537 : }
538 :
539 2574092888 : return ret;
540 : }
541 :
542 : int
543 81573679 : submit_chunk_unbuffered(struct block_decoder* decoder, struct iovec* iov, size_t count)
544 : {
545 163147358 : int result = on_unbuffered_chunk(decoder->elink_entry, decoder->block_address, iov,
546 81573679 : count, decoder->error, 0);
547 81573679 : LOG_TRACE("sending chunk of iov size %lu, result was %d", count, result);
548 81573679 : if(decoder->error){
549 209224 : update_decoder_counters(decoder);
550 209224 : decoder->error=0;
551 : }
552 81573679 : return result;
553 : }
554 :
555 : int
556 838299349 : submit_chunk_buffered(struct block_decoder* decoder, void* data, size_t len)
557 : {
558 838299349 : int result = on_buffered_chunk(decoder->elink_entry, data, len, 0);
559 838299349 : LOG_TRACE("sending chunk of size %d, result was %d", len, result);
560 838299349 : if(decoder->error){
561 0 : update_decoder_counters(decoder);
562 0 : decoder->error=0;
563 : }
564 838299349 : return result;
565 : }
|