Mercurial > hg > nginx
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 { |