• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * This file is part of the openHiTLS project.
3  *
4  * openHiTLS is licensed under the Mulan PSL v2.
5  * You can use this software according to the terms and conditions of the Mulan PSL v2.
6  * You may obtain a copy of Mulan PSL v2 at:
7  *
8  *     http://license.coscl.org.cn/MulanPSL2
9  *
10  * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
11  * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
12  * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
13  * See the Mulan PSL v2 for more details.
14  */
15 
16 #include "hitls_build.h"
17 #ifdef HITLS_BSL_UIO_BUFFER
18 
19 #include "securec.h"
20 #include "bsl_sal.h"
21 #include "bsl_errno.h"
22 #include "bsl_err_internal.h"
23 #include "bsl_uio.h"
24 #include "uio_abstraction.h"
25 
26 // The write behavior must be the same.
27 #define UIO_BUFFER_DEFAULT_SIZE     4096
28 #define DTLS_MIN_MTU 256    /* Minimum MTU setting size */
29 #define DTLS_MAX_MTU_OVERHEAD 48 /* Highest MTU overhead, IPv6 40 + UDP 8 */
30 
31 typedef struct {
32     uint32_t outSize;
33     // This variable will make the write() logic consistent with the ossl. Reason:
34     // 1) The handshake logic is complex.
35     // 2) The behavior consistency problem of the handshake logic is difficult to locate.
36     uint32_t outOff;
37     uint32_t outLen;
38     uint8_t *outBuf;
39 } BufferCtx;
40 
BufferCreate(BSL_UIO * uio)41 static int32_t BufferCreate(BSL_UIO *uio)
42 {
43     if (uio == NULL) {
44         BSL_ERR_PUSH_ERROR(BSL_NULL_INPUT);
45         return BSL_NULL_INPUT;
46     }
47     BufferCtx *ctx = BSL_SAL_Calloc(1, sizeof(BufferCtx));
48     if (ctx == NULL) {
49         BSL_ERR_PUSH_ERROR(BSL_MALLOC_FAIL);
50         return BSL_MALLOC_FAIL;
51     }
52     ctx->outSize = UIO_BUFFER_DEFAULT_SIZE;
53     ctx->outBuf = (uint8_t *)BSL_SAL_Malloc(UIO_BUFFER_DEFAULT_SIZE);
54     if (ctx->outBuf == NULL) {
55         BSL_SAL_FREE(ctx);
56         BSL_ERR_PUSH_ERROR(BSL_MALLOC_FAIL);
57         return BSL_MALLOC_FAIL;
58     }
59     BSL_UIO_SetCtx(uio, ctx);
60     uio->init = 1;
61     return BSL_SUCCESS;
62 }
63 
BufferDestroy(BSL_UIO * uio)64 static int32_t BufferDestroy(BSL_UIO *uio)
65 {
66     if (uio == NULL) {
67         BSL_ERR_PUSH_ERROR(BSL_NULL_INPUT);
68         return BSL_NULL_INPUT;
69     }
70     BufferCtx *ctx = BSL_UIO_GetCtx(uio);
71     if (ctx != NULL) {
72         BSL_SAL_FREE(ctx->outBuf);
73         BSL_SAL_FREE(ctx);
74         BSL_UIO_SetCtx(uio, NULL);
75     }
76     uio->flags = 0;
77     uio->init = 0;
78     return BSL_SUCCESS;
79 }
80 
BufferFlushInternal(BSL_UIO * uio)81 static int32_t BufferFlushInternal(BSL_UIO *uio)
82 {
83     BufferCtx *ctx = BSL_UIO_GetCtx(uio);
84     if (ctx == NULL) {
85         BSL_ERR_PUSH_ERROR(BSL_NULL_INPUT);
86         return BSL_NULL_INPUT;
87     }
88     while (ctx->outLen > 0) {
89         uint32_t tmpWriteLen = 0;
90         int32_t ret = BSL_UIO_Write(uio->next, &ctx->outBuf[ctx->outOff], ctx->outLen, &tmpWriteLen);
91         if (ret != BSL_SUCCESS) {
92             uio->flags = uio->next->flags;
93             return ret;
94         }
95         if (tmpWriteLen == 0) {
96             BSL_ERR_PUSH_ERROR(BSL_UIO_IO_BUSY);
97             return BSL_UIO_IO_BUSY;
98         }
99         ctx->outOff += tmpWriteLen;
100         ctx->outLen -= tmpWriteLen;
101     }
102     ctx->outOff = 0;
103     ctx->outLen = 0;
104     return BSL_SUCCESS;
105 }
106 
BufferFlush(BSL_UIO * uio,int32_t larg,void * parg)107 static int32_t BufferFlush(BSL_UIO *uio, int32_t larg, void *parg)
108 {
109     bool invalid = (uio == NULL) || (uio->next == NULL) || (uio->ctx == NULL);
110     if (invalid) {
111         BSL_ERR_PUSH_ERROR(BSL_NULL_INPUT);
112         return BSL_NULL_INPUT;
113     }
114     BufferCtx *ctx = BSL_UIO_GetCtx(uio);
115     if (ctx->outLen == 0) { // invoke the flush of the next UIO object
116         return BSL_UIO_Ctrl(uio->next, BSL_UIO_FLUSH, larg, parg);
117     }
118     (void)BSL_UIO_ClearFlags(uio, (BSL_UIO_FLAGS_RWS | BSL_UIO_FLAGS_SHOULD_RETRY));
119     int32_t ret = BufferFlushInternal(uio);
120     if (ret != BSL_SUCCESS) {
121         BSL_ERR_PUSH_ERROR(ret);
122         return ret;
123     }
124     return BSL_UIO_Ctrl(uio->next, BSL_UIO_FLUSH, larg, parg);
125 }
126 
BufferReset(BSL_UIO * uio)127 static int32_t BufferReset(BSL_UIO *uio)
128 {
129     if (uio == NULL || uio->ctx == NULL) {
130         BSL_ERR_PUSH_ERROR(BSL_NULL_INPUT);
131         return BSL_NULL_INPUT;
132     }
133     BufferCtx *ctx = uio->ctx;
134     ctx->outLen = 0;
135     ctx->outOff = 0;
136 
137     if (uio->next == NULL) {
138         BSL_ERR_PUSH_ERROR(BSL_NULL_INPUT);
139         return BSL_NULL_INPUT;
140     }
141     return BSL_UIO_Ctrl(uio->next, BSL_UIO_RESET, 0, NULL);
142 }
143 
BufferSetBufferSize(BSL_UIO * uio,int32_t larg,void * parg)144 static int32_t BufferSetBufferSize(BSL_UIO *uio, int32_t larg, void *parg)
145 {
146     if (larg != (int32_t)sizeof(uint32_t) || parg == NULL || *(uint32_t *)parg < DTLS_MIN_MTU - DTLS_MAX_MTU_OVERHEAD) {
147         BSL_ERR_PUSH_ERROR(BSL_INVALID_ARG);
148         return BSL_INVALID_ARG;
149     }
150     BufferCtx *ctx = BSL_UIO_GetCtx(uio);
151     if (ctx == NULL) {
152         BSL_ERR_PUSH_ERROR(BSL_NULL_INPUT);
153         return BSL_NULL_INPUT;
154     }
155     uint32_t len = *(uint32_t *)parg;
156     BSL_SAL_FREE(ctx->outBuf);
157     ctx->outBuf = (uint8_t *)BSL_SAL_Malloc(len);
158     if (ctx->outBuf == NULL) {
159         BSL_ERR_PUSH_ERROR(BSL_MALLOC_FAIL);
160         return BSL_MALLOC_FAIL;
161     }
162     ctx->outSize = len;
163     return BSL_SUCCESS;
164 }
165 
BufferCtrl(BSL_UIO * uio,int32_t cmd,int32_t larg,void * parg)166 static int32_t BufferCtrl(BSL_UIO *uio, int32_t cmd, int32_t larg, void *parg)
167 {
168     switch (cmd) {
169         case BSL_UIO_FLUSH:
170             return BufferFlush(uio, larg, parg);
171         case BSL_UIO_RESET:
172             return BufferReset(uio);
173         case BSL_UIO_SET_BUFFER_SIZE:
174             return BufferSetBufferSize(uio, larg, parg);
175         default:
176             if (uio->next != NULL) {
177                 return BSL_UIO_Ctrl(uio->next, cmd, larg, parg);
178             }
179             break;
180     }
181     BSL_ERR_PUSH_ERROR(BSL_UIO_FAIL);
182     return BSL_UIO_FAIL;
183 }
184 
185 // Add data to the remaining space.
TryCompleteBuffer(BufferCtx * ctx,const void * in,uint32_t remain,uint32_t * writeLen)186 static int32_t TryCompleteBuffer(BufferCtx *ctx, const void *in, uint32_t remain, uint32_t *writeLen)
187 {
188     const uint32_t freeSpace = ctx->outSize - (ctx->outOff + ctx->outLen);
189     if (freeSpace == 0) {
190         return BSL_SUCCESS;
191     }
192     const uint32_t real = (freeSpace < remain) ? freeSpace : remain;
193     if (memcpy_s(&ctx->outBuf[ctx->outOff + ctx->outLen], freeSpace, in, real) != EOK) {
194         BSL_ERR_PUSH_ERROR(BSL_UIO_IO_EXCEPTION);
195         return BSL_UIO_IO_EXCEPTION;
196     }
197     ctx->outLen += real;
198     *writeLen += real;
199     return BSL_SUCCESS;
200 }
201 
BufferWrite(BSL_UIO * uio,const void * buf,uint32_t len,uint32_t * writeLen)202 static int32_t BufferWrite(BSL_UIO *uio, const void *buf, uint32_t len, uint32_t *writeLen)
203 {
204     bool invalid = (uio == NULL) || (buf == NULL) || (writeLen == NULL) || (uio->next == NULL);
205     if (invalid) {
206         BSL_ERR_PUSH_ERROR(BSL_NULL_INPUT);
207         return BSL_NULL_INPUT;
208     }
209     *writeLen = 0;
210     BufferCtx *ctx = BSL_UIO_GetCtx(uio);
211     invalid = (ctx == NULL) || (ctx->outBuf == NULL);
212     if (invalid) {
213         BSL_ERR_PUSH_ERROR(BSL_NULL_INPUT);
214         return BSL_NULL_INPUT;
215     }
216     (void)BSL_UIO_ClearFlags(uio, (BSL_UIO_FLAGS_RWS | BSL_UIO_FLAGS_SHOULD_RETRY));
217     const uint8_t *in = buf;
218     uint32_t remain = len;
219     while (remain > 0) {
220         const uint32_t freeSpace = ctx->outSize - (ctx->outOff + ctx->outLen);
221         if (freeSpace >= remain) { // If the space is sufficient, cache the data.
222             return TryCompleteBuffer(ctx, in, remain, writeLen);
223         }
224         // else: space is insufficient
225         if (ctx->outLen > 0) {  // buffer already has data, need to send the existing data first.
226             int32_t ret = BufferFlushInternal(uio);
227             if (ret != BSL_SUCCESS) {
228                 return ret;
229             }
230         }
231         ctx->outOff = 0;
232         while (remain >= ctx->outSize) {
233             uint32_t tmpWriteLen = 0;
234             int32_t ret = BSL_UIO_Write(uio->next, in, remain, &tmpWriteLen);
235             if (ret != BSL_SUCCESS) {
236                 uio->flags = uio->next->flags;
237                 return ret;
238             }
239             *writeLen += tmpWriteLen;
240             in = &in[tmpWriteLen];
241             remain -= tmpWriteLen;
242         }
243     }
244     return BSL_SUCCESS;
245 }
246 
BSL_UIO_BufferMethod(void)247 const BSL_UIO_Method *BSL_UIO_BufferMethod(void)
248 {
249     static const BSL_UIO_Method m = {
250         BSL_UIO_BUFFER,
251         BufferWrite,
252         NULL,
253         BufferCtrl,
254         NULL,
255         NULL,
256         BufferCreate,
257         BufferDestroy,
258     };
259     return &m;
260 }
261 #endif /* HITLS_BSL_UIO_BUFFER */
262