Coverage Report

Created: 2025-07-23 06:27

/src/libwebsockets/lib/tls/openssl/openssl-ssl.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * libwebsockets - small server side websockets and web server implementation
3
 *
4
 * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
5
 *
6
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7
 * of this software and associated documentation files (the "Software"), to
8
 * deal in the Software without restriction, including without limitation the
9
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10
 * sell copies of the Software, and to permit persons to whom the Software is
11
 * furnished to do so, subject to the following conditions:
12
 *
13
 * The above copyright notice and this permission notice shall be included in
14
 * all copies or substantial portions of the Software.
15
 *
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22
 * IN THE SOFTWARE.
23
 */
24
25
#include "private-lib-core.h"
26
#include "private-lib-tls-openssl.h"
27
28
int openssl_websocket_private_data_index,
29
     openssl_SSL_CTX_private_data_index;
30
31
/*
32
 * Care: many openssl apis return 1 for success.  These are translated to the
33
 * lws convention of 0 for success.
34
 */
35
36
int lws_openssl_describe_cipher(struct lws *wsi)
37
0
{
38
0
#if !defined(LWS_WITH_NO_LOGS) && !defined(USE_WOLFSSL)
39
0
  int np = -1;
40
0
  SSL *s = wsi->tls.ssl;
41
42
0
  SSL_get_cipher_bits(s, &np);
43
0
  lwsl_info("%s: %s: %s, %s, %d bits, %s\n", __func__, lws_wsi_tag(wsi),
44
0
      SSL_get_cipher_name(s), SSL_get_cipher(s), np,
45
0
      SSL_get_cipher_version(s));
46
0
#endif
47
48
0
  return 0;
49
0
}
50
51
int lws_ssl_get_error(struct lws *wsi, int n)
52
0
{
53
0
  int m;
54
0
  unsigned long l;
55
0
  char buf[160];
56
57
0
  if (!wsi->tls.ssl)
58
0
    return 99;
59
60
0
  m = SSL_get_error(wsi->tls.ssl, n);
61
0
       lwsl_debug("%s: %p %d -> %d (errno %d)\n", __func__, wsi->tls.ssl, n, m, LWS_ERRNO);
62
0
  if (m == SSL_ERROR_SSL) {
63
0
    if (!wsi->tls.err_helper[0]) {
64
      /* Append first error for clarity */
65
0
      l = ERR_get_error();
66
0
      if (l) {
67
0
        ERR_error_string_n(
68
#if defined(LWS_WITH_BORINGSSL) || defined(LWS_WITH_AWSLC)
69
          (uint32_t)
70
#endif
71
0
          l, buf, sizeof(buf) - 1);
72
0
        buf[sizeof(buf) - 1] = '\0';
73
0
        lws_strncpy(wsi->tls.err_helper, buf,
74
0
              sizeof(wsi->tls.err_helper));
75
0
      }
76
0
    }
77
78
    // Describe other errors
79
0
    lws_tls_err_describe_clear();
80
0
  }
81
82
       // assert (LWS_ERRNO != 9);
83
84
0
  return m;
85
0
}
86
87
#if defined(LWS_WITH_SERVER)
88
static int
89
lws_context_init_ssl_pem_passwd_cb(char *buf, int size, int rwflag,
90
           void *userdata)
91
0
{
92
0
  struct lws_context_creation_info * info =
93
0
      (struct lws_context_creation_info *)userdata;
94
95
0
  strncpy(buf, info->ssl_private_key_password, (unsigned int)size);
96
0
  buf[size - 1] = '\0';
97
98
0
  return (int)strlen(buf);
99
0
}
100
#endif
101
102
#if defined(LWS_WITH_CLIENT)
103
static int
104
lws_context_init_ssl_pem_passwd_client_cb(char *buf, int size, int rwflag,
105
            void *userdata)
106
0
{
107
0
  struct lws_context_creation_info * info =
108
0
      (struct lws_context_creation_info *)userdata;
109
0
  const char *p = info->ssl_private_key_password;
110
111
0
  if (info->client_ssl_private_key_password)
112
0
    p = info->client_ssl_private_key_password;
113
114
0
  strncpy(buf, p, (unsigned int)size);
115
0
  buf[size - 1] = '\0';
116
117
0
  return (int)strlen(buf);
118
0
}
119
#endif
120
121
void
122
lws_ssl_bind_passphrase(SSL_CTX *ssl_ctx, int is_client,
123
      const struct lws_context_creation_info *info)
