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.
Maxim Dounin
9 years ago
527 | 527 | return NGX_ERROR; |
528 | 528 | } |
529 | 529 | |
530 | SSL_CTX_set_options(ssl->ctx, SSL_OP_SINGLE_ECDH_USE); | |
531 | ||
530 | 532 | SSL_CTX_set_tmp_ecdh(ssl->ctx, ecdh); |
531 | ||
532 | SSL_CTX_set_options(ssl->ctx, SSL_OP_SINGLE_ECDH_USE); | |
533 | 533 | |
534 | 534 | EC_KEY_free(ecdh); |
535 | 535 | #endif |
692 | 692 | return NGX_ERROR; |
693 | 693 | } |
694 | 694 | |
695 | if (ngx_handle_write_event(c->write, 0) != NGX_OK) { | |
696 | return NGX_ERROR; | |
697 | } | |
698 | ||
695 | 699 | return NGX_AGAIN; |
696 | 700 | } |
697 | 701 | |
699 | 703 | c->write->ready = 0; |
700 | 704 | c->read->handler = ngx_ssl_handshake_handler; |
701 | 705 | c->write->handler = ngx_ssl_handshake_handler; |
706 | ||
707 | if (ngx_handle_read_event(c->read, 0) != NGX_OK) { | |
708 | return NGX_ERROR; | |
709 | } | |
702 | 710 | |
703 | 711 | if (ngx_handle_write_event(c->write, 0) != NGX_OK) { |
704 | 712 | return NGX_ERROR; |
1052 | 1060 | buf->end = buf->start + NGX_SSL_BUFSIZE; |
1053 | 1061 | } |
1054 | 1062 | |
1055 | send = 0; | |
1056 | flush = (in == NULL) ? 1 : 0; | |
1063 | send = buf->last - buf->pos; | |
1064 | flush = (in == NULL) ? 1 : buf->flush; | |
1057 | 1065 | |
1058 | 1066 | for ( ;; ) { |
1059 | 1067 | |
1075 | 1083 | |
1076 | 1084 | if (send + size > limit) { |
1077 | 1085 | size = (ssize_t) (limit - send); |
1078 | flush = 1; | |
1079 | 1086 | } |
1080 | 1087 | |
1081 | 1088 | ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, |
1092 | 1099 | } |
1093 | 1100 | } |
1094 | 1101 | |
1102 | if (!flush && send < limit && buf->last < buf->end) { | |
1103 | break; | |
1104 | } | |
1105 | ||
1095 | 1106 | size = buf->last - buf->pos; |
1096 | 1107 | |
1097 | if (!flush && buf->last < buf->end && c->ssl->buffer) { | |
1098 | break; | |
1108 | if (size == 0) { | |
1109 | buf->flush = 0; | |
1110 | c->buffered &= ~NGX_SSL_BUFFERED; | |
1111 | return in; | |
1099 | 1112 | } |
1100 | 1113 | |
1101 | 1114 | n = ngx_ssl_write(c, buf->pos, size); |
1105 | 1118 | } |
1106 | 1119 | |
1107 | 1120 | if (n == NGX_AGAIN) { |
1108 | c->buffered |= NGX_SSL_BUFFERED; | |
1109 | return in; | |
1121 | break; | |
1110 | 1122 | } |
1111 | 1123 | |
1112 | 1124 | buf->pos += n; |
1116 | 1128 | break; |
1117 | 1129 | } |
1118 | 1130 | |
1119 | if (buf->pos == buf->last) { | |
1120 | buf->pos = buf->start; | |
1121 | buf->last = buf->start; | |
1122 | } | |
1131 | flush = 0; | |
1132 | ||
1133 | buf->pos = buf->start; | |
1134 | buf->last = buf->start; | |
1123 | 1135 | |
1124 | 1136 | if (in == NULL || send == limit) { |
1125 | 1137 | break; |
1126 | 1138 | } |
1127 | 1139 | } |
1140 | ||
1141 | buf->flush = flush; | |
1128 | 1142 | |
1129 | 1143 | if (buf->pos < buf->last) { |
1130 | 1144 | c->buffered |= NGX_SSL_BUFFERED; |