LCOV - code coverage report
Current view: top level - common/stream - openssl_stream.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 56 66 84.8 %
Date: 2024-04-26 00:35:57 Functions: 6 7 85.7 %

          Line data    Source code
       1             : /*
       2             :  * SPDX-License-Identifier: MPL-2.0
       3             :  *
       4             :  * This Source Code Form is subject to the terms of the Mozilla Public
       5             :  * License, v. 2.0.  If a copy of the MPL was not distributed with this
       6             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       7             :  *
       8             :  * Copyright 2024 MonetDB Foundation;
       9             :  * Copyright August 2008 - 2023 MonetDB B.V.;
      10             :  * Copyright 1997 - July 2008 CWI.
      11             :  */
      12             : 
      13             : #include "monetdb_config.h"
      14             : #include "stream.h"
      15             : #include "stream_internal.h"
      16             : 
      17             : #include <openssl/ssl.h>
      18             : #include <openssl/err.h>
      19             : 
      20             : static ssize_t ostream_read(stream *restrict s, void *restrict buf, size_t elmsize, size_t cnt);
      21             : static ssize_t ostream_write(stream *restrict s, const void *restrict buf, size_t elmsize, size_t cnt);
      22             : static void ostream_close(stream *s);
      23             : static int ostream_flush(stream *s, mnstr_flush_level flush_level);
      24             : 
      25             : stream *
      26           4 : openssl_rstream(const char *host_colon_port, BIO *bio)
      27             : {
      28           4 :         stream *s = openssl_wstream(host_colon_port, bio);
      29           4 :         if (s != NULL)
      30           4 :                 s->readonly = true;
      31           4 :         return s;
      32             : }
      33             : stream *
      34           8 : openssl_wstream(const char *host_colon_port, BIO *bio)
      35             : {
      36           8 :         assert(bio);
      37             : 
      38           8 :         stream *s = create_stream(host_colon_port);
      39           8 :         if (s == NULL)
      40             :                 return NULL;
      41             : 
      42           8 :         s->stream_data.p = bio;
      43           8 :         s->readonly = false;
      44           8 :         s->binary = true;
      45           8 :         s->read = ostream_read;
      46           8 :         s->write = ostream_write;
      47           8 :         s->close = ostream_close;
      48           8 :         s->flush = ostream_flush;
      49             : 
      50           8 :         return s;
      51             : }
      52             : 
      53             : static ssize_t
      54           0 : ostream_error(stream *s, mnstr_error_kind kind)
      55             : {
      56           0 :         unsigned long err = ERR_get_error();
      57           0 :         const char *msg = ERR_reason_error_string(err);
      58           0 :         mnstr_set_error(s, kind, "%s", msg);
      59           0 :         return -1;
      60             : }
      61             : 
      62             : 
      63             : ssize_t
      64          16 : ostream_read(stream *restrict s, void *restrict buf, size_t elmsize, size_t cnt)
      65             : {
      66          16 :         BIO *bio = (BIO*)s->stream_data.p;
      67             : 
      68          16 :         char *start = (char*)buf;
      69          16 :         size_t size = elmsize * cnt;
      70          16 :         if (size == 0)
      71             :                 return 0;
      72             : 
      73             :         // iterate in order to read a complete number of items
      74             :         size_t pos = 0;
      75          16 :         do {
      76             :                 // pity we cannot use BIO_read_ex, BIO_read takes an int, not size_t
      77          16 :                 size_t to_read = size - pos;
      78          16 :                 if (to_read > INT_MAX)
      79             :                         to_read = INT_MAX;
      80          16 :                 int nread = BIO_read(bio, start + pos, (int)to_read);
      81          16 :                 if (nread < 0)
      82           0 :                         return ostream_error(s, MNSTR_READ_ERROR);
      83          16 :                 if (nread == 0) {
      84           0 :                         s->eof = 0;
      85           0 :                         break;
      86             :                 }
      87          16 :                 pos += (size_t)nread;
      88             : 
      89             :                 // adjust pos to the smallest multiple of elmsize.
      90             :                 // example 1: size=4 pos=7 (-7)%4=1, newsize=8
      91          16 :                 size_t delta = (0-pos) % size;
      92          16 :                 if (size - pos > delta)
      93           0 :                         size = pos + delta;
      94          16 :         } while (pos < size);
      95             : 
      96          16 :         return (ssize_t) (pos / elmsize);
      97             : }
      98             : 
      99             : ssize_t
     100          12 : ostream_write(stream *restrict s, const void *restrict buf, size_t elmsize, size_t cnt)
     101             : {
     102          12 :         BIO *bio = (BIO*)s->stream_data.p;
     103             : 
     104          12 :         char *start = (char*)buf;
     105          12 :         size_t size = elmsize * cnt;
     106          12 :         size_t pos = 0;
     107          24 :         while (pos < size) {
     108             :                 // pity we cannot use BIO_write_ex, BIO_write takes an int, not size_t
     109          12 :                 size_t to_write = size - pos;
     110          12 :                 if (to_write > INT_MAX)
     111             :                         to_write = INT_MAX;
     112          12 :                 int nwritten = BIO_write(bio, start + pos, (int)to_write);
     113          12 :                 if (nwritten < 0)
     114           0 :                         return ostream_error(s, MNSTR_WRITE_ERROR);
     115          12 :                 if (nwritten == 0 && !BIO_should_retry(bio))
     116             :                         break;
     117          12 :                 pos += (size_t)nwritten;
     118             :         }
     119             : 
     120          12 :         return (ssize_t) (pos / elmsize);
     121             : }
     122             : 
     123             : void
     124           8 : ostream_close(stream *s)
     125             : {
     126           8 :         BIO *bio = (BIO*) s->stream_data.p;
     127           8 :         BIO_free(bio);
     128           8 :         s->stream_data.p = NULL;
     129           8 : }
     130             : 
     131             : int
     132           4 : ostream_flush(stream *s, mnstr_flush_level flush_level)
     133             : {
     134           4 :         (void)flush_level;
     135           4 :         BIO *bio = (BIO*) s->stream_data.p;
     136             :         // This segfaults, I don't understand why.
     137             :         // It seems to work without it so for the time being leave it commented out.
     138             :         // if (1 != BIO_flush(bio))
     139             :         //      return ostream_error(s, MNSTR_WRITE_ERROR);
     140           4 :         (void)bio;
     141           4 :         return 0;
     142             : }

Generated by: LCOV version 1.14