1 /* 2 * Copyright 2016-2020 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 /* This must be the first #include file */ 11 #include "async_local.h" 12 13 #include <openssl/err.h> 14 15 ASYNC_WAIT_CTX *ASYNC_WAIT_CTX_new(void) 16 { 17 return OPENSSL_zalloc(sizeof(ASYNC_WAIT_CTX)); 18 } 19 20 void ASYNC_WAIT_CTX_free(ASYNC_WAIT_CTX *ctx) 21 { 22 struct fd_lookup_st *curr; 23 struct fd_lookup_st *next; 24 25 if (ctx == NULL) 26 return; 27 28 curr = ctx->fds; 29 while (curr != NULL) { 30 if (!curr->del) { 31 /* Only try and cleanup if it hasn't been marked deleted */ 32 if (curr->cleanup != NULL) 33 curr->cleanup(ctx, curr->key, curr->fd, curr->custom_data); 34 } 35 /* Always free the fd_lookup_st */ 36 next = curr->next; 37 OPENSSL_free(curr); 38 curr = next; 39 } 40 41 OPENSSL_free(ctx); 42 } 43 int ASYNC_WAIT_CTX_set_wait_fd(ASYNC_WAIT_CTX *ctx, const void *key, 44 OSSL_ASYNC_FD fd, void *custom_data, 45 void (*cleanup)(ASYNC_WAIT_CTX *, const void *, 46 OSSL_ASYNC_FD, void *)) 47 { 48 struct fd_lookup_st *fdlookup; 49 50 if ((fdlookup = OPENSSL_zalloc(sizeof(*fdlookup))) == NULL) { 51 ERR_raise(ERR_LIB_ASYNC, ERR_R_MALLOC_FAILURE); 52 return 0; 53 } 54 55 fdlookup->key = key; 56 fdlookup->fd = fd; 57 fdlookup->custom_data = custom_data; 58 fdlookup->cleanup = cleanup; 59 fdlookup->add = 1; 60 fdlookup->next = ctx->fds; 61 ctx->fds = fdlookup; 62 ctx->numadd++; 63 return 1; 64 } 65 66 int ASYNC_WAIT_CTX_get_fd(ASYNC_WAIT_CTX *ctx, const void *key, 67 OSSL_ASYNC_FD *fd, void **custom_data) 68 { 69 struct fd_lookup_st *curr; 70 71 curr = ctx->fds; 72 while (curr != NULL) { 73 if (curr->del) { 74 /* This one has been marked deleted so do nothing */ 75 curr = curr->next; 76 continue; 77 } 78 if (curr->key == key) { 79 *fd = curr->fd; 80 *custom_data = curr->custom_data; 81 return 1; 82 } 83 curr = curr->next; 84 } 85 return 0; 86 } 87 88 int ASYNC_WAIT_CTX_get_all_fds(ASYNC_WAIT_CTX *ctx, OSSL_ASYNC_FD *fd, 89 size_t *numfds) 90 { 91 struct fd_lookup_st *curr; 92 93 curr = ctx->fds; 94 *numfds = 0; 95 while (curr != NULL) { 96 if (curr->del) { 97 /* This one has been marked deleted so do nothing */ 98 curr = curr->next; 99 continue; 100 } 101 if (fd != NULL) { 102 *fd = curr->fd; 103 fd++; 104 } 105 (*numfds)++; 106 curr = curr->next; 107 } 108 return 1; 109 } 110 111 int ASYNC_WAIT_CTX_get_changed_fds(ASYNC_WAIT_CTX *ctx, OSSL_ASYNC_FD *addfd, 112 size_t *numaddfds, OSSL_ASYNC_FD *delfd, 113 size_t *numdelfds) 114 { 115 struct fd_lookup_st *curr; 116 117 *numaddfds = ctx->numadd; 118 *numdelfds = ctx->numdel; 119 if (addfd == NULL && delfd == NULL) 120 return 1; 121 122 curr = ctx->fds; 123 124 while (curr != NULL) { 125 /* We ignore fds that have been marked as both added and deleted */ 126 if (curr->del && !curr->add && (delfd != NULL)) { 127 *delfd = curr->fd; 128 delfd++; 129 } 130 if (curr->add && !curr->del && (addfd != NULL)) { 131 *addfd = curr->fd; 132 addfd++; 133 } 134 curr = curr->next; 135 } 136 137 return 1; 138 } 139 140 int ASYNC_WAIT_CTX_clear_fd(ASYNC_WAIT_CTX *ctx, const void *key) 141 { 142 struct fd_lookup_st *curr, *prev; 143 144 curr = ctx->fds; 145 prev = NULL; 146 while (curr != NULL) { 147 if (curr->del == 1) { 148 /* This one has been marked deleted already so do nothing */ 149 prev = curr; 150 curr = curr->next; 151 continue; 152 } 153 if (curr->key == key) { 154 /* If fd has just been added, remove it from the list */ 155 if (curr->add == 1) { 156 if (ctx->fds == curr) { 157 ctx->fds = curr->next; 158 } else { 159 prev->next = curr->next; 160 } 161 162 /* It is responsibility of the caller to cleanup before calling 163 * ASYNC_WAIT_CTX_clear_fd 164 */ 165 OPENSSL_free(curr); 166 ctx->numadd--; 167 return 1; 168 } 169 170 /* 171 * Mark it as deleted. We don't call cleanup if explicitly asked 172 * to clear an fd. We assume the caller is going to do that (if 173 * appropriate). 174 */ 175 curr->del = 1; 176 ctx->numdel++; 177 return 1; 178 } 179 prev = curr; 180 curr = curr->next; 181 } 182 return 0; 183 } 184 185 int ASYNC_WAIT_CTX_set_callback(ASYNC_WAIT_CTX *ctx, 186 ASYNC_callback_fn callback, 187 void *callback_arg) 188 { 189 if (ctx == NULL) 190 return 0; 191 192 ctx->callback = callback; 193 ctx->callback_arg = callback_arg; 194 return 1; 195 } 196 197 int ASYNC_WAIT_CTX_get_callback(ASYNC_WAIT_CTX *ctx, 198 ASYNC_callback_fn *callback, 199 void **callback_arg) 200 { 201 if (ctx->callback == NULL) 202 return 0; 203 204 *callback = ctx->callback; 205 *callback_arg = ctx->callback_arg; 206 return 1; 207 } 208 209 int ASYNC_WAIT_CTX_set_status(ASYNC_WAIT_CTX *ctx, int status) 210 { 211 ctx->status = status; 212 return 1; 213 } 214 215 int ASYNC_WAIT_CTX_get_status(ASYNC_WAIT_CTX *ctx) 216 { 217 return ctx->status; 218 } 219 220 void async_wait_ctx_reset_counts(ASYNC_WAIT_CTX *ctx) 221 { 222 struct fd_lookup_st *curr, *prev = NULL; 223 224 ctx->numadd = 0; 225 ctx->numdel = 0; 226 227 curr = ctx->fds; 228 229 while (curr != NULL) { 230 if (curr->del) { 231 if (prev == NULL) 232 ctx->fds = curr->next; 233 else 234 prev->next = curr->next; 235 OPENSSL_free(curr); 236 if (prev == NULL) 237 curr = ctx->fds; 238 else 239 curr = prev->next; 240 continue; 241 } 242 if (curr->add) { 243 curr->add = 0; 244 } 245 prev = curr; 246 curr = curr->next; 247 } 248 } 249