1/*
2 * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved.
3 *
4 * Licensed under the Apache License 2.0 (the "License").  You may not use
5 * this file except in compliance with the License.  You can obtain a copy
6 * in the file LICENSE in the source distribution or at
7 * https://www.openssl.org/source/license.html
8 */
9
10#include <stdio.h>
11#include <errno.h>
12#include "bio_local.h"
13#include "internal/cryptlib.h"
14#include "internal/ktls.h"
15
16#ifndef OPENSSL_NO_SOCK
17
18# include <openssl/bio.h>
19
20# ifdef WATT32
21/* Watt-32 uses same names */
22#  undef sock_write
23#  undef sock_read
24#  undef sock_puts
25#  define sock_write SockWrite
26#  define sock_read  SockRead
27#  define sock_puts  SockPuts
28# endif
29
30static int sock_write(BIO *h, const char *buf, int num);
31static int sock_read(BIO *h, char *buf, int size);
32static int sock_puts(BIO *h, const char *str);
33static long sock_ctrl(BIO *h, int cmd, long arg1, void *arg2);
34static int sock_new(BIO *h);
35static int sock_free(BIO *data);
36int BIO_sock_should_retry(int s);
37
38static const BIO_METHOD methods_sockp = {
39    BIO_TYPE_SOCKET,
40    "socket",
41    bwrite_conv,
42    sock_write,
43    bread_conv,
44    sock_read,
45    sock_puts,
46    NULL,                       /* sock_gets,         */
47    sock_ctrl,
48    sock_new,
49    sock_free,
50    NULL,                       /* sock_callback_ctrl */
51};
52
53const BIO_METHOD *BIO_s_socket(void)
54{
55    return &methods_sockp;
56}
57
58BIO *BIO_new_socket(int fd, int close_flag)
59{
60    BIO *ret;
61
62    ret = BIO_new(BIO_s_socket());
63    if (ret == NULL)
64        return NULL;
65    BIO_set_fd(ret, fd, close_flag);
66# ifndef OPENSSL_NO_KTLS
67    {
68        /*
69         * The new socket is created successfully regardless of ktls_enable.
70         * ktls_enable doesn't change any functionality of the socket, except
71         * changing the setsockopt to enable the processing of ktls_start.
72         * Thus, it is not a problem to call it for non-TLS sockets.
73         */
74        ktls_enable(fd);
75    }
76# endif
77    return ret;
78}
79
80static int sock_new(BIO *bi)
81{
82    bi->init = 0;
83    bi->num = 0;
84    bi->ptr = NULL;
85    bi->flags = 0;
86    return 1;
87}
88
89static int sock_free(BIO *a)
90{
91    if (a == NULL)
92        return 0;
93    if (a->shutdown) {
94        if (a->init) {
95            BIO_closesocket(a->num);
96        }
97        a->init = 0;
98        a->flags = 0;
99    }
100    return 1;
101}
102
103static int sock_read(BIO *b, char *out, int outl)
104{
105    int ret = 0;
106
107    if (out != NULL) {
108        clear_socket_error();
109# ifndef OPENSSL_NO_KTLS
110        if (BIO_get_ktls_recv(b))
111            ret = ktls_read_record(b->num, out, outl);
112        else
113# endif
114            ret = readsocket(b->num, out, outl);
115        BIO_clear_retry_flags(b);
116        if (ret <= 0) {
117            if (BIO_sock_should_retry(ret))
118                BIO_set_retry_read(b);
119            else if (ret == 0)
120                b->flags |= BIO_FLAGS_IN_EOF;
121        }
122    }
123    return ret;
124}
125
126static int sock_write(BIO *b, const char *in, int inl)
127{
128    int ret = 0;
129
130    clear_socket_error();
131# ifndef OPENSSL_NO_KTLS
132    if (BIO_should_ktls_ctrl_msg_flag(b)) {
133        unsigned char record_type = (intptr_t)b->ptr;
134        ret = ktls_send_ctrl_message(b->num, record_type, in, inl);
135        if (ret >= 0) {
136            ret = inl;
137            BIO_clear_ktls_ctrl_msg_flag(b);
138        }
139    } else
140# endif
141        ret = writesocket(b->num, in, inl);
142    BIO_clear_retry_flags(b);
143    if (ret <= 0) {
144        if (BIO_sock_should_retry(ret))
145            BIO_set_retry_write(b);
146    }
147    return ret;
148}
149
150static long sock_ctrl(BIO *b, int cmd, long num, void *ptr)
151{
152    long ret = 1;
153    int *ip;
154# ifndef OPENSSL_NO_KTLS
155    ktls_crypto_info_t *crypto_info;
156# endif
157
158    switch (cmd) {
159    case BIO_C_SET_FD:
160        sock_free(b);
161        b->num = *((int *)ptr);
162        b->shutdown = (int)num;
163        b->init = 1;
164        break;
165    case BIO_C_GET_FD:
166        if (b->init) {
167            ip = (int *)ptr;
168            if (ip != NULL)
169                *ip = b->num;
170            ret = b->num;
171        } else
172            ret = -1;
173        break;
174    case BIO_CTRL_GET_CLOSE:
175        ret = b->shutdown;
176        break;
177    case BIO_CTRL_SET_CLOSE:
178        b->shutdown = (int)num;
179        break;
180    case BIO_CTRL_DUP:
181    case BIO_CTRL_FLUSH:
182        ret = 1;
183        break;
184# ifndef OPENSSL_NO_KTLS
185    case BIO_CTRL_SET_KTLS:
186        crypto_info = (ktls_crypto_info_t *)ptr;
187        ret = ktls_start(b->num, crypto_info, num);
188        if (ret)
189            BIO_set_ktls_flag(b, num);
190        break;
191    case BIO_CTRL_GET_KTLS_SEND:
192        return BIO_should_ktls_flag(b, 1) != 0;
193    case BIO_CTRL_GET_KTLS_RECV:
194        return BIO_should_ktls_flag(b, 0) != 0;
195    case BIO_CTRL_SET_KTLS_TX_SEND_CTRL_MSG:
196        BIO_set_ktls_ctrl_msg_flag(b);
197        b->ptr = (void *)num;
198        ret = 0;
199        break;
200    case BIO_CTRL_CLEAR_KTLS_TX_CTRL_MSG:
201        BIO_clear_ktls_ctrl_msg_flag(b);
202        ret = 0;
203        break;
204# endif
205    case BIO_CTRL_EOF:
206        ret = (b->flags & BIO_FLAGS_IN_EOF) != 0;
207        break;
208    default:
209        ret = 0;
210        break;
211    }
212    return ret;
213}
214
215static int sock_puts(BIO *bp, const char *str)
216{
217    int n, ret;
218
219    n = strlen(str);
220    ret = sock_write(bp, str, n);
221    return ret;
222}
223
224int BIO_sock_should_retry(int i)
225{
226    int err;
227
228    if ((i == 0) || (i == -1)) {
229        err = get_last_socket_error();
230
231        return BIO_sock_non_fatal_error(err);
232    }
233    return 0;
234}
235
236int BIO_sock_non_fatal_error(int err)
237{
238    switch (err) {
239# if defined(OPENSSL_SYS_WINDOWS)
240#  if defined(WSAEWOULDBLOCK)
241    case WSAEWOULDBLOCK:
242#  endif
243# endif
244
245# ifdef EWOULDBLOCK
246#  ifdef WSAEWOULDBLOCK
247#   if WSAEWOULDBLOCK != EWOULDBLOCK
248    case EWOULDBLOCK:
249#   endif
250#  else
251    case EWOULDBLOCK:
252#  endif
253# endif
254
255# if defined(ENOTCONN)
256    case ENOTCONN:
257# endif
258
259# ifdef EINTR
260    case EINTR:
261# endif
262
263# ifdef EAGAIN
264#  if EWOULDBLOCK != EAGAIN
265    case EAGAIN:
266#  endif
267# endif
268
269# ifdef EPROTO
270    case EPROTO:
271# endif
272
273# ifdef EINPROGRESS
274    case EINPROGRESS:
275# endif
276
277# ifdef EALREADY
278    case EALREADY:
279# endif
280        return 1;
281    default:
282        break;
283    }
284    return 0;
285}
286
287#endif                          /* #ifndef OPENSSL_NO_SOCK */
288