LCOV - code coverage report
Current view: top level - builds/gnutls/coverage/gnutls-git/lib - iov.c (source / functions) Hit Total Coverage
Test: GnuTLS-3.6.14 Code Coverage Lines: 65 68 95.6 %
Date: 2020-10-30 04:50:48 Functions: 3 3 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (C) 2019 Red Hat, Inc.
       3             :  *
       4             :  * Author: Daiki Ueno
       5             :  *
       6             :  * This file is part of GnuTLS.
       7             :  *
       8             :  * The GnuTLS is free software; you can redistribute it and/or
       9             :  * modify it under the terms of the GNU Lesser General Public License
      10             :  * as published by the Free Software Foundation; either version 2.1 of
      11             :  * the License, or (at your option) any later version.
      12             :  *
      13             :  * This library is distributed in the hope that it will be useful, but
      14             :  * WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      16             :  * Lesser General Public License for more details.
      17             :  *
      18             :  * You should have received a copy of the GNU Lesser General Public License
      19             :  * along with this program.  If not, see <https://www.gnu.org/licenses/>
      20             :  *
      21             :  */
      22             : 
      23             : #include "gnutls_int.h"
      24             : #include "iov.h"
      25             : 
      26             : /**
      27             :  * _gnutls_iov_iter_init:
      28             :  * @iter: the iterator
      29             :  * @iov: the data buffers
      30             :  * @iov_count: the number of data buffers
      31             :  * @block_size: block size to iterate
      32             :  *
      33             :  * Initialize the iterator.
      34             :  *
      35             :  * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise
      36             :  *   an error code is returned
      37             :  */
      38             : int
      39      837583 : _gnutls_iov_iter_init(struct iov_iter_st *iter,
      40             :                       const giovec_t *iov, size_t iov_count,
      41             :                       size_t block_size)
      42             : {
      43      837583 :         if (unlikely(block_size > MAX_CIPHER_BLOCK_SIZE))
      44           0 :                 return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
      45             : 
      46      837583 :         iter->iov = iov;
      47      837583 :         iter->iov_count = iov_count;
      48      837583 :         iter->iov_index = 0;
      49      837583 :         iter->iov_offset = 0;
      50      837583 :         iter->block_size = block_size;
      51      837583 :         iter->block_offset = 0;
      52      837583 :         return 0;
      53             : }
      54             : 
      55             : /**
      56             :  * _gnutls_iov_iter_next:
      57             :  * @iter: the iterator
      58             :  * @data: the return location of extracted data
      59             :  *
      60             :  * Retrieve block(s) pointed by @iter and advance it to the next
      61             :  * position.  It returns the number of bytes in @data.  At the end of
      62             :  * iteration, 0 is returned.
      63             :  *
      64             :  * If the data stored in @iter is not multiple of the block size, the
      65             :  * remaining data is stored in the "block" field of @iter with the
      66             :  * size stored in the "block_offset" field.
      67             :  *
      68             :  * Returns: On success, a value greater than or equal to zero is
      69             :  *   returned, otherwise a negative error code is returned
      70             :  */
      71             : ssize_t
      72     1902230 : _gnutls_iov_iter_next(struct iov_iter_st *iter, uint8_t **data)
      73             : {
      74     3136710 :         while (iter->iov_index < iter->iov_count) {
      75     1471160 :                 const giovec_t *iov = &iter->iov[iter->iov_index];
      76     1471160 :                 uint8_t *p = iov->iov_base;
      77     1471160 :                 size_t len = iov->iov_len;
      78     1471160 :                 size_t block_left;
      79             : 
      80     1471160 :                 if (!p) {
      81             :                         // skip NULL iov entries, else we run into issues below
      82          32 :                         iter->iov_index++;
      83          32 :                         continue;
      84             :                 }
      85             : 
      86     1471130 :                 if (unlikely(len < iter->iov_offset))
      87           0 :                         return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
      88     1471130 :                 len -= iter->iov_offset;
      89     1471130 :                 p += iter->iov_offset;
      90             : 
      91             :                 /* We have at least one full block, return a whole set
      92             :                  * of full blocks immediately. */
      93     1471130 :                 if (iter->block_offset == 0 && len >= iter->block_size) {
      94      227066 :                         if ((len % iter->block_size) == 0) {
      95       12491 :                                 iter->iov_index++;
      96       12491 :                                 iter->iov_offset = 0;
      97             :                         } else {
      98      214575 :                                 len -= (len % iter->block_size);
      99      214575 :                                 iter->iov_offset += len;
     100             :                         }
     101             : 
     102             :                         /* Return the blocks. */
     103      227066 :                         *data = p;
     104      227066 :                         return len;
     105             :                 }
     106             : 
     107             :                 /* We can complete one full block to return. */
     108     1244060 :                 block_left = iter->block_size - iter->block_offset;
     109     1244060 :                 if (len >= block_left) {
     110        9613 :                         memcpy(iter->block + iter->block_offset, p, block_left);
     111        9613 :                         if (len == block_left) {
     112        9576 :                                 iter->iov_index++;
     113        9576 :                                 iter->iov_offset = 0;
     114             :                         } else
     115          37 :                                 iter->iov_offset += block_left;
     116        9613 :                         iter->block_offset = 0;
     117             : 
     118             :                         /* Return the filled block. */
     119        9613 :                         *data = iter->block;
     120        9613 :                         return iter->block_size;
     121             :                 }
     122             : 
     123             :                 /* Not enough data for a full block, store in temp
     124             :                  * memory and continue. */
     125     1234450 :                 memcpy(iter->block + iter->block_offset, p, len);
     126     1234450 :                 iter->block_offset += len;
     127     1234450 :                 iter->iov_index++;
     128     1234450 :                 iter->iov_offset = 0;
     129             :         }
     130             : 
     131     1665550 :         if (iter->block_offset > 0) {
     132      827968 :                 size_t len = iter->block_offset;
     133             : 
     134             :                 /* Return the incomplete block. */
     135      827968 :                 *data = iter->block;
     136      827968 :                 iter->block_offset = 0;
     137      827968 :                 return len;
     138             :         }
     139             : 
     140             :         return 0;
     141             : }
     142             : 
     143             : /**
     144             :  * _gnutls_iov_iter_sync:
     145             :  * @iter: the iterator
     146             :  * @data: data returned by _gnutls_iov_iter_next
     147             :  * @data_size: size of @data
     148             :  *
     149             :  * Flush the content of temp buffer (if any) to the data buffer.
     150             :  */
     151             : int
     152          56 : _gnutls_iov_iter_sync(struct iov_iter_st *iter, const uint8_t *data,
     153             :                       size_t data_size)
     154             : {
     155          56 :         size_t iov_index;
     156          56 :         size_t iov_offset;
     157             : 
     158             :         /* We didn't return the cached block. */
     159          56 :         if (data != iter->block)
     160             :                 return 0;
     161             : 
     162          21 :         iov_index = iter->iov_index;
     163          21 :         iov_offset = iter->iov_offset;
     164             : 
     165             :         /* When syncing a cache block we walk backwards because we only have a
     166             :          * pointer to were the block ends in the iovec, walking backwards is
     167             :          * fine as we are always writing a full block, so the whole content
     168             :          * is written in the right places:
     169             :          * iovec:     |--0--|---1---|--2--|-3-|
     170             :          * block:     |-----------------------|
     171             :          * 1st write                      |---|
     172             :          * 2nd write                |-----
     173             :          * 3rd write        |-------
     174             :          * last write |-----
     175             :          */
     176          59 :         while (data_size > 0) {
     177             :                 const giovec_t *iov;
     178             :                 uint8_t *p;
     179             :                 size_t to_write;
     180             : 
     181          73 :                 while (iov_offset == 0) {
     182          35 :                         if (unlikely(iov_index == 0))
     183           0 :                                 return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
     184             : 
     185          35 :                         iov_index--;
     186          35 :                         iov_offset = iter->iov[iov_index].iov_len;
     187             :                 }
     188             : 
     189          38 :                 iov = &iter->iov[iov_index];
     190          38 :                 p = iov->iov_base;
     191          38 :                 to_write = MIN(data_size, iov_offset);
     192             : 
     193          38 :                 iov_offset -= to_write;
     194          38 :                 data_size -= to_write;
     195             : 
     196          38 :                 memcpy(p + iov_offset, &iter->block[data_size], to_write);
     197             :         }
     198             : 
     199             :         return 0;
     200             : }

Generated by: LCOV version 1.14