@@ -25,6 +25,7 @@ HTTPSConnection::HTTPSConnection(ResourceResolver * resResolver):
25
25
_defaultHeaders = NULL ;
26
26
_isKeepAlive = false ;
27
27
_lastTransmissionTS = millis ();
28
+ _shutdownTS = 0 ;
28
29
}
29
30
30
31
HTTPSConnection::~HTTPSConnection () {
@@ -115,29 +116,53 @@ bool HTTPSConnection::isError() {
115
116
void HTTPSConnection::closeConnection () {
116
117
// TODO: Call an event handler here, maybe?
117
118
118
- // Tear down SSL
119
- if (_ssl) {
120
- // wait here so that SSL_shutdown returns 1
121
- while (SSL_shutdown (_ssl) == 0 ) delay (1 );
122
- SSL_free (_ssl);
123
- _ssl = NULL ;
124
- }
125
119
126
- // Tear down the socket
127
- if (_socket >= 0 ) {
128
- HTTPS_DLOGHEX (" [<--] Connection has been closed. fid = " , _socket);
129
- close (_socket);
130
- _socket = -1 ;
131
- _addrLen = 0 ;
132
- }
120
+ if (_connectionState != STATE_ERROR && _connectionState != STATE_CLOSED) {
133
121
134
- if (_connectionState != STATE_ERROR) {
135
- _connectionState = STATE_CLOSED;
136
- }
122
+ // First call to closeConnection - set the timestamp to calculate the timeout later on
123
+ if (_connectionState != STATE_CLOSING) {
124
+ _shutdownTS = millis ();
125
+ }
137
126
138
- if (_httpHeaders != NULL ) {
139
- delete _httpHeaders;
140
- _httpHeaders = NULL ;
127
+ // Set the connection state to closing. We stay in closing as long as SSL has not been shutdown
128
+ // correctly
129
+ _connectionState = STATE_CLOSING;
130
+
131
+ // Try to tear down SSL
132
+ if (_ssl) {
133
+ if (SSL_shutdown (_ssl) == 0 ) {
134
+ // SSL_shutdown will return 1 as soon as the client answered with close notify
135
+ // This means we are safe to close the socket
136
+ SSL_free (_ssl);
137
+ _ssl = NULL ;
138
+ } else if (_shutdownTS + HTTPS_SHUTDOWN_TIMEOUT < millis ()) {
139
+ // The timeout has been hit, we force SSL shutdown now by freeing the context
140
+ SSL_free (_ssl);
141
+ _ssl = NULL ;
142
+ HTTPS_DLOG (" [ERR] SSL_shutdown did not receive close notification from the client" );
143
+ _connectionState = STATE_ERROR;
144
+ }
145
+ }
146
+
147
+ // If SSL has been brought down, close the socket
148
+ if (!_ssl) {
149
+ // Tear down the socket
150
+ if (_socket >= 0 ) {
151
+ HTTPS_DLOGHEX (" [<--] Connection has been closed. fid = " , _socket);
152
+ close (_socket);
153
+ _socket = -1 ;
154
+ _addrLen = 0 ;
155
+ }
156
+
157
+ if (_connectionState != STATE_ERROR) {
158
+ _connectionState = STATE_CLOSED;
159
+ }
160
+
161
+ if (_httpHeaders != NULL ) {
162
+ delete _httpHeaders;
163
+ _httpHeaders = NULL ;
164
+ }
165
+ }
141
166
}
142
167
}
143
168
@@ -489,6 +514,9 @@ void HTTPSConnection::loop() {
489
514
case STATE_BODY_FINISHED: // Request is complete
490
515
closeConnection ();
491
516
break ;
517
+ case STATE_CLOSING: // As long as we are in closing state, we call closeConnection() again and wait for it to finish or timeout
518
+ closeConnection ();
519
+ break ;
492
520
case STATE_WEBSOCKET: // Do handling of the websocket
493
521
494
522
break ;
0 commit comments