comparison src/event/ngx_event_openssl.c @ 5058:f25d0bbc4392 stable-1.2

Merge of r5004, r5019-r5025: ssl fixes. *) SSL: speedup loading of configs with many ssl servers. The patch saves one EC_KEY_generate_key() call per server{} block by informing OpenSSL about SSL_OP_SINGLE_ECDH_USE we are going to use before the SSL_CTX_set_tmp_ecdh() call. For a configuration file with 10k simple server{} blocks with SSL enabled this change reduces startup time from 18s to 5s on a slow test box here. *) SSL: removed conditions that always hold true. *) SSL: resetting of flush flag after the data was written. There is no need to flush next chunk of data if it does not contain a buffer with the flush or last_buf flags set. *) SSL: preservation of flush flag for buffered data. Previously, if SSL buffer was not sent we lost information that the data must be flushed. *) SSL: calculation of buffer size moved closer to its usage. No functional changes. *) SSL: avoid calling SSL_write() with zero data size. According to documentation, calling SSL_write() with num=0 bytes to be sent results in undefined behavior. We don't currently call ngx_ssl_send_chain() with empty chain and buffer. This check handles the case of a chain with total data size that is a multiple of NGX_SSL_BUFSIZE, and with the special buffer at the end. In practice such cases resulted in premature connection close and critical error "SSL_write() failed (SSL:)" in the error log. *) SSL: take into account data in the buffer while limiting output. In some rare cases this can result in a more smooth sending rate. *) SSL: fixed ngx_ssl_handshake() with level-triggered event methods. Missing calls to ngx_handle_write_event() and ngx_handle_read_event() resulted in a CPU hog during SSL handshake if an level-triggered event method (e.g. select) was used.
author Maxim Dounin <mdounin@mdounin.ru>
date Mon, 11 Feb 2013 15:12:06 +0000
parents a0cb7fc23cc2
children 0dbe5eaa2388
comparison
equal deleted inserted replaced
5057:ffe4df586561 5058:f25d0bbc4392
526 ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, 526 ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
527 "Unable to create curve \"%s\"", name->data); 527 "Unable to create curve \"%s\"", name->data);
528 return NGX_ERROR; 528 return NGX_ERROR;
529 } 529 }
530 530
531 SSL_CTX_set_options(ssl->ctx, SSL_OP_SINGLE_ECDH_USE);
532
531 SSL_CTX_set_tmp_ecdh(ssl->ctx, ecdh); 533 SSL_CTX_set_tmp_ecdh(ssl->ctx, ecdh);
532
533 SSL_CTX_set_options(ssl->ctx, SSL_OP_SINGLE_ECDH_USE);
534 534
535 EC_KEY_free(ecdh); 535 EC_KEY_free(ecdh);
536 #endif 536 #endif
537 #endif 537 #endif
538 538
691 691
692 if (ngx_handle_read_event(c->read, 0) != NGX_OK) { 692 if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
693 return NGX_ERROR; 693 return NGX_ERROR;
694 } 694 }
695 695
696 if (ngx_handle_write_event(c->write, 0) != NGX_OK) {
697 return NGX_ERROR;
698 }
699
696 return NGX_AGAIN; 700 return NGX_AGAIN;
697 } 701 }
698 702
699 if (sslerr == SSL_ERROR_WANT_WRITE) { 703 if (sslerr == SSL_ERROR_WANT_WRITE) {
700 c->write->ready = 0; 704 c->write->ready = 0;
701 c->read->handler = ngx_ssl_handshake_handler; 705 c->read->handler = ngx_ssl_handshake_handler;
702 c->write->handler = ngx_ssl_handshake_handler; 706 c->write->handler = ngx_ssl_handshake_handler;
707
708 if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
709 return NGX_ERROR;
710 }
703 711
704 if (ngx_handle_write_event(c->write, 0) != NGX_OK) { 712 if (ngx_handle_write_event(c->write, 0) != NGX_OK) {
705 return NGX_ERROR; 713 return NGX_ERROR;
706 } 714 }
707 715
1051 buf->pos = buf->start; 1059 buf->pos = buf->start;
1052 buf->last = buf->start; 1060 buf->last = buf->start;
1053 buf->end = buf->start + NGX_SSL_BUFSIZE; 1061 buf->end = buf->start + NGX_SSL_BUFSIZE;
1054 } 1062 }
1055 1063
1056 send = 0; 1064 send = buf->last - buf->pos;
1057 flush = (in == NULL) ? 1 : 0; 1065 flush = (in == NULL) ? 1 : buf->flush;
1058 1066
1059 for ( ;; ) { 1067 for ( ;; ) {
1060 1068
1061 while (in && buf->last < buf->end && send < limit) { 1069 while (in && buf->last < buf->end && send < limit) {
1062 if (in->buf->last_buf || in->buf->flush) { 1070 if (in->buf->last_buf || in->buf->flush) {
1074 size = buf->end - buf->last; 1082 size = buf->end - buf->last;
1075 } 1083 }
1076 1084
1077 if (send + size > limit) { 1085 if (send + size > limit) {
1078 size = (ssize_t) (limit - send); 1086 size = (ssize_t) (limit - send);
1079 flush = 1;
1080 } 1087 }
1081 1088
1082 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, 1089 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
1083 "SSL buf copy: %d", size); 1090 "SSL buf copy: %d", size);
1084 1091
1091 if (in->buf->pos == in->buf->last) { 1098 if (in->buf->pos == in->buf->last) {
1092 in = in->next; 1099 in = in->next;
1093 } 1100 }
1094 } 1101 }
1095 1102
1103 if (!flush && send < limit && buf->last < buf->end) {
1104 break;
1105 }
1106
1096 size = buf->last - buf->pos; 1107 size = buf->last - buf->pos;
1097 1108
1098 if (!flush && buf->last < buf->end && c->ssl->buffer) { 1109 if (size == 0) {
1099 break; 1110 buf->flush = 0;
1111 c->buffered &= ~NGX_SSL_BUFFERED;
1112 return in;
1100 } 1113 }
1101 1114
1102 n = ngx_ssl_write(c, buf->pos, size); 1115 n = ngx_ssl_write(c, buf->pos, size);
1103 1116
1104 if (n == NGX_ERROR) { 1117 if (n == NGX_ERROR) {
1105 return NGX_CHAIN_ERROR; 1118 return NGX_CHAIN_ERROR;
1106 } 1119 }
1107 1120
1108 if (n == NGX_AGAIN) { 1121 if (n == NGX_AGAIN) {
1109 c->buffered |= NGX_SSL_BUFFERED; 1122 break;
1110 return in;
1111 } 1123 }
1112 1124
1113 buf->pos += n; 1125 buf->pos += n;
1114 c->sent += n; 1126 c->sent += n;
1115 1127
1116 if (n < size) { 1128 if (n < size) {
1117 break; 1129 break;
1118 } 1130 }
1119 1131
1120 if (buf->pos == buf->last) { 1132 flush = 0;
1121 buf->pos = buf->start; 1133
1122 buf->last = buf->start; 1134 buf->pos = buf->start;
1123 } 1135 buf->last = buf->start;
1124 1136
1125 if (in == NULL || send == limit) { 1137 if (in == NULL || send == limit) {
1126 break; 1138 break;
1127 } 1139 }
1128 } 1140 }
1141
1142 buf->flush = flush;
1129 1143
1130 if (buf->pos < buf->last) { 1144 if (buf->pos < buf->last) {
1131 c->buffered |= NGX_SSL_BUFFERED; 1145 c->buffered |= NGX_SSL_BUFFERED;
1132 1146
1133 } else { 1147 } else {