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