Project homepage Mailing List  Warmcat.com  API Docs  Github Mirror 
{"schema":"libjg2-1", "vpath":"/git/", "avatar":"/git/avatar/", "alang":"", "gen_ut":1713528575, "reponame":"libwebsockets", "desc":"libwebsockets lightweight C networking library", "owner": { "name": "Andy Green", "email": "andy@warmcat.com", "md5": "c50933ca2aa61e0fe2c43d46bb6b59cb" },"url":"https://libwebsockets.org/repo/libwebsockets", "f":3, "items": [ {"schema":"libjg2-1", "cid":"8acb17ac7ee6bc80baebb5f376183640", "oid":{ "oid": "f28a45246e7ea479718ddba5e80deb355b23f5f3", "alias": [ "refs/heads/main"]},"blobname": "lib/tls/openssl/openssl-ssl.c", "blob": "/*\n * libwebsockets - small server side websockets and web server implementation\n *\n * Copyright (C) 2010 - 2019 Andy Green \u003candy@warmcat.com\u003e\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \u0022Software\u0022), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \u0022AS IS\u0022, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n#include \u0022private-lib-core.h\u0022\n#include \u0022private-lib-tls-openssl.h\u0022\n\nint openssl_websocket_private_data_index,\n\t openssl_SSL_CTX_private_data_index;\n\n/*\n * Care: many openssl apis return 1 for success. These are translated to the\n * lws convention of 0 for success.\n */\n\nint lws_openssl_describe_cipher(struct lws *wsi)\n{\n#if !defined(LWS_WITH_NO_LOGS) \u0026\u0026 !defined(USE_WOLFSSL)\n\tint np \u003d -1;\n\tSSL *s \u003d wsi-\u003etls.ssl;\n\n\tSSL_get_cipher_bits(s, \u0026np);\n\tlwsl_info(\u0022%s: %s: %s, %s, %d bits, %s\u005cn\u0022, __func__, lws_wsi_tag(wsi),\n\t\t\tSSL_get_cipher_name(s), SSL_get_cipher(s), np,\n\t\t\tSSL_get_cipher_version(s));\n#endif\n\n\treturn 0;\n}\n\nint lws_ssl_get_error(struct lws *wsi, int n)\n{\n\tint m;\n\n\tif (!wsi-\u003etls.ssl)\n\t\treturn 99;\n\n\tm \u003d SSL_get_error(wsi-\u003etls.ssl, n);\n lwsl_debug(\u0022%s: %p %d -\u003e %d (errno %d)\u005cn\u0022, __func__, wsi-\u003etls.ssl, n, m, LWS_ERRNO);\n\n // assert (LWS_ERRNO !\u003d 9);\n\n\treturn m;\n}\n\n#if defined(LWS_WITH_SERVER)\nstatic int\nlws_context_init_ssl_pem_passwd_cb(char *buf, int size, int rwflag,\n\t\t\t\t void *userdata)\n{\n\tstruct lws_context_creation_info * info \u003d\n\t\t\t(struct lws_context_creation_info *)userdata;\n\n\tstrncpy(buf, info-\u003essl_private_key_password, (unsigned int)size);\n\tbuf[size - 1] \u003d '\u005c0';\n\n\treturn (int)strlen(buf);\n}\n#endif\n\n#if defined(LWS_WITH_CLIENT)\nstatic int\nlws_context_init_ssl_pem_passwd_client_cb(char *buf, int size, int rwflag,\n\t\t\t\t\t void *userdata)\n{\n\tstruct lws_context_creation_info * info \u003d\n\t\t\t(struct lws_context_creation_info *)userdata;\n\tconst char *p \u003d info-\u003essl_private_key_password;\n\n\tif (info-\u003eclient_ssl_private_key_password)\n\t\tp \u003d info-\u003eclient_ssl_private_key_password;\n\n\tstrncpy(buf, p, (unsigned int)size);\n\tbuf[size - 1] \u003d '\u005c0';\n\n\treturn (int)strlen(buf);\n}\n#endif\n\nvoid\nlws_ssl_bind_passphrase(SSL_CTX *ssl_ctx, int is_client,\n\t\t\tconst struct lws_context_creation_info *info)\n{\n\tif (\n#if defined(LWS_WITH_SERVER)\n\t\t!info-\u003essl_private_key_password\n#endif\n#if defined(LWS_WITH_SERVER) \u0026\u0026 defined(LWS_WITH_CLIENT)\n\t\t\t\u0026\u0026\n#endif\n#if defined(LWS_WITH_CLIENT)\n\t !info-\u003eclient_ssl_private_key_password\n#endif\n\t )\n\t\treturn;\n\t/*\n\t * password provided, set ssl callback and user data\n\t * for checking password which will be trigered during\n\t * SSL_CTX_use_PrivateKey_file function\n\t */\n\tSSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, (void *)info);\n\tSSL_CTX_set_default_passwd_cb(ssl_ctx, is_client ?\n#if defined(LWS_WITH_CLIENT)\n\t\t\t\t lws_context_init_ssl_pem_passwd_client_cb:\n#else\n\t\t\t\t\tNULL:\n#endif\n#if defined(LWS_WITH_SERVER)\n\t\t\t\t lws_context_init_ssl_pem_passwd_cb\n#else\n\t\t\t\t \tNULL\n#endif\n\t\t\t\t );\n}\n\n#if defined(LWS_WITH_CLIENT)\nstatic void\nlws_ssl_destroy_client_ctx(struct lws_vhost *vhost)\n{\n\tif (vhost-\u003etls.user_supplied_ssl_ctx || !vhost-\u003etls.ssl_client_ctx)\n\t\treturn;\n\n\tif (vhost-\u003etls.tcr \u0026\u0026 --vhost-\u003etls.tcr-\u003erefcount)\n\t\treturn;\n\n\tSSL_CTX_free(vhost-\u003etls.ssl_client_ctx);\n\tvhost-\u003etls.ssl_client_ctx \u003d NULL;\n\n\tvhost-\u003econtext-\u003etls.count_client_contexts--;\n\n\tif (vhost-\u003etls.tcr) {\n\t\tlws_dll2_remove(\u0026vhost-\u003etls.tcr-\u003ecc_list);\n\t\tlws_free(vhost-\u003etls.tcr);\n\t\tvhost-\u003etls.tcr \u003d NULL;\n\t}\n}\n#endif\nvoid\nlws_ssl_destroy(struct lws_vhost *vhost)\n{\n\tif (!lws_check_opt(vhost-\u003econtext-\u003eoptions,\n\t\t\t LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT))\n\t\treturn;\n\n\tif (vhost-\u003etls.ssl_ctx)\n\t\tSSL_CTX_free(vhost-\u003etls.ssl_ctx);\n#if defined(LWS_WITH_CLIENT)\n\tlws_ssl_destroy_client_ctx(vhost);\n#endif\n\n// after 1.1.0 no need\n#if (OPENSSL_VERSION_NUMBER \u003c 0x10100000)\n// \u003c\u003d 1.0.1f \u003d old api, 1.0.1g+ \u003d new api\n#if (OPENSSL_VERSION_NUMBER \u003c\u003d 0x1000106f) || defined(USE_WOLFSSL)\n\tERR_remove_state(0);\n#else\n#if OPENSSL_VERSION_NUMBER \u003e\u003d 0x1010005f \u0026\u0026 \u005c\n !defined(LIBRESSL_VERSION_NUMBER) \u0026\u0026 \u005c\n !defined(OPENSSL_IS_BORINGSSL)\n\tERR_remove_thread_state();\n#else\n\tERR_remove_thread_state(NULL);\n#endif\n#endif\n\t/* not needed after 1.1.0 */\n#if (OPENSSL_VERSION_NUMBER \u003e\u003d 0x10002000) \u0026\u0026 \u005c\n (OPENSSL_VERSION_NUMBER \u003c\u003d 0x10100000)\n\tSSL_COMP_free_compression_methods();\n#endif\n\tERR_free_strings();\n\tEVP_cleanup();\n\tCRYPTO_cleanup_all_ex_data();\n#endif\n}\n\nint\nlws_ssl_capable_read(struct lws *wsi, unsigned char *buf, size_t len)\n{\n\tstruct lws_context *context \u003d wsi-\u003ea.context;\n\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[(int)wsi-\u003etsi];\n\tint n \u003d 0, m;\n\n\tif (!wsi-\u003etls.ssl)\n\t\treturn lws_ssl_capable_read_no_ssl(wsi, buf, len);\n\n#ifndef WIN32\n\terrno \u003d 0;\n#else\n WSASetLastError(0);\n#endif\n\tERR_clear_error();\n\tn \u003d SSL_read(wsi-\u003etls.ssl, buf, (int)(ssize_t)len);\n#if defined(LWS_PLAT_FREERTOS)\n\tif (!n \u0026\u0026 errno \u003d\u003d LWS_ENOTCONN) {\n\t\tlwsl_debug(\u0022%s: SSL_read ENOTCONN\u005cn\u0022, lws_wsi_tag(wsi));\n\t\treturn LWS_SSL_CAPABLE_ERROR;\n\t}\n#endif\n\n\tlwsl_debug(\u0022%s: SSL_read says %d\u005cn\u0022, lws_wsi_tag(wsi), n);\n\t/* manpage: returning 0 means connection shut down\n\t *\n\t * 2018-09-10: https://github.com/openssl/openssl/issues/1903\n\t *\n\t * So, in summary, if you get a 0 or -1 return from SSL_read() /\n\t * SSL_write(), you should call SSL_get_error():\n\t *\n\t * - If you get back SSL_ERROR_RETURN_ZERO then you know the connection\n\t * has been cleanly shutdown by the peer. To fully close the\n\t * connection you may choose to call SSL_shutdown() to send a\n\t * close_notify back.\n\t *\n\t * - If you get back SSL_ERROR_SSL then some kind of internal or\n\t * protocol error has occurred. More details will be on the SSL error\n\t * queue. You can also call SSL_get_shutdown(). If this indicates a\n\t * state of SSL_RECEIVED_SHUTDOWN then you know a fatal alert has\n\t * been received from the peer (if it had been a close_notify then\n\t * SSL_get_error() would have returned SSL_ERROR_RETURN_ZERO).\n\t * SSL_ERROR_SSL is considered fatal - you should not call\n\t * SSL_shutdown() in this case.\n\t *\n\t * - If you get back SSL_ERROR_SYSCALL then some kind of fatal (i.e.\n\t * non-retryable) error has occurred in a system call.\n\t */\n\tif (n \u003c\u003d 0) {\n\t\tm \u003d lws_ssl_get_error(wsi, n);\n lwsl_debug(\u0022%s: ssl err %d errno %d\u005cn\u0022, lws_wsi_tag(wsi), m, LWS_ERRNO);\n\t\tif (m \u003d\u003d SSL_ERROR_ZERO_RETURN) /* cleanly shut down */\n\t\t\tgoto do_err;\n\n\t\tif (m \u003d\u003d SSL_ERROR_SSL)\n\t\t lws_tls_err_describe_clear();\n\n\t\t/* hm not retryable.. could be 0 size pkt or error */\n\n\t\tif (m \u003d\u003d SSL_ERROR_SSL || m \u003d\u003d SSL_ERROR_SYSCALL ||\n LWS_ERRNO \u003d\u003d LWS_ENOTCONN) {\n\n\t\t\t/* unclean, eg closed conn */\n\n\t\t\twsi-\u003esocket_is_permanently_unusable \u003d 1;\ndo_err:\n#if defined(LWS_WITH_SYS_METRICS)\n\t\tif (wsi-\u003ea.vhost)\n\t\t\tlws_metric_event(wsi-\u003ea.vhost-\u003emt_traffic_rx,\n\t\t\t\t\t METRES_NOGO, 0);\n#endif\n\t\t\treturn LWS_SSL_CAPABLE_ERROR;\n\t\t}\n\n\t\t/* retryable? */\n\n\t\tif (SSL_want_read(wsi-\u003etls.ssl)) {\n\t\t\tlwsl_debug(\u0022%s: WANT_READ\u005cn\u0022, __func__);\n\t\t\tlwsl_debug(\u0022%s: LWS_SSL_CAPABLE_MORE_SERVICE\u005cn\u0022, lws_wsi_tag(wsi));\n\t\t\treturn LWS_SSL_CAPABLE_MORE_SERVICE;\n\t\t}\n\t\tif (SSL_want_write(wsi-\u003etls.ssl)) {\n\t\t\tlwsl_info(\u0022%s: WANT_WRITE\u005cn\u0022, __func__);\n\t\t\tlwsl_debug(\u0022%s: LWS_SSL_CAPABLE_MORE_SERVICE\u005cn\u0022, lws_wsi_tag(wsi));\n\t\t\twsi-\u003etls_read_wanted_write \u003d 1;\n\t\t\tlws_callback_on_writable(wsi);\n\t\t\treturn LWS_SSL_CAPABLE_MORE_SERVICE;\n\t\t}\n\n\t\t/* keep on trucking it seems */\n\t}\n\n#if defined(LWS_TLS_LOG_PLAINTEXT_RX)\n\t/*\n\t * If using openssl type tls library, this is the earliest point for all\n\t * paths to dump what was received as decrypted data from the tls tunnel\n\t */\n\tlwsl_notice(\u0022%s: len %d\u005cn\u0022, __func__, n);\n\tlwsl_hexdump_notice(buf, (unsigned int)n);\n#endif\n\n#if defined(LWS_WITH_SYS_METRICS)\n\tif (wsi-\u003ea.vhost)\n\t\tlws_metric_event(wsi-\u003ea.vhost-\u003emt_traffic_rx, METRES_GO, (u_mt_t)n);\n#endif\n\n\t/*\n\t * if it was our buffer that limited what we read,\n\t * check if SSL has additional data pending inside SSL buffers.\n\t *\n\t * Because these won't signal at the network layer with POLLIN\n\t * and if we don't realize, this data will sit there forever\n\t */\n\tif (n !\u003d (int)(ssize_t)len)\n\t\tgoto bail;\n\tif (!wsi-\u003etls.ssl)\n\t\tgoto bail;\n\n\tif (SSL_pending(wsi-\u003etls.ssl)) {\n\t\tif (lws_dll2_is_detached(\u0026wsi-\u003etls.dll_pending_tls))\n\t\t\tlws_dll2_add_head(\u0026wsi-\u003etls.dll_pending_tls,\n\t\t\t\t\t \u0026pt-\u003etls.dll_pending_tls_owner);\n\t} else\n\t\t__lws_ssl_remove_wsi_from_buffered_list(wsi);\n\n\treturn n;\nbail:\n\tlws_ssl_remove_wsi_from_buffered_list(wsi);\n\n\treturn n;\n}\n\nint\nlws_ssl_pending(struct lws *wsi)\n{\n\tif (!wsi-\u003etls.ssl)\n\t\treturn 0;\n\n\treturn SSL_pending(wsi-\u003etls.ssl);\n}\n\nint\nlws_ssl_capable_write(struct lws *wsi, unsigned char *buf, size_t len)\n{\n\tint n, m;\n\n\n#if defined(LWS_TLS_LOG_PLAINTEXT_TX)\n\t/*\n\t * If using OpenSSL type tls library, this is the last point for all\n\t * paths before sending data into the tls tunnel, where you can dump it\n\t * and see what is being sent.\n\t */\n\tlwsl_notice(\u0022%s: len %u\u005cn\u0022, __func__, (unsigned int)len);\n\tlwsl_hexdump_notice(buf, len);\n#endif\n\n\tif (!wsi-\u003etls.ssl)\n\t\treturn lws_ssl_capable_write_no_ssl(wsi, buf, len);\n\n\terrno \u003d 0;\n\tERR_clear_error();\n\tn \u003d SSL_write(wsi-\u003etls.ssl, buf, (int)(ssize_t)len);\n\tif (n \u003e 0) {\n#if defined(LWS_WITH_SYS_METRICS)\n\t\tif (wsi-\u003ea.vhost)\n\t\t\tlws_metric_event(wsi-\u003ea.vhost-\u003emt_traffic_tx,\n\t\t\t\t\t METRES_GO, (u_mt_t)n);\n#endif\n\t\treturn n;\n\t}\n\n\tm \u003d lws_ssl_get_error(wsi, n);\n\tif (m !\u003d SSL_ERROR_SYSCALL) {\n\t\tif (m \u003d\u003d SSL_ERROR_WANT_READ || SSL_want_read(wsi-\u003etls.ssl)) {\n\t\t\tlwsl_notice(\u0022%s: want read\u005cn\u0022, __func__);\n\n\t\t\treturn LWS_SSL_CAPABLE_MORE_SERVICE;\n\t\t}\n\n\t\tif (m \u003d\u003d SSL_ERROR_WANT_WRITE || SSL_want_write(wsi-\u003etls.ssl)) {\n\t\t\tlws_set_blocking_send(wsi);\n\n\t\t\tlwsl_debug(\u0022%s: want write\u005cn\u0022, __func__);\n\n\t\t\treturn LWS_SSL_CAPABLE_MORE_SERVICE;\n\t\t}\n\t}\n\n\tlwsl_debug(\u0022%s failed: %s\u005cn\u0022,__func__, ERR_error_string((unsigned int)m, NULL));\n\tlws_tls_err_describe_clear();\n\n\twsi-\u003esocket_is_permanently_unusable \u003d 1;\n\n#if defined(LWS_WITH_SYS_METRICS)\n\t\tif (wsi-\u003ea.vhost)\n\t\t\tlws_metric_event(wsi-\u003ea.vhost-\u003emt_traffic_tx,\n\t\t\t\t\t METRES_NOGO, 0);\n#endif\n\n\treturn LWS_SSL_CAPABLE_ERROR;\n}\n\nvoid\nlws_ssl_info_callback(const SSL *ssl, int where, int ret)\n{\n\tstruct lws *wsi;\n\tstruct lws_context *context;\n\tstruct lws_ssl_info si;\n\tint fd;\n\n#ifndef USE_WOLFSSL\n\tcontext \u003d (struct lws_context *)SSL_CTX_get_ex_data(\n\t\t\t\t\tSSL_get_SSL_CTX(ssl),\n\t\t\t\t\topenssl_SSL_CTX_private_data_index);\n#else\n\tcontext \u003d (struct lws_context *)SSL_CTX_get_ex_data(\n\t\t\t\t\tSSL_get_SSL_CTX((SSL*) ssl),\n\t\t\t\t\topenssl_SSL_CTX_private_data_index);\n#endif\n\tif (!context)\n\t\treturn;\n\n\tfd \u003d SSL_get_fd(ssl);\n\tif (fd \u003c 0 || (fd - lws_plat_socket_offset()) \u003c 0)\n\t\treturn;\n\n\twsi \u003d wsi_from_fd(context, fd);\n\tif (!wsi)\n\t\treturn;\n\n\tif (!(where \u0026 wsi-\u003ea.vhost-\u003etls.ssl_info_event_mask))\n\t\treturn;\n\n\tsi.where \u003d where;\n\tsi.ret \u003d ret;\n\n\tif (user_callback_handle_rxflow(wsi-\u003ea.protocol-\u003ecallback,\n\t\t\t\t\twsi, LWS_CALLBACK_SSL_INFO,\n\t\t\t\t\twsi-\u003euser_space, \u0026si, 0))\n\t\tlws_set_timeout(wsi, PENDING_TIMEOUT_KILLED_BY_SSL_INFO, -1);\n}\n\n\nint\nlws_ssl_close(struct lws *wsi)\n{\n\tlws_sockfd_type n;\n\n\tif (!wsi-\u003etls.ssl)\n\t\treturn 0; /* not handled */\n\n#if defined (LWS_HAVE_SSL_SET_INFO_CALLBACK)\n\t/* kill ssl callbacks, because we will remove the fd from the\n\t * table linking it to the wsi\n\t */\n\tif (wsi-\u003ea.vhost-\u003etls.ssl_info_event_mask)\n\t\tSSL_set_info_callback(wsi-\u003etls.ssl, NULL);\n#endif\n\n#if defined(LWS_TLS_SYNTHESIZE_CB)\n\tlws_sul_cancel(\u0026wsi-\u003etls.sul_cb_synth);\n\t/*\n\t * ... check the session in case it did not live long enough to get\n\t * the scheduled callback to sample it\n\t */\n\tlws_sess_cache_synth_cb(\u0026wsi-\u003etls.sul_cb_synth);\n#endif\n\n\tn \u003d SSL_get_fd(wsi-\u003etls.ssl);\n\tif (!wsi-\u003esocket_is_permanently_unusable)\n\t\tSSL_shutdown(wsi-\u003etls.ssl);\n\tcompatible_close(n);\n\tSSL_free(wsi-\u003etls.ssl);\n\twsi-\u003etls.ssl \u003d NULL;\n\n\tlws_tls_restrict_return(wsi);\n\n\t// lwsl_notice(\u0022%s: ssl restr %d, simul %d\u005cn\u0022, __func__,\n\t//\t\twsi-\u003ea.context-\u003esimultaneous_ssl_restriction,\n\t//\t\twsi-\u003ea.context-\u003esimultaneous_ssl);\n\n\treturn 1; /* handled */\n}\n\nvoid\nlws_ssl_SSL_CTX_destroy(struct lws_vhost *vhost)\n{\n\tif (vhost-\u003etls.ssl_ctx)\n\t\tSSL_CTX_free(vhost-\u003etls.ssl_ctx);\n\n#if defined(LWS_WITH_CLIENT)\n\tlws_ssl_destroy_client_ctx(vhost);\n#endif\n\n#if defined(LWS_WITH_ACME)\n\tlws_tls_acme_sni_cert_destroy(vhost);\n#endif\n}\n\nvoid\nlws_ssl_context_destroy(struct lws_context *context)\n{\n// after 1.1.0 no need\n#if (OPENSSL_VERSION_NUMBER \u003c 0x10100000)\n// \u003c\u003d 1.0.1f \u003d old api, 1.0.1g+ \u003d new api\n#if (OPENSSL_VERSION_NUMBER \u003c\u003d 0x1000106f) || defined(USE_WOLFSSL)\n\tERR_remove_state(0);\n#else\n#if OPENSSL_VERSION_NUMBER \u003e\u003d 0x1010005f \u0026\u0026 \u005c\n !defined(LIBRESSL_VERSION_NUMBER) \u0026\u0026 \u005c\n !defined(OPENSSL_IS_BORINGSSL)\n\tERR_remove_thread_state();\n#else\n\tERR_remove_thread_state(NULL);\n#endif\n#endif\n\t// after 1.1.0 no need\n#if (OPENSSL_VERSION_NUMBER \u003e\u003d 0x10002000) \u0026\u0026 (OPENSSL_VERSION_NUMBER \u003c\u003d 0x10100000)\n\tSSL_COMP_free_compression_methods();\n#endif\n\tERR_free_strings();\n\tEVP_cleanup();\n\tCRYPTO_cleanup_all_ex_data();\n#endif\n}\n\nlws_tls_ctx *\nlws_tls_ctx_from_wsi(struct lws *wsi)\n{\n\tif (!wsi-\u003etls.ssl)\n\t\treturn NULL;\n\n\treturn SSL_get_SSL_CTX(wsi-\u003etls.ssl);\n}\n\nenum lws_ssl_capable_status\n__lws_tls_shutdown(struct lws *wsi)\n{\n\tint n;\n\n#ifndef WIN32\n\terrno \u003d 0;\n#else\n WSASetLastError(0);\n#endif\n\tERR_clear_error();\n\tn \u003d SSL_shutdown(wsi-\u003etls.ssl);\n\tlwsl_debug(\u0022SSL_shutdown\u003d%d for fd %d\u005cn\u0022, n, wsi-\u003edesc.sockfd);\n\tswitch (n) {\n\tcase 1: /* successful completion */\n\t\tn \u003d shutdown(wsi-\u003edesc.sockfd, SHUT_WR);\n\t\treturn LWS_SSL_CAPABLE_DONE;\n\n\tcase 0: /* needs a retry */\n\t\t__lws_change_pollfd(wsi, 0, LWS_POLLIN);\n\t\treturn LWS_SSL_CAPABLE_MORE_SERVICE;\n\n\tdefault: /* fatal error, or WANT */\n\t\tn \u003d SSL_get_error(wsi-\u003etls.ssl, n);\n\t\tif (n !\u003d SSL_ERROR_SYSCALL \u0026\u0026 n !\u003d SSL_ERROR_SSL) {\n\t\t\tif (SSL_want_read(wsi-\u003etls.ssl)) {\n\t\t\t\tlwsl_debug(\u0022(wants read)\u005cn\u0022);\n\t\t\t\t__lws_change_pollfd(wsi, 0, LWS_POLLIN);\n\t\t\t\treturn LWS_SSL_CAPABLE_MORE_SERVICE_READ;\n\t\t\t}\n\t\t\tif (SSL_want_write(wsi-\u003etls.ssl)) {\n\t\t\t\tlwsl_debug(\u0022(wants write)\u005cn\u0022);\n\t\t\t\t__lws_change_pollfd(wsi, 0, LWS_POLLOUT);\n\t\t\t\treturn LWS_SSL_CAPABLE_MORE_SERVICE_WRITE;\n\t\t\t}\n\t\t}\n\t\treturn LWS_SSL_CAPABLE_ERROR;\n\t}\n}\n\n\nstatic int\ntops_fake_POLLIN_for_buffered_openssl(struct lws_context_per_thread *pt)\n{\n\treturn lws_tls_fake_POLLIN_for_buffered(pt);\n}\n\nconst struct lws_tls_ops tls_ops_openssl \u003d {\n\t/* fake_POLLIN_for_buffered */\ttops_fake_POLLIN_for_buffered_openssl,\n};\n","s":{"c":1713528575,"u": 603}} ],"g": 2554,"chitpc": 0,"ehitpc": 0,"indexed":0 , "ab": 1, "si": 0, "db":0, "di":0, "sat":0, "lfc": "0000"}