LCOV - code coverage report
Current view: top level - felix-star/src - decode.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 240 315 76.2 %
Date: 2025-06-10 03:23:28 Functions: 8 8 100.0 %

          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             : }

Generated by: LCOV version 1.0