126
126
when defineSsl:
127
127
sslHandle: SslPtr
128
128
sslContext: SslContext
129
- bioIn: BIO
130
- bioOut: BIO
131
129
sslNoShutdown: bool
132
130
domain: Domain
133
131
sockType: SockType
@@ -210,7 +208,7 @@ when defineSsl:
210
208
proc raiseSslHandleError =
211
209
raiseSSLError(" The SSL Handle is closed/unset" )
212
210
213
- proc getSslError(socket: AsyncSocket, err: cint ): cint =
211
+ proc getSslError(socket: AsyncSocket, flags: set [SocketFlag], err: cint ) : cint =
214
212
assert socket.isSsl
215
213
assert err < 0
216
214
var ret = SSL_get_error(socket.sslHandle, err.cint )
@@ -223,47 +221,49 @@ when defineSsl:
223
221
return ret
224
222
of SSL_ERROR_WANT_X509_LOOKUP:
225
223
raiseSSLError(" Function for x509 lookup has been called." )
226
- of SSL_ERROR_SYSCALL, SSL_ERROR_SSL:
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:
227
243
socket.sslNoShutdown = true
228
244
raiseSSLError()
229
245
else : raiseSSLError(" Unknown Error" )
230
246
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.} =
247
+ proc handleSslFailure(socket: AsyncSocket, flags: set [SocketFlag], sslError: cint ) : Future[bool ] =
247
248
# # Returns `true` if `socket` is still connected, otherwise `false`.
248
- result = true
249
+ let retFut = newFuture[ bool ]( " asyncnet.handleSslFailure " )
249
250
case sslError
250
- of SSL_ERROR_WANT_WRITE:
251
- await sendPendingSslData(socket, flags)
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
+ )
252
256
of SSL_ERROR_WANT_READ:
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
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 )
265
264
else :
266
- raiseSSLError(" Cannot appease SSL." )
265
+ raiseSSLError(" Cannot handle SSL failure." )
266
+ return retFut
267
267
268
268
template sslLoop(socket: AsyncSocket, flags: set [SocketFlag],
269
269
op: untyped ) =
@@ -274,20 +274,12 @@ 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
-
285
277
# If the operation failed, try to see if SSL has some data to read
286
278
# or write.
287
279
if opResult < 0 :
288
- let fut = appeaseSsl (socket, flags, err .cint )
289
- yield fut
290
- if not fut.read() :
280
+ let err = getSslError (socket, flags, opResult .cint )
281
+ let connected = await handleSslFailure(socket, flags, err. cint )
282
+ if not connected :
291
283
# Socket disconnected.
292
284
if SocketFlag.SafeDisconn in flags:
293
285
opResult = 0 .cint
@@ -323,8 +315,7 @@ proc connect*(socket: AsyncSocket, address: string, port: Port) {.async.} =
323
315
discard SSL_set_tlsext_host_name(socket.sslHandle, address)
324
316
325
317
let flags = {SocketFlag.SafeDisconn}
326
- sslSetConnectState(socket.sslHandle)
327
- sslLoop(socket, flags, sslDoHandshake(socket.sslHandle))
318
+ sslLoop(socket, flags, SSL_connect(socket.sslHandle))
328
319
329
320
template readInto(buf: pointer , size: int , socket: AsyncSocket,
330
321
flags: set [SocketFlag]) : int =
@@ -461,7 +452,6 @@ proc send*(socket: AsyncSocket, buf: pointer, size: int,
461
452
when defineSsl:
462
453
sslLoop(socket, flags,
463
454
sslWrite(socket.sslHandle, cast [cstring ](buf), size.cint ))
464
- await sendPendingSslData(socket, flags)
465
455
else :
466
456
await send(socket.fd.AsyncFD, buf, size, flags)
467
457
@@ -475,52 +465,9 @@ proc send*(socket: AsyncSocket, data: string,
475
465
var copy = data
476
466
sslLoop(socket, flags,
477
467
sslWrite(socket.sslHandle, cast [cstring ](addr copy[0 ]), copy.len.cint ))
478
- await sendPendingSslData(socket, flags)
479
468
else :
480
469
await send(socket.fd.AsyncFD, data, flags)
481
470
482
- proc acceptAddr* (socket: AsyncSocket, flags = {SocketFlag.SafeDisconn},
483
- inheritable = defined(nimInheritHandles)):
484
- owned (Future[tuple [address: string , client: AsyncSocket]]) =
485
- # # Accepts a new connection. Returns a future containing the client socket
486
- # # corresponding to that connection and the remote address of the client.
487
- # #
488
- # # If `inheritable` is false (the default), the resulting client socket will
489
- # # not be inheritable by child processes.
490
- # #
491
- # # The future will complete when the connection is successfully accepted.
492
- var retFuture = newFuture[tuple [address: string , client: AsyncSocket]](" asyncnet.acceptAddr" )
493
- var fut = acceptAddr(socket.fd.AsyncFD, flags, inheritable)
494
- fut.callback =
495
- proc (future: Future[tuple [address: string , client: AsyncFD]]) =
496
- assert future.finished
497
- if future.failed:
498
- retFuture.fail(future.readError)
499
- else :
500
- let resultTup = (future.read.address,
501
- newAsyncSocket(future.read.client, socket.domain,
502
- socket.sockType, socket.protocol, socket.isBuffered, inheritable))
503
- retFuture.complete(resultTup)
504
- return retFuture
505
-
506
- proc accept* (socket: AsyncSocket,
507
- flags = {SocketFlag.SafeDisconn}): owned (Future[AsyncSocket]) =
508
- # # Accepts a new connection. Returns a future containing the client socket
509
- # # corresponding to that connection.
510
- # # If `inheritable` is false (the default), the resulting client socket will
511
- # # not be inheritable by child processes.
512
- # # The future will complete when the connection is successfully accepted.
513
- var retFut = newFuture[AsyncSocket]("asyncnet.accept")
514
- var fut = acceptAddr(socket, flags)
515
- fut.callback =
516
- proc (future: Future[tuple[address: string , client: AsyncSocket]]) =
517
- assert future.finished
518
- if future.failed:
519
- retFut.fail(future.readError)
520
- else:
521
- retFut.complete(future.read.client)
522
- return retFut
523
-
524
471
proc recvLineInto* (socket: AsyncSocket, resString: FutureVar[string ],
525
472
flags = {SocketFlag.SafeDisconn}, maxLength = MaxLineLength) {.async.} =
526
473
# # Reads a line of data from `socket` into `resString`.
@@ -776,9 +723,8 @@ when defineSsl:
776
723
if socket.sslHandle == nil:
777
724
raiseSSLError()
778
725
779
- socket.bioIn = bioNew(bioSMem())
780
- socket.bioOut = bioNew(bioSMem())
781
- sslSetBio(socket.sslHandle, socket.bioIn, socket.bioOut)
726
+ if SSL_set_fd(socket.sslHandle, socket.fd) != 1:
727
+ raiseSSLError()
782
728
783
729
socket.sslNoShutdown = true
784
730
@@ -795,6 +741,8 @@ when defineSsl:
795
741
##
796
742
## **Disclaimer**: This code is not well tested, may be very unsafe and
797
743
## prone to security vulnerabilities.
744
+ if socket.isSsl:
745
+ return
798
746
wrapSocket(ctx, socket)
799
747
800
748
case handshake
@@ -818,6 +766,48 @@ when defineSsl:
818
766
else:
819
767
result = getPeerCertificates(socket.sslHandle)
820
768
769
+ proc acceptAddr*(socket: AsyncSocket, flags = {SocketFlag.SafeDisconn},
770
+ inheritable = defined(nimInheritHandles)):
771
+ owned (Future[tuple[address: string , client: AsyncSocket]]) {.async.} =
772
+ ## Accepts a new connection. Returns a future containing the client socket
773
+ ## corresponding to that connection and the remote address of the client.
774
+ ##
775
+ ## If `inheritable` is false (the default), the resulting client socket will
776
+ ## not be inheritable by child processes.
777
+ ##
778
+ ## The future will complete when the connection is successfully accepted.
779
+ let (address, fd) = await acceptAddr(socket.fd.AsyncFD, flags, inheritable)
780
+ let client = newAsyncSocket(fd, socket.domain, socket.sockType,
781
+ socket.protocol, socket.isBuffered, inheritable)
782
+ result = (address, client)
783
+ if socket.isSsl:
784
+ when defineSsl:
785
+ if socket.sslContext == nil:
786
+ raiseSSLError("The SSL Context is closed/unset")
787
+ wrapSocket(socket.sslContext, result .client)
788
+ if result .client.sslHandle == nil:
789
+ raiseSslHandleError()
790
+ let flags = {SocketFlag.SafeDisconn}
791
+ sslLoop(result .client, flags, SSL_accept(result .client.sslHandle))
792
+
793
+ proc accept*(socket: AsyncSocket,
794
+ flags = {SocketFlag.SafeDisconn}): owned (Future[AsyncSocket]) =
795
+ ## Accepts a new connection. Returns a future containing the client socket
796
+ ## corresponding to that connection.
797
+ ## If `inheritable` is false (the default), the resulting client socket will
798
+ ## not be inheritable by child processes.
799
+ ## The future will complete when the connection is successfully accepted.
800
+ var retFut = newFuture[AsyncSocket]("asyncnet.accept")
801
+ var fut = acceptAddr(socket, flags)
802
+ fut.callback =
803
+ proc (future: Future[tuple[address: string , client: AsyncSocket]]) =
804
+ assert future.finished
805
+ if future.failed:
806
+ retFut.fail(future.readError)
807
+ else:
808
+ retFut.complete(future.read.client)
809
+ return retFut
810
+
821
811
proc getSockOpt*(socket: AsyncSocket, opt: SOBool, level = SOL_SOCKET): bool {.
822
812
tags: [ReadIOEffect].} =
823
813
## Retrieves option `opt` as a boolean value.
0 commit comments