124
0
{
125
0
  if (
126
0
#if defined(LWS_WITH_SERVER)
127
0
    !info->ssl_private_key_password
128
0
#endif
129
0
#if defined(LWS_WITH_SERVER) && defined(LWS_WITH_CLIENT)
130
0
      &&
131
0
#endif
132
0
#if defined(LWS_WITH_CLIENT)
133
0
      !info->client_ssl_private_key_password
134
0
#endif
135
0
      )
136
0
    return;
137
  /*
138
   * password provided, set ssl callback and user data
139
   * for checking password which will be trigered during
140
   * SSL_CTX_use_PrivateKey_file function
141
   */
142
0
  SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, (void *)info);
143
0
  SSL_CTX_set_default_passwd_cb(ssl_ctx, is_client ?
144
0
#if defined(LWS_WITH_CLIENT)
145
0
              lws_context_init_ssl_pem_passwd_client_cb:
146
#else
147
          NULL:
148
#endif
149
0
#if defined(LWS_WITH_SERVER)
150
0
              lws_context_init_ssl_pem_passwd_cb
151
#else
152
                NULL
153
#endif
154
0
          );
155
0
}
156
157
#if defined(LWS_WITH_CLIENT)
158
static void
159
lws_ssl_destroy_client_ctx(struct lws_vhost *vhost)
160
0
{
161
0
  if (vhost->tls.user_supplied_ssl_ctx || !vhost->tls.ssl_client_ctx)
162
0
    return;
163
164
0
  if (vhost->tls.tcr && --vhost->tls.tcr->refcount)
165
0
    return;
166
167
0
  SSL_CTX_free(vhost->tls.ssl_client_ctx);
168
0
  vhost->tls.ssl_client_ctx = NULL;
169
170
0
  vhost->context->tls.count_client_contexts--;
171
172
0
  if (vhost->tls.tcr) {
173
0
    lws_dll2_remove(&vhost->tls.tcr->cc_list);
174
0
    lws_free(vhost->tls.tcr);
175
0
    vhost->tls.tcr = NULL;
176
0
  }
177
0
}
178
#endif
179
void
180
lws_ssl_destroy(struct lws_vhost *vhost)
181
0
{
182
0
  if (!lws_check_opt(vhost->context->options,
183
0
         LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT))
184
0
    return;
185
186
0
  if (vhost->tls.ssl_ctx)
187
0
    SSL_CTX_free(vhost->tls.ssl_ctx);
188
0
#if defined(LWS_WITH_CLIENT)
189
0
  lws_ssl_destroy_client_ctx(vhost);
190
0
#endif
191
192
// after 1.1.0 no need
193
#if (OPENSSL_VERSION_NUMBER <  0x10100000)
194
// <= 1.0.1f = old api, 1.0.1g+ = new api
195
#if (OPENSSL_VERSION_NUMBER <= 0x1000106f) || defined(USE_WOLFSSL)
196
  ERR_remove_state(0);
197
#else
198
#if OPENSSL_VERSION_NUMBER >= 0x1010005f && \
199
    !defined(LIBRESSL_VERSION_NUMBER) && \
200
    !defined(OPENSSL_IS_BORINGSSL) && \
201
  !defined(OPENSSL_IS_AWSLC)
202
  ERR_remove_thread_state();
203
#else
204
  ERR_remove_thread_state(NULL);
205
#endif
206
#endif
207
  /* not needed after 1.1.0 */
208
#if  (OPENSSL_VERSION_NUMBER >= 0x10002000) && \
209
     (OPENSSL_VERSION_NUMBER <= 0x10100000)
210
  SSL_COMP_free_compression_methods();
211
#endif
212
  ERR_free_strings();
213
  EVP_cleanup();
214
  CRYPTO_cleanup_all_ex_data();
215
#endif
216
0
}
217
218
int
219
lws_ssl_capable_read(struct lws *wsi, unsigned char *buf, size_t len)
220
0
{
221
0
  struct lws_context *context = wsi->a.context;
222
0
  struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
223
0
  int n = 0, m;
224
225
0
  if (!wsi->tls.ssl)
226
0
    return lws_ssl_capable_read_no_ssl(wsi, buf, len);
227
228
0
#ifndef WIN32
229
0
  errno = 0;
230
#else
231
  WSASetLastError(0);
232
#endif
233
0
  ERR_clear_error();
234
0
  n = SSL_read(wsi->tls.ssl, buf, (int)(ssize_t)len);
235
#if defined(LWS_PLAT_FREERTOS)
236
  if (!n && errno == LWS_ENOTCONN) {
237
    lwsl_debug("%s: SSL_read ENOTCONN\n", lws_wsi_tag(wsi));
238
    return LWS_SSL_CAPABLE_ERROR;
239
  }
240
#endif
241
242
0
  lwsl_debug("%s: SSL_read says %d\n", lws_wsi_tag(wsi), n);
243
  /* manpage: returning 0 means connection shut down
244
   *
245
   * 2018-09-10: https://github.com/openssl/openssl/issues/1903
246
   *
247
   * So, in summary, if you get a 0 or -1 return from SSL_read() /
248
   * SSL_write(), you should call SSL_get_error():
249
   *
250
   *  - If you get back SSL_ERROR_RETURN_ZERO then you know the connection
251
   *    has been cleanly shutdown by the peer. To fully close the
252
   *    connection you may choose to call SSL_shutdown() to send a
253
   *    close_notify back.
254
   *
255
   *  - If you get back SSL_ERROR_SSL then some kind of internal or
256
   *    protocol error has occurred. More details will be on the SSL error
257
   *    queue. You can also call SSL_get_shutdown(). If this indicates a
258
   *    state of SSL_RECEIVED_SHUTDOWN then you know a fatal alert has
259
   *    been received from the peer (if it had been a close_notify then
260
   *    SSL_get_error() would have returned SSL_ERROR_RETURN_ZERO).
261
   *    SSL_ERROR_SSL is considered fatal - you should not call
262
   *    SSL_shutdown() in this case.
263
   *
264
   *  - If you get back SSL_ERROR_SYSCALL then some kind of fatal (i.e.
265
   *    non-retryable) error has occurred in a system call.
266
   */
267
0
  if (n <= 0) {
268
0
    m = lws_ssl_get_error(wsi, n);
269
0
               lwsl_debug("%s: ssl err %d errno %d\n", lws_wsi_tag(wsi), m, LWS_ERRNO);
270
0
    if (m == SSL_ERROR_ZERO_RETURN) /* cleanly shut down */
271
0
      goto do_err;
272
273
0
    if (m == SSL_ERROR_SSL)
274
0
        lws_tls_err_describe_clear();
275
276
    /* hm not retryable.. could be 0 size pkt or error  */
277
278
0
    if (m == SSL_ERROR_SSL || m == SSL_ERROR_SYSCALL ||
279
0
        LWS_ERRNO == LWS_ENOTCONN) {
280
281
      /* unclean, eg closed conn */
282
283
0
      wsi->socket_is_permanently_unusable = 1;
284
0
do_err:
285
#if defined(LWS_WITH_SYS_METRICS)
286
    if (wsi->a.vhost)
287
      lws_metric_event(wsi->a.vhost->mt_traffic_rx,
288
           METRES_NOGO, 0);
289
#endif
290
0
      return LWS_SSL_CAPABLE_ERROR;
291
0
    }
292
293
    /* retryable? */
294
295
0
    if (SSL_want_read(wsi->tls.ssl)) {
296
0
      lwsl_debug("%s: WANT_READ\n", __func__);
297
0
      lwsl_debug("%s: LWS_SSL_CAPABLE_MORE_SERVICE\n", lws_wsi_tag(wsi));
298
0
      return LWS_SSL_CAPABLE_MORE_SERVICE;
299
0
    }
300
0
    if (SSL_want_write(wsi->tls.ssl)) {
301
0
      lwsl_info("%s: WANT_WRITE\n", __func__);
302
0
      lwsl_debug("%s: LWS_SSL_CAPABLE_MORE_SERVICE\n", lws_wsi_tag(wsi));
303
0
      wsi->tls_read_wanted_write = 1;
304
0
      lws_callback_on_writable(wsi);
305
0
      return LWS_SSL_CAPABLE_MORE_SERVICE;
306
0
    }
307
308
    /* keep on trucking it seems */
309
0
  }
310
311
#if defined(LWS_TLS_LOG_PLAINTEXT_RX)
312
  /*
313
   * If using openssl type tls library, this is the earliest point for all
314
   * paths to dump what was received as decrypted data from the tls tunnel
315
   */
316
  lwsl_notice("%s: len %d\n", __func__, n);
317
  lwsl_hexdump_notice(buf, (unsigned int)n);
318
#endif
319
320
#if defined(LWS_WITH_SYS_METRICS)
321
  if (wsi->a.vhost)
322
    lws_metric_event(wsi->a.vhost->mt_traffic_rx, METRES_GO, (u_mt_t)n);
323
#endif
324
325
  /*
326
   * if it was our buffer that limited what we read,
327
   * check if SSL has additional data pending inside SSL buffers.
328
   *
329
   * Because these won't signal at the network layer with POLLIN
330
   * and if we don't realize, this data will sit there forever
331
   */
332
0
  if (n != (int)(ssize_t)len)
333
0
    goto bail;
334
0
  if (!wsi->tls.ssl)
335
0
    goto bail;
336
337
0
  if (SSL_pending(wsi->tls.ssl)) {
338
0
    if (lws_dll2_is_detached(&wsi->tls.dll_pending_tls))
339
0
      lws_dll2_add_head(&wsi->tls.dll_pending_tls,
340
0
            &pt->tls.dll_pending_tls_owner);
341
0
  } else
342
0
    __lws_ssl_remove_wsi_from_buffered_list(wsi);
343
344
0
  return n;
345
0
bail:
346
0
  lws_ssl_remove_wsi_from_buffered_list(wsi);
347
348
0
  return n;
349
0
}
350
351
int
352
lws_ssl_pending(struct lws *wsi)
353
0
{
354
0
  if (!wsi->tls.ssl)
355
0
    return 0;
356
357
0
  return SSL_pending(wsi->tls.ssl);
358
0
}
359
360
int
361
lws_ssl_capable_write(struct lws *wsi, unsigned char *buf, size_t len)
362
0
{
363
0
  int n, m;
364
365
366
#if defined(LWS_TLS_LOG_PLAINTEXT_TX)
367
  /*
368
   * If using OpenSSL type tls library, this is the last point for all
369
   * paths before sending data into the tls tunnel, where you can dump it
370
   * and see what is being sent.
371
   */
372
  lwsl_notice("%s: len %u\n", __func__, (unsigned int)len);
373
  lwsl_hexdump_notice(buf, len);
374
#endif
375
376
0
  if (!wsi->tls.ssl)
377
0
    return lws_ssl_capable_write_no_ssl(wsi, buf, len);
378
379
0
  errno = 0;
380
0
  ERR_clear_error();
381
0
  n = SSL_write(wsi->tls.ssl, buf, (int)(ssize_t)len);
382
0
  if (n > 0) {
383
#if defined(LWS_WITH_SYS_METRICS)
384
    if (wsi->a.vhost)
385
      lws_metric_event(wsi->a.vhost->mt_traffic_tx,
386
           METRES_GO, (u_mt_t)n);
387
#endif
388
0
    return n;
389
0
  }
390
391
0
  m = lws_ssl_get_error(wsi, n);
392
0
  if (m != SSL_ERROR_SYSCALL) {
393
0
    if (m == SSL_ERROR_WANT_READ || SSL_want_read(wsi->tls.ssl)) {
394
0
      lwsl_notice("%s: want read\n", __func__);
395
396
0
      return LWS_SSL_CAPABLE_MORE_SERVICE;
397
0
    }
398
399
0
    if (m == SSL_ERROR_WANT_WRITE || SSL_want_write(wsi->tls.ssl)) {
400
0
      lws_set_blocking_send(wsi);
401
402
0
      lwsl_debug("%s: want write\n", __func__);
403
404
0
      return LWS_SSL_CAPABLE_MORE_SERVICE;
405
0
    }
406
0
  }
407
408
0
  lwsl_debug("%s failed: %s\n",__func__, ERR_error_string((unsigned int)m, NULL));
409
0
  lws_tls_err_describe_clear();
410
411
0
  wsi->socket_is_permanently_unusable = 1;
412
413
#if defined(LWS_WITH_SYS_METRICS)
414
    if (wsi->a.vhost)
415
      lws_metric_event(wsi->a.vhost->mt_traffic_tx,
416
           METRES_NOGO, 0);
417
#endif
418
419
0
  return LWS_SSL_CAPABLE_ERROR;
420
0
}
421
422
void
423
lws_ssl_info_callback(const SSL *ssl, int where, int ret)
424
0
{
425
0
  struct lws *wsi;
426
0
  struct lws_context *context;
427
0
  struct lws_ssl_info si;
428
0
  int fd;
429
430
0
#ifndef USE_WOLFSSL
431
0
  context = (struct lws_context *)SSL_CTX_get_ex_data(
432
0
          SSL_get_SSL_CTX(ssl),
433
0
          openssl_SSL_CTX_private_data_index);
434
#else
435
  context = (struct lws_context *)SSL_CTX_get_ex_data(
436
          SSL_get_SSL_CTX((SSL*) ssl),
437
          openssl_SSL_CTX_private_data_index);
438
#endif
439
0
  if (!context)
440
0
    return;
441
442
0
  fd = SSL_get_fd(ssl);
443
0
  if (fd < 0 || (fd - lws_plat_socket_offset()) < 0)
444
0
    return;
445
446
0
  wsi = wsi_from_fd(context, fd);
447
0
  if (!wsi)
448
0
    return;
449
450
0
  if (!(where & wsi->a.vhost->tls.ssl_info_event_mask))
451
0
    return;
452
453
0
  si.where = where;
454
0
  si.ret = ret;
455
456
0
  if (user_callback_handle_rxflow(wsi->a.protocol->callback,
457
0
          wsi, LWS_CALLBACK_SSL_INFO,
458
0
          wsi->user_space, &si, 0))
459
0
    lws_set_timeout(wsi, PENDING_TIMEOUT_KILLED_BY_SSL_INFO, -1);
460
0
}
461
462
463
int
464
lws_ssl_close(struct lws *wsi)
465
0
{
466
0
  lws_sockfd_type n;
467
468
0
  if (!wsi->tls.ssl)
469
0
    return 0; /* not handled */
470
471
0
#if defined (LWS_HAVE_SSL_SET_INFO_CALLBACK)
472
  /* kill ssl callbacks, because we will remove the fd from the
473
   * table linking it to the wsi
474
   */
475
0
  if (wsi->a.vhost->tls.ssl_info_event_mask)
476
0
    SSL_set_info_callback(wsi->tls.ssl, NULL);
477
0
#endif
478
479
#if defined(LWS_TLS_SYNTHESIZE_CB)
480
  lws_sul_cancel(&wsi->tls.sul_cb_synth);
481
  /*
482
   * ... check the session in case it did not live long enough to get
483
   * the scheduled callback to sample it
484
   */
485
  lws_sess_cache_synth_cb(&wsi->tls.sul_cb_synth);
486
#endif
487
488
0
  n = SSL_get_fd(wsi->tls.ssl);
489
0
  if (!wsi->socket_is_permanently_unusable)
490
0
    SSL_shutdown(wsi->tls.ssl);
491
0
  compatible_close(n);
492
0
  SSL_free(wsi->tls.ssl);
493
0
  wsi->tls.ssl = NULL;
494
495
0
  lws_tls_restrict_return(wsi);
496
497
  // lwsl_notice("%s: ssl restr %d, simul %d\n", __func__,
498
  //    wsi->a.context->simultaneous_ssl_restriction,
499
  //    wsi->a.context->simultaneous_ssl);
500
501
0
  return 1; /* handled */
502
0
}
503
504
void
505
lws_ssl_SSL_CTX_destroy(struct lws_vhost *vhost)
506
0
{
507
0
  if (vhost->tls.ssl_ctx)
508
0
    SSL_CTX_free(vhost->tls.ssl_ctx);
509
510
0
#if defined(LWS_WITH_CLIENT)
511
0
  lws_ssl_destroy_client_ctx(vhost);
512
0
#endif
513
514
#if defined(LWS_WITH_ACME)
515
  lws_tls_acme_sni_cert_destroy(vhost);
516
#endif
517
0
}
518
519
void
520
lws_ssl_context_destroy(struct lws_context *context)
521
0
{
522
// after 1.1.0 no need
523
#if (OPENSSL_VERSION_NUMBER <  0x10100000)
524
// <= 1.0.1f = old api, 1.0.1g+ = new api
525
#if (OPENSSL_VERSION_NUMBER <= 0x1000106f) || defined(USE_WOLFSSL)
526
  ERR_remove_state(0);
527
#else
528
#if OPENSSL_VERSION_NUMBER >= 0x1010005f && \
529
    !defined(LIBRESSL_VERSION_NUMBER) && \
530
    !defined(OPENSSL_IS_BORINGSSL) && \
531
  !defined(OPENSSL_IS_AWSLC)
532
  ERR_remove_thread_state();
533
#else
534
  ERR_remove_thread_state(NULL);
535
#endif
536
#endif
537
  // after 1.1.0 no need
538
#if  (OPENSSL_VERSION_NUMBER >= 0x10002000) && (OPENSSL_VERSION_NUMBER <= 0x10100000)
539
  SSL_COMP_free_compression_methods();
540
#endif
541
  ERR_free_strings();
542
  EVP_cleanup();
543
  CRYPTO_cleanup_all_ex_data();
544
#endif
545
0
}
546
547
lws_tls_ctx *
548
lws_tls_ctx_from_wsi(struct lws *wsi)
549
0
{
550
0
  if (!wsi->tls.ssl)
551
0
    return NULL;
552
553
0
  return SSL_get_SSL_CTX(wsi->tls.ssl);
554
0
}
555
556
enum lws_ssl_capable_status
557
__lws_tls_shutdown(struct lws *wsi)
558
0
{
559
0
  int n;
560
561
0
#ifndef WIN32
562
0
  errno = 0;
563
#else
564
  WSASetLastError(0);
565
#endif
566
0
  ERR_clear_error();
567
0
  n = SSL_shutdown(wsi->tls.ssl);
568
0
  lwsl_debug("SSL_shutdown=%d for fd %d\n", n, wsi->desc.sockfd);
569
0
  switch (n) {
570
0
  case 1: /* successful completion */
571
0
    n = shutdown(wsi->desc.sockfd, SHUT_WR);
572
0
    return LWS_SSL_CAPABLE_DONE;
573
574
0
  case 0: /* needs a retry */
575
0
    __lws_change_pollfd(wsi, 0, LWS_POLLIN);
576
0
    return LWS_SSL_CAPABLE_MORE_SERVICE;
577
578
0
  default: /* fatal error, or WANT */
579
0
    n = SSL_get_error(wsi->tls.ssl, n);
580
0
    if (n != SSL_ERROR_SYSCALL && n != SSL_ERROR_SSL) {
581
0
      if (SSL_want_read(wsi->tls.ssl)) {
582
0
        lwsl_debug("(wants read)\n");
583
0
        __lws_change_pollfd(wsi, 0, LWS_POLLIN);
584
0
        return LWS_SSL_CAPABLE_MORE_SERVICE_READ;
585
0
      }
586
0
      if (SSL_want_write(wsi->tls.ssl)) {
587
0
        lwsl_debug("(wants write)\n");
588
0
        __lws_change_pollfd(wsi, 0, LWS_POLLOUT);
589
0
        return LWS_SSL_CAPABLE_MORE_SERVICE_WRITE;
590
0
      }
591
0
    }
592
0
    return LWS_SSL_CAPABLE_ERROR;
593
0
  }
594
0
}
595
596
597
static int
598
tops_fake_POLLIN_for_buffered_openssl(struct lws_context_per_thread *pt)
599
0
{
600
0
  return lws_tls_fake_POLLIN_for_buffered(pt);
601
0
}
602
603
const struct lws_tls_ops tls_ops_openssl = {
604
  /* fake_POLLIN_for_buffered */  tops_fake_POLLIN_for_buffered_openssl,
605
};