xref: /unit/src/nxt_cyassl.c (revision 564:762f8c976ead)
10Sigor@sysoev.ru 
20Sigor@sysoev.ru /*
30Sigor@sysoev.ru  * Copyright (C) NGINX, Inc.
40Sigor@sysoev.ru  * Copyright (C) Igor Sysoev
50Sigor@sysoev.ru  */
60Sigor@sysoev.ru 
70Sigor@sysoev.ru #include <nxt_main.h>
80Sigor@sysoev.ru #include <cyassl/ssl.h>
90Sigor@sysoev.ru #include <cyassl/error-ssl.h>
100Sigor@sysoev.ru 
110Sigor@sysoev.ru 
120Sigor@sysoev.ru typedef struct {
130Sigor@sysoev.ru     CYASSL         *session;
140Sigor@sysoev.ru 
150Sigor@sysoev.ru     int            ssl_error;
160Sigor@sysoev.ru     uint8_t        times;      /* 2 bits */
170Sigor@sysoev.ru 
180Sigor@sysoev.ru     nxt_buf_mem_t  buffer;
190Sigor@sysoev.ru } nxt_cyassl_conn_t;
200Sigor@sysoev.ru 
210Sigor@sysoev.ru 
220Sigor@sysoev.ru static nxt_int_t nxt_cyassl_server_init(nxt_ssltls_conf_t *conf);
230Sigor@sysoev.ru static void nxt_cyassl_conn_init(nxt_thread_t *thr, nxt_ssltls_conf_t *conf,
240Sigor@sysoev.ru     nxt_event_conn_t *c);
250Sigor@sysoev.ru static void nxt_cyassl_session_cleanup(void *data);
260Sigor@sysoev.ru static int nxt_cyassl_io_recv(CYASSL *ssl, char *buf, int size, void *data);
270Sigor@sysoev.ru static int nxt_cyassl_io_send(CYASSL *ssl, char *buf, int size, void *data);
280Sigor@sysoev.ru static void nxt_cyassl_conn_handshake(nxt_thread_t *thr, void *obj, void *data);
290Sigor@sysoev.ru static void nxt_cyassl_conn_io_read(nxt_thread_t *thr, void *obj, void *data);
300Sigor@sysoev.ru static void nxt_cyassl_conn_io_shutdown(nxt_thread_t *thr, void *obj,
310Sigor@sysoev.ru     void *data);
320Sigor@sysoev.ru static ssize_t nxt_cyassl_conn_io_write_chunk(nxt_thread_t *thr,
330Sigor@sysoev.ru     nxt_event_conn_t *c, nxt_buf_t *b, size_t limit);
340Sigor@sysoev.ru static ssize_t nxt_cyassl_conn_io_send(nxt_event_conn_t *c, void *buf,
350Sigor@sysoev.ru     size_t size);
360Sigor@sysoev.ru static nxt_int_t nxt_cyassl_conn_test_error(nxt_thread_t *thr,
370Sigor@sysoev.ru     nxt_event_conn_t *c, int err, nxt_work_handler_t handler);
380Sigor@sysoev.ru static void nxt_cdecl nxt_cyassl_conn_error(nxt_event_conn_t *c, nxt_err_t err,
390Sigor@sysoev.ru     const char *fmt, ...);
400Sigor@sysoev.ru static nxt_uint_t nxt_cyassl_log_error_level(nxt_event_conn_t *c, nxt_err_t err,
410Sigor@sysoev.ru     int ssl_error);
420Sigor@sysoev.ru static void nxt_cdecl nxt_cyassl_log_error(nxt_uint_t level, nxt_log_t *log,
430Sigor@sysoev.ru     int ret, const char *fmt, ...);
440Sigor@sysoev.ru static u_char *nxt_cyassl_copy_error(int err, u_char *p, u_char *end);
450Sigor@sysoev.ru 
460Sigor@sysoev.ru 
470Sigor@sysoev.ru const nxt_ssltls_lib_t  nxt_cyassl_lib = {
480Sigor@sysoev.ru     nxt_cyassl_server_init,
490Sigor@sysoev.ru     NULL,
500Sigor@sysoev.ru };
510Sigor@sysoev.ru 
520Sigor@sysoev.ru 
530Sigor@sysoev.ru static nxt_event_conn_io_t  nxt_cyassl_event_conn_io = {
540Sigor@sysoev.ru     NULL,
550Sigor@sysoev.ru     NULL,
560Sigor@sysoev.ru 
570Sigor@sysoev.ru     nxt_cyassl_conn_io_read,
580Sigor@sysoev.ru     NULL,
590Sigor@sysoev.ru     NULL,
600Sigor@sysoev.ru 
610Sigor@sysoev.ru     nxt_event_conn_io_write,
620Sigor@sysoev.ru     nxt_cyassl_conn_io_write_chunk,
630Sigor@sysoev.ru     NULL,
640Sigor@sysoev.ru     NULL,
650Sigor@sysoev.ru     nxt_cyassl_conn_io_send,
660Sigor@sysoev.ru 
670Sigor@sysoev.ru     nxt_cyassl_conn_io_shutdown,
680Sigor@sysoev.ru };
690Sigor@sysoev.ru 
700Sigor@sysoev.ru 
710Sigor@sysoev.ru static nxt_int_t
nxt_cyassl_start(void)720Sigor@sysoev.ru nxt_cyassl_start(void)
730Sigor@sysoev.ru {
740Sigor@sysoev.ru     int                err;
750Sigor@sysoev.ru     nxt_thread_t       *thr;
760Sigor@sysoev.ru     static nxt_bool_t  started;
770Sigor@sysoev.ru 
780Sigor@sysoev.ru     if (nxt_fast_path(started)) {
790Sigor@sysoev.ru         return NXT_OK;
800Sigor@sysoev.ru     }
810Sigor@sysoev.ru 
820Sigor@sysoev.ru     started = 1;
830Sigor@sysoev.ru 
840Sigor@sysoev.ru     thr = nxt_thread();
850Sigor@sysoev.ru 
860Sigor@sysoev.ru     /* TODO: CyaSSL_Cleanup() */
870Sigor@sysoev.ru 
880Sigor@sysoev.ru     err = CyaSSL_Init();
890Sigor@sysoev.ru     if (err != SSL_SUCCESS) {
90*564Svbart@nginx.com         nxt_cyassl_log_error(NXT_LOG_ALERT, thr->log, err,
910Sigor@sysoev.ru                              "CyaSSL_Init() failed");
920Sigor@sysoev.ru         return NXT_ERROR;
930Sigor@sysoev.ru     }
940Sigor@sysoev.ru 
950Sigor@sysoev.ru     nxt_thread_log_error(NXT_LOG_INFO, "CyaSSL version: %s",
960Sigor@sysoev.ru                          LIBCYASSL_VERSION_STRING);
970Sigor@sysoev.ru 
980Sigor@sysoev.ru     /* CyaSSL_SetLoggingCb */
990Sigor@sysoev.ru     /* CyaSSL_SetAllocators */
1000Sigor@sysoev.ru 
1010Sigor@sysoev.ru     return NXT_OK;
1020Sigor@sysoev.ru }
1030Sigor@sysoev.ru 
1040Sigor@sysoev.ru 
1050Sigor@sysoev.ru static nxt_int_t
nxt_cyassl_server_init(nxt_ssltls_conf_t * conf)1060Sigor@sysoev.ru nxt_cyassl_server_init(nxt_ssltls_conf_t *conf)
1070Sigor@sysoev.ru {
1080Sigor@sysoev.ru     int           err;
1090Sigor@sysoev.ru     char          *certificate, *key;
1100Sigor@sysoev.ru     CYASSL_CTX    *ctx;
1110Sigor@sysoev.ru     nxt_thread_t  *thr;
1120Sigor@sysoev.ru 
1130Sigor@sysoev.ru     thr = nxt_thread();
1140Sigor@sysoev.ru 
1150Sigor@sysoev.ru     if (nxt_slow_path(nxt_cyassl_start() != NXT_OK)) {
1160Sigor@sysoev.ru         return NXT_ERROR;
1170Sigor@sysoev.ru     }
1180Sigor@sysoev.ru 
1190Sigor@sysoev.ru     ctx = CyaSSL_CTX_new(CyaSSLv23_server_method());
1200Sigor@sysoev.ru     if (ctx == NULL) {
121*564Svbart@nginx.com         nxt_cyassl_log_error(NXT_LOG_ALERT, thr->log, 0,
1220Sigor@sysoev.ru                              "CyaSSL_CTX_new() failed");
1230Sigor@sysoev.ru         return NXT_ERROR;
1240Sigor@sysoev.ru     }
1250Sigor@sysoev.ru 
1260Sigor@sysoev.ru     conf->ctx = ctx;
1270Sigor@sysoev.ru     conf->conn_init = nxt_cyassl_conn_init;
1280Sigor@sysoev.ru 
1290Sigor@sysoev.ru     certificate = conf->certificate;
1300Sigor@sysoev.ru 
1310Sigor@sysoev.ru     err = CyaSSL_CTX_use_certificate_file(ctx, certificate, SSL_FILETYPE_PEM);
1320Sigor@sysoev.ru     if (err != SSL_SUCCESS) {
133*564Svbart@nginx.com         nxt_cyassl_log_error(NXT_LOG_ALERT, thr->log, err,
1340Sigor@sysoev.ru                              "CyaSSL_CTX_use_certificate_file(\"%s\") failed",
1350Sigor@sysoev.ru                              certificate);
1360Sigor@sysoev.ru         goto fail;
1370Sigor@sysoev.ru     }
1380Sigor@sysoev.ru 
1390Sigor@sysoev.ru     key = conf->certificate_key;
1400Sigor@sysoev.ru 
1410Sigor@sysoev.ru     err = CyaSSL_CTX_use_PrivateKey_file(ctx, key, SSL_FILETYPE_PEM);
1420Sigor@sysoev.ru     if (err != SSL_SUCCESS) {
143*564Svbart@nginx.com         nxt_cyassl_log_error(NXT_LOG_ALERT, thr->log, err,
1440Sigor@sysoev.ru                              "CyaSSL_CTX_use_PrivateKey_file(\"%s\") failed",
1450Sigor@sysoev.ru                              key);
1460Sigor@sysoev.ru         goto fail;
1470Sigor@sysoev.ru     }
1480Sigor@sysoev.ru 
1490Sigor@sysoev.ru     if (conf->ciphers != NULL) {
1500Sigor@sysoev.ru         err = CyaSSL_CTX_set_cipher_list(ctx, conf->ciphers);
1510Sigor@sysoev.ru         if (err != SSL_SUCCESS) {
152*564Svbart@nginx.com             nxt_cyassl_log_error(NXT_LOG_ALERT, thr->log, err,
1530Sigor@sysoev.ru                                  "CyaSSL_CTX_set_cipher_list(\"%s\") failed",
1540Sigor@sysoev.ru                                  conf->ciphers);
1550Sigor@sysoev.ru             goto fail;
1560Sigor@sysoev.ru         }
1570Sigor@sysoev.ru     }
1580Sigor@sysoev.ru 
1590Sigor@sysoev.ru     /* TODO: ca_certificate */
1600Sigor@sysoev.ru 
1610Sigor@sysoev.ru     CyaSSL_SetIORecv(ctx, nxt_cyassl_io_recv);
1620Sigor@sysoev.ru     CyaSSL_SetIOSend(ctx, nxt_cyassl_io_send);
1630Sigor@sysoev.ru 
1640Sigor@sysoev.ru     return NXT_OK;
1650Sigor@sysoev.ru 
1660Sigor@sysoev.ru fail:
1670Sigor@sysoev.ru 
1680Sigor@sysoev.ru     CyaSSL_CTX_free(ctx);
1690Sigor@sysoev.ru 
1700Sigor@sysoev.ru     return NXT_ERROR;
1710Sigor@sysoev.ru }
1720Sigor@sysoev.ru 
1730Sigor@sysoev.ru 
1740Sigor@sysoev.ru static void
nxt_cyassl_conn_init(nxt_thread_t * thr,nxt_ssltls_conf_t * conf,nxt_event_conn_t * c)1750Sigor@sysoev.ru nxt_cyassl_conn_init(nxt_thread_t *thr, nxt_ssltls_conf_t *conf,
1760Sigor@sysoev.ru     nxt_event_conn_t *c)
1770Sigor@sysoev.ru {
1780Sigor@sysoev.ru     CYASSL                  *s;
1790Sigor@sysoev.ru     CYASSL_CTX              *ctx;
1800Sigor@sysoev.ru     nxt_cyassl_conn_t       *ssltls;
1810Sigor@sysoev.ru     nxt_mem_pool_cleanup_t  *mpcl;
1820Sigor@sysoev.ru 
1830Sigor@sysoev.ru     nxt_log_debug(c->socket.log, "cyassl conn init");
1840Sigor@sysoev.ru 
18565Sigor@sysoev.ru     ssltls = nxt_mp_zget(c->mem_pool, sizeof(nxt_cyassl_conn_t));
1860Sigor@sysoev.ru     if (ssltls == NULL) {
1870Sigor@sysoev.ru         goto fail;
1880Sigor@sysoev.ru     }
1890Sigor@sysoev.ru 
1900Sigor@sysoev.ru     c->u.ssltls = ssltls;
1910Sigor@sysoev.ru     nxt_buf_mem_set_size(&ssltls->buffer, conf->buffer_size);
1920Sigor@sysoev.ru 
1930Sigor@sysoev.ru     mpcl = nxt_mem_pool_cleanup(c->mem_pool, 0);
1940Sigor@sysoev.ru     if (mpcl == NULL) {
1950Sigor@sysoev.ru         goto fail;
1960Sigor@sysoev.ru     }
1970Sigor@sysoev.ru 
1980Sigor@sysoev.ru     ctx = conf->ctx;
1990Sigor@sysoev.ru 
2000Sigor@sysoev.ru     s = CyaSSL_new(ctx);
2010Sigor@sysoev.ru     if (s == NULL) {
202*564Svbart@nginx.com         nxt_cyassl_log_error(NXT_LOG_ALERT, c->socket.log, 0,
2030Sigor@sysoev.ru                              "CyaSSL_new() failed");
2040Sigor@sysoev.ru         goto fail;
2050Sigor@sysoev.ru     }
2060Sigor@sysoev.ru 
2070Sigor@sysoev.ru     ssltls->session = s;
2080Sigor@sysoev.ru     mpcl->handler = nxt_cyassl_session_cleanup;
2090Sigor@sysoev.ru     mpcl->data = ssltls;
2100Sigor@sysoev.ru 
2110Sigor@sysoev.ru     CyaSSL_SetIOReadCtx(s, c);
2120Sigor@sysoev.ru     CyaSSL_SetIOWriteCtx(s, c);
2130Sigor@sysoev.ru 
2140Sigor@sysoev.ru     c->io = &nxt_cyassl_event_conn_io;
2150Sigor@sysoev.ru     c->sendfile = NXT_CONN_SENDFILE_OFF;
2160Sigor@sysoev.ru 
2170Sigor@sysoev.ru     nxt_cyassl_conn_handshake(thr, c, c->socket.data);
2180Sigor@sysoev.ru     return;
2190Sigor@sysoev.ru 
2200Sigor@sysoev.ru fail:
2210Sigor@sysoev.ru 
2220Sigor@sysoev.ru     nxt_event_conn_io_handle(thr, c->read_work_queue,
2230Sigor@sysoev.ru                              c->read_state->error_handler, c, c->socket.data);
2240Sigor@sysoev.ru }
2250Sigor@sysoev.ru 
2260Sigor@sysoev.ru 
2270Sigor@sysoev.ru static void
nxt_cyassl_session_cleanup(void * data)2280Sigor@sysoev.ru nxt_cyassl_session_cleanup(void *data)
2290Sigor@sysoev.ru {
2300Sigor@sysoev.ru     nxt_cyassl_conn_t  *ssltls;
2310Sigor@sysoev.ru 
2320Sigor@sysoev.ru     ssltls = data;
2330Sigor@sysoev.ru 
2340Sigor@sysoev.ru     nxt_thread_log_debug("cyassl session cleanup");
2350Sigor@sysoev.ru 
2360Sigor@sysoev.ru     nxt_free(ssltls->buffer.start);
2370Sigor@sysoev.ru 
2380Sigor@sysoev.ru     CyaSSL_free(ssltls->session);
2390Sigor@sysoev.ru }
2400Sigor@sysoev.ru 
2410Sigor@sysoev.ru 
2420Sigor@sysoev.ru static int
nxt_cyassl_io_recv(CYASSL * ssl,char * buf,int size,void * data)2430Sigor@sysoev.ru nxt_cyassl_io_recv(CYASSL *ssl, char *buf, int size, void *data)
2440Sigor@sysoev.ru {
2450Sigor@sysoev.ru     ssize_t           n;
2460Sigor@sysoev.ru     nxt_thread_t      *thr;
2470Sigor@sysoev.ru     nxt_event_conn_t  *c;
2480Sigor@sysoev.ru 
2490Sigor@sysoev.ru     c = data;
2500Sigor@sysoev.ru     thr = nxt_thread();
2510Sigor@sysoev.ru 
2520Sigor@sysoev.ru     n = thr->engine->event->io->recv(c, (u_char *) buf, size, 0);
2530Sigor@sysoev.ru 
2540Sigor@sysoev.ru     if (n > 0) {
2550Sigor@sysoev.ru         return n;
2560Sigor@sysoev.ru     }
2570Sigor@sysoev.ru 
2580Sigor@sysoev.ru     if (n == 0) {
2590Sigor@sysoev.ru         return CYASSL_CBIO_ERR_CONN_CLOSE;
2600Sigor@sysoev.ru     }
2610Sigor@sysoev.ru 
2620Sigor@sysoev.ru     if (n == NXT_AGAIN) {
2630Sigor@sysoev.ru         return CYASSL_CBIO_ERR_WANT_READ;
2640Sigor@sysoev.ru     }
2650Sigor@sysoev.ru 
2660Sigor@sysoev.ru     return CYASSL_CBIO_ERR_GENERAL;
2670Sigor@sysoev.ru }
2680Sigor@sysoev.ru 
2690Sigor@sysoev.ru 
2700Sigor@sysoev.ru static int
nxt_cyassl_io_send(CYASSL * ssl,char * buf,int size,void * data)2710Sigor@sysoev.ru nxt_cyassl_io_send(CYASSL *ssl, char *buf, int size, void *data)
2720Sigor@sysoev.ru {
2730Sigor@sysoev.ru     ssize_t           n;
2740Sigor@sysoev.ru     nxt_thread_t      *thr;
2750Sigor@sysoev.ru     nxt_event_conn_t  *c;
2760Sigor@sysoev.ru 
2770Sigor@sysoev.ru     c = data;
2780Sigor@sysoev.ru     thr = nxt_thread();
2790Sigor@sysoev.ru 
2800Sigor@sysoev.ru     n = thr->engine->event->io->send(c, (u_char *) buf, size);
2810Sigor@sysoev.ru 
2820Sigor@sysoev.ru     if (n > 0) {
2830Sigor@sysoev.ru         return n;
2840Sigor@sysoev.ru     }
2850Sigor@sysoev.ru 
2860Sigor@sysoev.ru     if (n == NXT_AGAIN) {
2870Sigor@sysoev.ru         return CYASSL_CBIO_ERR_WANT_WRITE;
2880Sigor@sysoev.ru     }
2890Sigor@sysoev.ru 
2900Sigor@sysoev.ru     return CYASSL_CBIO_ERR_GENERAL;
2910Sigor@sysoev.ru }
2920Sigor@sysoev.ru 
2930Sigor@sysoev.ru 
2940Sigor@sysoev.ru static void
nxt_cyassl_conn_handshake(nxt_thread_t * thr,void * obj,void * data)2950Sigor@sysoev.ru nxt_cyassl_conn_handshake(nxt_thread_t *thr, void *obj, void *data)
2960Sigor@sysoev.ru {
2970Sigor@sysoev.ru     int                ret;
2980Sigor@sysoev.ru     nxt_int_t          n;
2990Sigor@sysoev.ru     nxt_err_t          err;
3000Sigor@sysoev.ru     nxt_event_conn_t   *c;
3010Sigor@sysoev.ru     nxt_cyassl_conn_t  *ssltls;
3020Sigor@sysoev.ru 
3030Sigor@sysoev.ru     c = obj;
3040Sigor@sysoev.ru     ssltls = c->u.ssltls;
3050Sigor@sysoev.ru 
3060Sigor@sysoev.ru     nxt_log_debug(thr->log, "cyassl conn handshake: %d", ssltls->times);
3070Sigor@sysoev.ru 
3080Sigor@sysoev.ru     /* "ssltls->times == 1" is suitable to run CyaSSL_negotiate() in job. */
3090Sigor@sysoev.ru 
3100Sigor@sysoev.ru     ret = CyaSSL_negotiate(ssltls->session);
3110Sigor@sysoev.ru 
3120Sigor@sysoev.ru     err = (ret != 0) ? nxt_socket_errno : 0;
3130Sigor@sysoev.ru 
3140Sigor@sysoev.ru     nxt_thread_time_debug_update(thr);
3150Sigor@sysoev.ru 
3160Sigor@sysoev.ru     nxt_log_debug(thr->log, "CyaSSL_negotiate(%d): %d", c->socket.fd, ret);
3170Sigor@sysoev.ru 
3180Sigor@sysoev.ru     if (ret == 0) {
3190Sigor@sysoev.ru         nxt_cyassl_conn_io_read(thr, c, data);
3200Sigor@sysoev.ru         return;
3210Sigor@sysoev.ru     }
3220Sigor@sysoev.ru 
3230Sigor@sysoev.ru     n = nxt_cyassl_conn_test_error(thr, c, ret, nxt_cyassl_conn_handshake);
3240Sigor@sysoev.ru 
3250Sigor@sysoev.ru     if (n == NXT_ERROR) {
3260Sigor@sysoev.ru         nxt_cyassl_conn_error(c, err, "CyaSSL_negotiate(%d) failed",
3270Sigor@sysoev.ru                               c->socket.fd);
3280Sigor@sysoev.ru 
3290Sigor@sysoev.ru         nxt_event_conn_io_handle(thr, c->read_work_queue,
3300Sigor@sysoev.ru                                  c->read_state->error_handler, c, data);
3310Sigor@sysoev.ru 
3320Sigor@sysoev.ru     } else if (ssltls->ssl_error == SSL_ERROR_WANT_READ && ssltls->times < 2) {
3330Sigor@sysoev.ru         ssltls->times++;
3340Sigor@sysoev.ru     }
3350Sigor@sysoev.ru }
3360Sigor@sysoev.ru 
3370Sigor@sysoev.ru 
3380Sigor@sysoev.ru static void
nxt_cyassl_conn_io_read(nxt_thread_t * thr,void * obj,void * data)3390Sigor@sysoev.ru nxt_cyassl_conn_io_read(nxt_thread_t *thr, void *obj, void *data)
3400Sigor@sysoev.ru {
3410Sigor@sysoev.ru     int                 ret;
3420Sigor@sysoev.ru     nxt_buf_t           *b;
3430Sigor@sysoev.ru     nxt_err_t           err;
3440Sigor@sysoev.ru     nxt_int_t           n;
3450Sigor@sysoev.ru     nxt_event_conn_t    *c;
3460Sigor@sysoev.ru     nxt_cyassl_conn_t   *ssltls;
3470Sigor@sysoev.ru     nxt_work_handler_t  handler;
3480Sigor@sysoev.ru 
3490Sigor@sysoev.ru     c = obj;
3500Sigor@sysoev.ru 
3510Sigor@sysoev.ru     nxt_log_debug(thr->log, "cyassl conn read");
3520Sigor@sysoev.ru 
3530Sigor@sysoev.ru     handler = c->read_state->ready_handler;
3540Sigor@sysoev.ru     b = c->read;
3550Sigor@sysoev.ru 
3560Sigor@sysoev.ru     /* b == NULL is used to test descriptor readiness. */
3570Sigor@sysoev.ru 
3580Sigor@sysoev.ru     if (b != NULL) {
3590Sigor@sysoev.ru         ssltls = c->u.ssltls;
3600Sigor@sysoev.ru 
3610Sigor@sysoev.ru         ret = CyaSSL_read(ssltls->session, b->mem.free,
3620Sigor@sysoev.ru                           b->mem.end - b->mem.free);
3630Sigor@sysoev.ru 
3640Sigor@sysoev.ru         err = (ret <= 0) ? nxt_socket_errno : 0;
3650Sigor@sysoev.ru 
3660Sigor@sysoev.ru         nxt_log_debug(thr->log, "CyaSSL_read(%d, %p, %uz): %d",
3670Sigor@sysoev.ru                       c->socket.fd, b->mem.free, b->mem.end - b->mem.free, ret);
3680Sigor@sysoev.ru 
3690Sigor@sysoev.ru         if (ret > 0) {
3700Sigor@sysoev.ru             /* c->socket.read_ready is kept. */
3710Sigor@sysoev.ru             b->mem.free += ret;
3720Sigor@sysoev.ru             handler = c->read_state->ready_handler;
3730Sigor@sysoev.ru 
3740Sigor@sysoev.ru         } else {
3750Sigor@sysoev.ru             n = nxt_cyassl_conn_test_error(thr, c, ret,
3760Sigor@sysoev.ru                                            nxt_cyassl_conn_io_read);
3770Sigor@sysoev.ru 
3780Sigor@sysoev.ru             if (nxt_fast_path(n != NXT_ERROR)) {
3790Sigor@sysoev.ru                 return;
3800Sigor@sysoev.ru             }
3810Sigor@sysoev.ru 
3820Sigor@sysoev.ru             nxt_cyassl_conn_error(c, err, "CyaSSL_read(%d, %p, %uz) failed",
3830Sigor@sysoev.ru                                   c->socket.fd, b->mem.free,
3840Sigor@sysoev.ru                                   b->mem.end - b->mem.free);
3850Sigor@sysoev.ru 
3860Sigor@sysoev.ru             handler = c->read_state->error_handler;
3870Sigor@sysoev.ru         }
3880Sigor@sysoev.ru     }
3890Sigor@sysoev.ru 
3900Sigor@sysoev.ru     nxt_event_conn_io_handle(thr, c->read_work_queue, handler, c, data);
3910Sigor@sysoev.ru }
3920Sigor@sysoev.ru 
3930Sigor@sysoev.ru 
3940Sigor@sysoev.ru static ssize_t
nxt_cyassl_conn_io_write_chunk(nxt_thread_t * thr,nxt_event_conn_t * c,nxt_buf_t * b,size_t limit)3950Sigor@sysoev.ru nxt_cyassl_conn_io_write_chunk(nxt_thread_t *thr, nxt_event_conn_t *c,
3960Sigor@sysoev.ru     nxt_buf_t *b, size_t limit)
3970Sigor@sysoev.ru {
3980Sigor@sysoev.ru     nxt_cyassl_conn_t  *ssltls;
3990Sigor@sysoev.ru 
4000Sigor@sysoev.ru     nxt_log_debug(thr->log, "cyassl conn write chunk");
4010Sigor@sysoev.ru 
4020Sigor@sysoev.ru     ssltls = c->u.ssltls;
4030Sigor@sysoev.ru 
4040Sigor@sysoev.ru     return nxt_sendbuf_copy_coalesce(c, &ssltls->buffer, b, limit);
4050Sigor@sysoev.ru }
4060Sigor@sysoev.ru 
4070Sigor@sysoev.ru 
4080Sigor@sysoev.ru static ssize_t
nxt_cyassl_conn_io_send(nxt_event_conn_t * c,void * buf,size_t size)4090Sigor@sysoev.ru nxt_cyassl_conn_io_send(nxt_event_conn_t *c, void *buf, size_t size)
4100Sigor@sysoev.ru {
4110Sigor@sysoev.ru     int                ret;
4120Sigor@sysoev.ru     nxt_err_t          err;
4130Sigor@sysoev.ru     nxt_int_t          n;
4140Sigor@sysoev.ru     nxt_cyassl_conn_t  *ssltls;
4150Sigor@sysoev.ru 
4160Sigor@sysoev.ru     nxt_log_debug(c->socket.log, "cyassl send");
4170Sigor@sysoev.ru 
4180Sigor@sysoev.ru     ssltls = c->u.ssltls;
4190Sigor@sysoev.ru 
4200Sigor@sysoev.ru     ret = CyaSSL_write(ssltls->session, buf, size);
4210Sigor@sysoev.ru 
4220Sigor@sysoev.ru     if (ret <= 0) {
4230Sigor@sysoev.ru         err = nxt_socket_errno;
4240Sigor@sysoev.ru         c->socket.error = err;
4250Sigor@sysoev.ru 
4260Sigor@sysoev.ru     } else {
4270Sigor@sysoev.ru         err = 0;
4280Sigor@sysoev.ru     }
4290Sigor@sysoev.ru 
4300Sigor@sysoev.ru     nxt_log_debug(c->socket.log, "CyaSSL_write(%d, %p, %uz): %d",
4310Sigor@sysoev.ru                   c->socket.fd, buf, size, ret);
4320Sigor@sysoev.ru 
4330Sigor@sysoev.ru     if (ret > 0) {
4340Sigor@sysoev.ru         return ret;
4350Sigor@sysoev.ru     }
4360Sigor@sysoev.ru 
4370Sigor@sysoev.ru     n = nxt_cyassl_conn_test_error(nxt_thread(), c, ret,
4380Sigor@sysoev.ru                                    nxt_event_conn_io_write);
4390Sigor@sysoev.ru 
4400Sigor@sysoev.ru     if (nxt_slow_path(n == NXT_ERROR)) {
4410Sigor@sysoev.ru         nxt_cyassl_conn_error(c, err, "CyaSSL_write(%d, %p, %uz) failed",
4420Sigor@sysoev.ru                               c->socket.fd, buf, size);
4430Sigor@sysoev.ru     }
4440Sigor@sysoev.ru 
4450Sigor@sysoev.ru     return n;
4460Sigor@sysoev.ru }
4470Sigor@sysoev.ru 
4480Sigor@sysoev.ru 
4490Sigor@sysoev.ru static void
nxt_cyassl_conn_io_shutdown(nxt_thread_t * thr,void * obj,void * data)4500Sigor@sysoev.ru nxt_cyassl_conn_io_shutdown(nxt_thread_t *thr, void *obj, void *data)
4510Sigor@sysoev.ru {
4520Sigor@sysoev.ru     int                ret;
4530Sigor@sysoev.ru     nxt_event_conn_t   *c;
4540Sigor@sysoev.ru     nxt_cyassl_conn_t  *ssltls;
4550Sigor@sysoev.ru 
4560Sigor@sysoev.ru     c = obj;
4570Sigor@sysoev.ru 
4580Sigor@sysoev.ru     nxt_log_debug(thr->log, "cyassl conn shutdown");
4590Sigor@sysoev.ru 
4600Sigor@sysoev.ru     ssltls = c->u.ssltls;
4610Sigor@sysoev.ru 
4620Sigor@sysoev.ru     ret = CyaSSL_shutdown(ssltls->session);
4630Sigor@sysoev.ru 
4640Sigor@sysoev.ru     nxt_log_debug(thr->log, "CyaSSL_shutdown(%d): %d", c->socket.fd, ret);
4650Sigor@sysoev.ru 
4660Sigor@sysoev.ru     if (nxt_slow_path(ret != SSL_SUCCESS)) {
4670Sigor@sysoev.ru         nxt_cyassl_conn_error(c, 0, "CyaSSL_shutdown(%d) failed", c->socket.fd);
4680Sigor@sysoev.ru     }
4690Sigor@sysoev.ru 
4700Sigor@sysoev.ru     nxt_event_conn_io_handle(thr, c->write_work_queue,
4710Sigor@sysoev.ru                              c->write_state->close_handler, c, data);
4720Sigor@sysoev.ru }
4730Sigor@sysoev.ru 
4740Sigor@sysoev.ru 
4750Sigor@sysoev.ru static nxt_int_t
nxt_cyassl_conn_test_error(nxt_thread_t * thr,nxt_event_conn_t * c,int ret,nxt_work_handler_t handler)4760Sigor@sysoev.ru nxt_cyassl_conn_test_error(nxt_thread_t *thr, nxt_event_conn_t *c, int ret,
4770Sigor@sysoev.ru     nxt_work_handler_t handler)
4780Sigor@sysoev.ru {
4790Sigor@sysoev.ru     nxt_work_queue_t   *wq;
4800Sigor@sysoev.ru     nxt_cyassl_conn_t  *ssltls;
4810Sigor@sysoev.ru 
4820Sigor@sysoev.ru     ssltls = c->u.ssltls;
4830Sigor@sysoev.ru     ssltls->ssl_error = CyaSSL_get_error(ssltls->session, ret);
4840Sigor@sysoev.ru 
4850Sigor@sysoev.ru     nxt_log_debug(thr->log, "CyaSSL_get_error(): %d", ssltls->ssl_error);
4860Sigor@sysoev.ru 
4870Sigor@sysoev.ru     switch (ssltls->ssl_error) {
4880Sigor@sysoev.ru 
4890Sigor@sysoev.ru     case SSL_ERROR_WANT_READ:
4900Sigor@sysoev.ru         nxt_event_fd_block_write(thr->engine, &c->socket);
4910Sigor@sysoev.ru 
4920Sigor@sysoev.ru         c->socket.read_ready = 0;
4930Sigor@sysoev.ru         c->socket.read_handler = handler;
4940Sigor@sysoev.ru 
4950Sigor@sysoev.ru         if (nxt_event_fd_is_disabled(c->socket.read)) {
4960Sigor@sysoev.ru             nxt_event_fd_enable_read(thr->engine, &c->socket);
4970Sigor@sysoev.ru         }
4980Sigor@sysoev.ru 
4990Sigor@sysoev.ru         return NXT_AGAIN;
5000Sigor@sysoev.ru 
5010Sigor@sysoev.ru     case SSL_ERROR_WANT_WRITE:
5020Sigor@sysoev.ru         nxt_event_fd_block_read(thr->engine, &c->socket);
5030Sigor@sysoev.ru 
5040Sigor@sysoev.ru         c->socket.write_ready = 0;
5050Sigor@sysoev.ru         c->socket.write_handler = handler;
5060Sigor@sysoev.ru 
5070Sigor@sysoev.ru         if (nxt_event_fd_is_disabled(c->socket.write)) {
5080Sigor@sysoev.ru             nxt_event_fd_enable_write(thr->engine, &c->socket);
5090Sigor@sysoev.ru         }
5100Sigor@sysoev.ru 
5110Sigor@sysoev.ru         return NXT_AGAIN;
5120Sigor@sysoev.ru 
5130Sigor@sysoev.ru     case SSL_ERROR_ZERO_RETURN:
5140Sigor@sysoev.ru         /* A "close notify" alert */
5150Sigor@sysoev.ru 
5160Sigor@sysoev.ru         if (c->read_state != NULL) {
5170Sigor@sysoev.ru             wq = c->read_work_queue;
5180Sigor@sysoev.ru             handler = c->read_state->close_handler;
5190Sigor@sysoev.ru 
5200Sigor@sysoev.ru         } else {
5210Sigor@sysoev.ru             wq = c->write_work_queue;
5220Sigor@sysoev.ru             handler = c->write_state->close_handler;
5230Sigor@sysoev.ru         }
5240Sigor@sysoev.ru 
5250Sigor@sysoev.ru         nxt_event_conn_io_handle(thr, wq, handler, c, c->socket.data);
5260Sigor@sysoev.ru 
5270Sigor@sysoev.ru         return 0;
5280Sigor@sysoev.ru 
5290Sigor@sysoev.ru     default:
5300Sigor@sysoev.ru         return NXT_ERROR;
5310Sigor@sysoev.ru     }
5320Sigor@sysoev.ru }
5330Sigor@sysoev.ru 
5340Sigor@sysoev.ru 
5350Sigor@sysoev.ru static void nxt_cdecl
nxt_cyassl_conn_error(nxt_event_conn_t * c,nxt_err_t err,const char * fmt,...)5360Sigor@sysoev.ru nxt_cyassl_conn_error(nxt_event_conn_t *c, nxt_err_t err, const char *fmt, ...)
5370Sigor@sysoev.ru {
5380Sigor@sysoev.ru     u_char             *p, *end;
5390Sigor@sysoev.ru     va_list            args;
5400Sigor@sysoev.ru     nxt_uint_t         level;
5410Sigor@sysoev.ru     nxt_cyassl_conn_t  *ssltls;
5420Sigor@sysoev.ru     u_char             msg[NXT_MAX_ERROR_STR];
5430Sigor@sysoev.ru 
5440Sigor@sysoev.ru     ssltls = c->u.ssltls;
5450Sigor@sysoev.ru 
5460Sigor@sysoev.ru     level = nxt_cyassl_log_error_level(c, err, ssltls->ssl_error);
5470Sigor@sysoev.ru 
5480Sigor@sysoev.ru     if (nxt_log_level_enough(c->socket.log, level)) {
5490Sigor@sysoev.ru 
5500Sigor@sysoev.ru         end = msg + sizeof(msg);
5510Sigor@sysoev.ru 
5520Sigor@sysoev.ru         va_start(args, fmt);
5530Sigor@sysoev.ru         p = nxt_vsprintf(msg, end, fmt, args);
5540Sigor@sysoev.ru         va_end(args);
5550Sigor@sysoev.ru 
5560Sigor@sysoev.ru         if (err != 0) {
5570Sigor@sysoev.ru             p = nxt_sprintf(p, end, " %E", err);
5580Sigor@sysoev.ru         }
5590Sigor@sysoev.ru 
5600Sigor@sysoev.ru         p = nxt_cyassl_copy_error(ssltls->ssl_error, p, end);
5610Sigor@sysoev.ru 
5620Sigor@sysoev.ru         nxt_log_error(level, c->socket.log, "%*s", p - msg, msg);
5630Sigor@sysoev.ru     }
5640Sigor@sysoev.ru }
5650Sigor@sysoev.ru 
5660Sigor@sysoev.ru 
5670Sigor@sysoev.ru static nxt_uint_t
nxt_cyassl_log_error_level(nxt_event_conn_t * c,nxt_err_t err,int ssl_error)5680Sigor@sysoev.ru nxt_cyassl_log_error_level(nxt_event_conn_t *c, nxt_err_t err, int ssl_error)
5690Sigor@sysoev.ru {
5700Sigor@sysoev.ru     switch (ssl_error) {
5710Sigor@sysoev.ru 
5720Sigor@sysoev.ru     case SOCKET_ERROR_E:            /* -208 */
5730Sigor@sysoev.ru     case MATCH_SUITE_ERROR:         /* -261 */
5740Sigor@sysoev.ru         break;
5750Sigor@sysoev.ru 
5760Sigor@sysoev.ru     default:
577*564Svbart@nginx.com         return NXT_LOG_ALERT;
5780Sigor@sysoev.ru     }
5790Sigor@sysoev.ru 
5800Sigor@sysoev.ru     return NXT_LOG_INFO;
5810Sigor@sysoev.ru }
5820Sigor@sysoev.ru 
5830Sigor@sysoev.ru 
5840Sigor@sysoev.ru static void nxt_cdecl
nxt_cyassl_log_error(nxt_uint_t level,nxt_log_t * log,int err,const char * fmt,...)5850Sigor@sysoev.ru nxt_cyassl_log_error(nxt_uint_t level, nxt_log_t *log, int err,
5860Sigor@sysoev.ru     const char *fmt, ...)
5870Sigor@sysoev.ru {
5880Sigor@sysoev.ru     u_char   *p, *end;
5890Sigor@sysoev.ru     va_list  args;
5900Sigor@sysoev.ru     u_char   msg[NXT_MAX_ERROR_STR];
5910Sigor@sysoev.ru 
5920Sigor@sysoev.ru     if (nxt_log_level_enough(log, level)) {
5930Sigor@sysoev.ru 
5940Sigor@sysoev.ru         end = msg + sizeof(msg);
5950Sigor@sysoev.ru 
5960Sigor@sysoev.ru         va_start(args, fmt);
5970Sigor@sysoev.ru         p = nxt_vsprintf(msg, end, fmt, args);
5980Sigor@sysoev.ru         va_end(args);
5990Sigor@sysoev.ru 
6000Sigor@sysoev.ru         p = nxt_cyassl_copy_error(err, p, end);
6010Sigor@sysoev.ru 
6020Sigor@sysoev.ru         nxt_log_error(level, log, "%*s", p - msg, msg);
6030Sigor@sysoev.ru     }
6040Sigor@sysoev.ru }
6050Sigor@sysoev.ru 
6060Sigor@sysoev.ru 
6070Sigor@sysoev.ru static u_char *
nxt_cyassl_copy_error(int err,u_char * p,u_char * end)6080Sigor@sysoev.ru nxt_cyassl_copy_error(int err, u_char *p, u_char *end)
6090Sigor@sysoev.ru {
6100Sigor@sysoev.ru     p = nxt_sprintf(p, end, " (SSL:%d ", err);
6110Sigor@sysoev.ru 
6120Sigor@sysoev.ru     CyaSSL_ERR_error_string_n(err, (char *) p, end - p);
6130Sigor@sysoev.ru 
6140Sigor@sysoev.ru     p += nxt_strlen(p);
6150Sigor@sysoev.ru 
6160Sigor@sysoev.ru     if (p < end) {
6170Sigor@sysoev.ru         *p++ = ')';
6180Sigor@sysoev.ru     }
6190Sigor@sysoev.ru 
6200Sigor@sysoev.ru     return p;
6210Sigor@sysoev.ru }
622