126
126
when defineSsl:
127
127
sslHandle: SslPtr
128
128
sslContext: SslContext
129
+ bioIn: BIO
130
+ bioOut: BIO
129
131
sslNoShutdown: bool
130
132
domain: Domain
131
133
sockType: SockType
@@ -208,7 +210,7 @@ when defineSsl:
208
210
proc raiseSslHandleError =
209
211
raiseSSLError(" The SSL Handle is closed/unset" )
210
212
211
- proc getSslError(socket: AsyncSocket, flags: set [SocketFlag], err: cint ) : cint =
213
+ proc getSslError(socket: AsyncSocket, err: cint ): cint =
212
214
assert socket.isSsl
213
215
assert err < 0
214
216
var ret = SSL_get_error(socket.sslHandle, err.cint )
@@ -221,49 +223,47 @@ when defineSsl:
221
223
return ret
222
224
of SSL_ERROR_WANT_X509_LOOKUP:
223
225
raiseSSLError(" Function for x509 lookup has been called." )
224
- of SSL_ERROR_SYSCALL:
225
- socket.sslNoShutdown = true
226
- let osErr = osLastError()
227
- if not flags.isDisconnectionError(osErr):
228
- var errStr = " IO error has occurred"
229
- let sslErr = ERR_peek_last_error()
230
- if sslErr == 0 and err == 0 :
231
- errStr.add ' '
232
- errStr.add " because an EOF was observed that violates the protocol"
233
- elif sslErr == 0 and err == - 1 :
234
- errStr.add ' '
235
- errStr.add " in the BIO layer"
236
- else :
237
- let errStr = $ ERR_error_string(sslErr, nil )
238
- raiseSSLError(errStr & " : " & errStr)
239
- raiseOSError(osErr, errStr)
240
- else :
241
- return ret
242
- of SSL_ERROR_SSL:
226
+ of SSL_ERROR_SYSCALL, SSL_ERROR_SSL:
243
227
socket.sslNoShutdown = true
244
228
raiseSSLError()
245
229
else : raiseSSLError(" Unknown Error" )
246
230
247
- proc handleSslFailure(socket: AsyncSocket, flags: set [SocketFlag], sslError: cint ) : Future[bool ] =
231
+ proc sendPendingSslData(socket: AsyncSocket,
232
+ flags: set [SocketFlag]) {.async.} =
233
+ if socket.sslHandle == nil :
234
+ raiseSslHandleError()
235
+ let len = bioCtrlPending(socket.bioOut)
236
+ if len > 0 :
237
+ var data = newString(len)
238
+ let read = bioRead(socket.bioOut, cast [cstring ](addr data[0 ]), len)
239
+ assert read != 0
240
+ if read < 0 :
241
+ raiseSSLError()
242
+ data.setLen(read)
243
+ await socket.fd.AsyncFD.send(data, flags)
244
+
245
+ proc appeaseSsl(socket: AsyncSocket, flags: set [SocketFlag],
246
+ sslError: cint ) : owned (Future[bool ]) {.async.} =
248
247
# # Returns `true` if `socket` is still connected, otherwise `false`.
249
- let retFut = newFuture[ bool ]( " asyncnet.handleSslFailure " )
248
+ result = true
250
249
case sslError
251
- of SSL_ERROR_WANT_WRITE, SSL_ERROR_WANT_CONNECT, SSL_ERROR_WANT_ACCEPT:
252
- addWrite(socket.fd.AsyncFD, proc (sock: AsyncFD): bool =
253
- retFut.complete(true )
254
- return true
255
- )
250
+ of SSL_ERROR_WANT_WRITE:
251
+ await sendPendingSslData(socket, flags)
256
252
of SSL_ERROR_WANT_READ:
257
- addRead(socket.fd.AsyncFD, proc (sock: AsyncFD): bool =
258
- retFut.complete(true )
259
- return true
260
- )
261
- of SSL_ERROR_SYSCALL:
262
- assert flags.isDisconnectionError(osLastError())
263
- retFut.complete(false )
253
+ var data = await recv(socket.fd.AsyncFD, BufferSize, flags)
254
+ if socket.sslHandle == nil :
255
+ raiseSslHandleError()
256
+ let length = len(data)
257
+ if length > 0 :
258
+ let ret = bioWrite(socket.bioIn, cast [cstring ](addr data[0 ]), length.cint )
259
+ if ret < 0 :
260
+ raiseSSLError()
261
+ elif length == 0 :
262
+ # connection not properly closed by remote side or connection dropped
263
+ SSL_set_shutdown(socket.sslHandle, SSL_RECEIVED_SHUTDOWN)
264
+ result = false
264
265
else :
265
- raiseSSLError(" Cannot handle SSL failure." )
266
- return retFut
266
+ raiseSSLError(" Cannot appease SSL." )
267
267
268
268
template sslLoop(socket: AsyncSocket, flags: set [SocketFlag],
269
269
op: untyped ) =
@@ -274,12 +274,20 @@ when defineSsl:
274
274
ErrClearError()
275
275
# Call the desired operation.
276
276
opResult = op
277
+ let err =
278
+ if opResult < 0 :
279
+ getSslError(socket, opResult.cint )
280
+ else :
281
+ SSL_ERROR_NONE
282
+ # Send any remaining pending SSL data.
283
+ await sendPendingSslData(socket, flags)
284
+
277
285
# If the operation failed, try to see if SSL has some data to read
278
286
# or write.
279
287
if opResult < 0 :
280
- let err = getSslError (socket, flags, opResult .cint )
281
- let connected = await handleSslFailure(socket, flags, err. cint )
282
- if not connected :
288
+ let fut = appeaseSsl (socket, flags, err .cint )
289
+ yield fut
290
+ if not fut.read() :
283
291
# Socket disconnected.
284
292
if SocketFlag.SafeDisconn in flags:
285
293
opResult = 0 .cint
@@ -315,7 +323,8 @@ proc connect*(socket: AsyncSocket, address: string, port: Port) {.async.} =
315
323
discard SSL_set_tlsext_host_name(socket.sslHandle, address)
316
324
317
325
let flags = {SocketFlag.SafeDisconn}
318
- sslLoop(socket, flags, SSL_connect(socket.sslHandle))
326
+ sslSetConnectState(socket.sslHandle)
327
+ sslLoop(socket, flags, sslDoHandshake(socket.sslHandle))
319
328
320
329
template readInto(buf: pointer , size: int , socket: AsyncSocket,
321
330
flags: set [SocketFlag]) : int =
@@ -452,6 +461,7 @@ proc send*(socket: AsyncSocket, buf: pointer, size: int,
452
461
when defineSsl:
453
462
sslLoop(socket, flags,
454
463
sslWrite(socket.sslHandle, cast [cstring ](buf), size.cint ))
464
+ await sendPendingSslData(socket, flags)
455
465
else :
456
466
await send(socket.fd.AsyncFD, buf, size, flags)
457
467
@@ -465,6 +475,7 @@ proc send*(socket: AsyncSocket, data: string,
465
475
var copy = data
466
476
sslLoop(socket, flags,
467
477
sslWrite(socket.sslHandle, cast [cstring ](addr copy[0 ]), copy.len.cint ))
478
+ await sendPendingSslData(socket, flags)
468
479
else :
469
480
await send(socket.fd.AsyncFD, data, flags)
470
481
@@ -765,8 +776,9 @@ when defineSsl:
765
776
if socket.sslHandle == nil:
766
777
raiseSSLError()
767
778
768
- if SSL_set_fd(socket.sslHandle, socket.fd) != 1:
769
- raiseSSLError()
779
+ socket.bioIn = bioNew(bioSMem())
780
+ socket.bioOut = bioNew(bioSMem())
781
+ sslSetBio(socket.sslHandle, socket.bioIn, socket.bioOut)
770
782
771
783
socket.sslNoShutdown = true
772
784
@@ -783,8 +795,6 @@ when defineSsl:
783
795
##
784
796
## **Disclaimer**: This code is not well tested, may be very unsafe and
785
797
## prone to security vulnerabilities.
786
- if socket.isSsl:
787
- return
788
798
wrapSocket(ctx, socket)
789
799
790
800
case handshake
0 commit comments