File Coverage

amqp_openssl_bio.c
Criterion Covered Total %
statement 39 54 72.2
branch 9 32 28.1
condition n/a
subroutine n/a
pod n/a
total 48 86 55.8


line stmt bran cond sub pod time code
1             /*
2             * Portions created by Alan Antonuk are Copyright (c) 2017 Alan Antonuk.
3             * All Rights Reserved.
4             *
5             * Permission is hereby granted, free of charge, to any person obtaining a
6             * copy of this software and associated documentation files (the "Software"),
7             * to deal in the Software without restriction, including without limitation
8             * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9             * and/or sell copies of the Software, and to permit persons to whom the
10             * Software is furnished to do so, subject to the following conditions:
11             *
12             * The above copyright notice and this permission notice shall be included in
13             * all copies or substantial portions of the Software.
14             *
15             * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16             * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17             * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18             * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19             * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20             * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21             * DEALINGS IN THE SOFTWARE.
22             */
23              
24             #include "amqp_openssl_bio.h"
25             #include "amqp_socket.h"
26              
27             #include
28             #include
29             #if ((defined(_WIN32)) || (defined(__MINGW32__)) || (defined(__MINGW64__)))
30             #ifndef WIN32_LEAN_AND_MEAN
31             #define WIN32_LEAN_AND_MEAN
32             #endif
33             #include
34             #else
35             #include
36             #include
37             #endif
38              
39             #ifdef MSG_NOSIGNAL
40             #define AMQP_USE_AMQP_BIO
41             #endif
42              
43             static int amqp_ssl_bio_initialized = 0;
44              
45             #ifdef AMQP_USE_AMQP_BIO
46              
47             static BIO_METHOD *amqp_bio_method;
48              
49 17           static int amqp_openssl_bio_should_retry(int res) {
50 17 50         if (res == -1) {
51 17           int err = amqp_os_socket_error();
52 17 50         if (
53             #ifdef EWOULDBLOCK
54 0 0         err == EWOULDBLOCK ||
55             #endif
56             #ifdef WSAEWOULDBLOCK
57             err == WSAEWOULDBLOCK ||
58             #endif
59             #ifdef ENOTCONN
60 0 0         err == ENOTCONN ||
61             #endif
62             #ifdef EINTR
63 0 0         err == EINTR ||
64             #endif
65             #ifdef EAGAIN
66 0 0         err == EAGAIN ||
67             #endif
68             #ifdef EPROTO
69 0 0         err == EPROTO ||
70             #endif
71             #ifdef EINPROGRESS
72             err == EINPROGRESS ||
73             #endif
74             #ifdef EALREADY
75 0 0         err == EALREADY ||
76             #endif
77             0) {
78 17           return 1;
79             }
80             }
81 0           return 0;
82             }
83              
84 21           static int amqp_openssl_bio_write(BIO *b, const char *in, int inl) {
85 21           int flags = 0;
86             int fd;
87             int res;
88              
89             #ifdef MSG_NOSIGNAL
90 21           flags |= MSG_NOSIGNAL;
91             #endif
92              
93 21           BIO_get_fd(b, &fd);
94 21           res = send(fd, in, inl, flags);
95              
96 21           BIO_clear_retry_flags(b);
97 21 50         if (res <= 0 && amqp_openssl_bio_should_retry(res)) {
    0          
98 0           BIO_set_retry_write(b);
99             }
100              
101 21           return res;
102             }
103              
104 59           static int amqp_openssl_bio_read(BIO *b, char *out, int outl) {
105 59           int flags = 0;
106             int fd;
107             int res;
108              
109             #ifdef MSG_NOSIGNAL
110 59           flags |= MSG_NOSIGNAL;
111             #endif
112              
113 59           BIO_get_fd(b, &fd);
114 59           res = recv(fd, out, outl, flags);
115              
116 59           BIO_clear_retry_flags(b);
117 59 100         if (res <= 0 && amqp_openssl_bio_should_retry(res)) {
    50          
118 17           BIO_set_retry_read(b);
119             }
120              
121 59           return res;
122             }
123              
124             #ifndef AMQP_OPENSSL_V110
125 1           static int BIO_meth_set_write(BIO_METHOD *biom,
126             int (*wfn)(BIO *, const char *, int)) {
127 1           biom->bwrite = wfn;
128 1           return 0;
129             }
130              
131 1           static int BIO_meth_set_read(BIO_METHOD *biom, int (*rfn)(BIO *, char *, int)) {
132 1           biom->bread = rfn;
133 1           return 0;
134             }
135             #endif /* AQP_OPENSSL_V110 */
136             #endif /* AMQP_USE_AMQP_BIO */
137              
138 1           int amqp_openssl_bio_init(void) {
139 1 50         assert(!amqp_ssl_bio_initialized);
140             #ifdef AMQP_USE_AMQP_BIO
141             #ifdef AMQP_OPENSSL_V110
142             if (!(amqp_bio_method = BIO_meth_new(BIO_TYPE_SOCKET, "amqp_bio_method"))) {
143             return AMQP_STATUS_NO_MEMORY;
144             }
145              
146             // casting away const is necessary until
147             // https://github.com/openssl/openssl/pull/2181/, which is targeted for
148             // openssl 1.1.1
149             BIO_METHOD *meth = (BIO_METHOD *)BIO_s_socket();
150             BIO_meth_set_create(amqp_bio_method, BIO_meth_get_create(meth));
151             BIO_meth_set_destroy(amqp_bio_method, BIO_meth_get_destroy(meth));
152             BIO_meth_set_ctrl(amqp_bio_method, BIO_meth_get_ctrl(meth));
153             BIO_meth_set_callback_ctrl(amqp_bio_method, BIO_meth_get_callback_ctrl(meth));
154             BIO_meth_set_read(amqp_bio_method, BIO_meth_get_read(meth));
155             BIO_meth_set_write(amqp_bio_method, BIO_meth_get_write(meth));
156             BIO_meth_set_gets(amqp_bio_method, BIO_meth_get_gets(meth));
157             BIO_meth_set_puts(amqp_bio_method, BIO_meth_get_puts(meth));
158             #else
159 1 50         if (!(amqp_bio_method = OPENSSL_malloc(sizeof(BIO_METHOD)))) {
160 0           return AMQP_STATUS_NO_MEMORY;
161             }
162              
163 1           memcpy(amqp_bio_method, BIO_s_socket(), sizeof(BIO_METHOD));
164             #endif
165 1           BIO_meth_set_write(amqp_bio_method, amqp_openssl_bio_write);
166 1           BIO_meth_set_read(amqp_bio_method, amqp_openssl_bio_read);
167             #endif
168              
169 1           amqp_ssl_bio_initialized = 1;
170 1           return AMQP_STATUS_OK;
171             }
172              
173 0           void amqp_openssl_bio_destroy(void) {
174 0 0         assert(amqp_ssl_bio_initialized);
175             #ifdef AMQP_USE_AMQP_BIO
176             #ifdef AMQP_OPENSSL_V110
177             BIO_meth_free(amqp_bio_method);
178             #else
179 0           OPENSSL_free(amqp_bio_method);
180             #endif
181 0           amqp_bio_method = NULL;
182             #endif
183 0           amqp_ssl_bio_initialized = 0;
184 0           }
185              
186 1           BIO_METHOD_PTR amqp_openssl_bio(void) {
187 1 50         assert(amqp_ssl_bio_initialized);
188             #ifdef AMQP_USE_AMQP_BIO
189 1           return amqp_bio_method;
190             #else
191             return BIO_s_socket();
192             #endif
193             }