126126 when defineSsl:
127127 sslHandle: SslPtr
128128 sslContext: SslContext
129+ bioIn: BIO
130+ bioOut: BIO
129131 sslNoShutdown: bool
130132 domain: Domain
131133 sockType: SockType
@@ -208,7 +210,7 @@ when defineSsl:
208210 proc raiseSslHandleError =
209211 raiseSSLError (" The SSL Handle is closed/unset" )
210212
211- proc getSslError (socket: AsyncSocket , flags: set [ SocketFlag ], err: cint ): cint =
213+ proc getSslError (socket: AsyncSocket , err: cint ): cint =
212214 assert socket.isSsl
213215 assert err < 0
214216 var ret = SSL_get_error (socket.sslHandle, err.cint )
@@ -221,49 +223,47 @@ when defineSsl:
221223 return ret
222224 of SSL_ERROR_WANT_X509_LOOKUP :
223225 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 :
243227 socket.sslNoShutdown = true
244228 raiseSSLError ()
245229 else : raiseSSLError (" Unknown Error" )
246230
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 .} =
248247 # # Returns `true` if `socket` is still connected, otherwise `false`.
249- let retFut = newFuture [ bool ]( " asyncnet.handleSslFailure " )
248+ result = true
250249 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)
256252 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
264265 else :
265- raiseSSLError (" Cannot handle SSL failure." )
266- return retFut
266+ raiseSSLError (" Cannot appease SSL." )
267267
268268 template sslLoop (socket: AsyncSocket , flags: set [SocketFlag ],
269269 op: untyped ) =
@@ -274,12 +274,20 @@ when defineSsl:
274274 ErrClearError ()
275275 # Call the desired operation.
276276 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+
277285 # If the operation failed, try to see if SSL has some data to read
278286 # or write.
279287 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 () :
283291 # Socket disconnected.
284292 if SocketFlag .SafeDisconn in flags:
285293 opResult = 0 .cint
@@ -315,7 +323,8 @@ proc connect*(socket: AsyncSocket, address: string, port: Port) {.async.} =
315323 discard SSL_set_tlsext_host_name (socket.sslHandle, address)
316324
317325 let flags = {SocketFlag .SafeDisconn }
318- sslLoop (socket, flags, SSL_connect (socket.sslHandle))
326+ sslSetConnectState (socket.sslHandle)
327+ sslLoop (socket, flags, sslDoHandshake (socket.sslHandle))
319328
320329template readInto (buf: pointer , size: int , socket: AsyncSocket ,
321330 flags: set [SocketFlag ]): int =
@@ -452,6 +461,7 @@ proc send*(socket: AsyncSocket, buf: pointer, size: int,
452461 when defineSsl:
453462 sslLoop (socket, flags,
454463 sslWrite (socket.sslHandle, cast [cstring ](buf), size.cint ))
464+ await sendPendingSslData (socket, flags)
455465 else :
456466 await send (socket.fd.AsyncFD , buf, size, flags)
457467
@@ -465,6 +475,7 @@ proc send*(socket: AsyncSocket, data: string,
465475 var copy = data
466476 sslLoop (socket, flags,
467477 sslWrite (socket.sslHandle, cast [cstring ](addr copy[0 ]), copy.len.cint ))
478+ await sendPendingSslData (socket, flags)
468479 else :
469480 await send (socket.fd.AsyncFD , data, flags)
470481
@@ -765,8 +776,9 @@ when defineSsl:
765776 if socket.sslHandle == nil :
766777 raiseSSLError ()
767778
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)
770782
771783 socket.sslNoShutdown = true
772784
@@ -783,8 +795,6 @@ when defineSsl:
783795 # #
784796 # # **Disclaimer**: This code is not well tested, may be very unsafe and
785797 # # prone to security vulnerabilities.
786- if socket.isSsl:
787- return
788798 wrapSocket (ctx, socket)
789799
790800 case handshake
0 commit comments