mirror of
https://github.com/nim-lang/Nim.git
synced 2026-04-19 14:00:35 +00:00
net: allow close() to ignore SSL failures due to disconnections (#15120)
* net: allow close() to ignore SSL failures due to disconnections Comes with this PR is also a SIGPIPE handling contraption. * net: don't do selectSigpipe() on macOS macOS sockets have SO_NOSIGPIPE set, so an EPIPE doesn't necessary mean that a SIGPIPE happened. * net: fix alreadyBlocked logic * net: WSAESHUTDOWN is also a disconnection error
This commit is contained in:
@@ -5,13 +5,16 @@ discard """
|
||||
import net, nativesockets
|
||||
|
||||
when defined(posix): import os, posix
|
||||
else:
|
||||
import winlean
|
||||
const SD_SEND = 1
|
||||
|
||||
when not defined(ssl):
|
||||
{.error: "This test must be compiled with -d:ssl".}
|
||||
|
||||
const DummyData = "dummy data\n"
|
||||
|
||||
proc connector(port: Port) {.thread.} =
|
||||
proc abruptShutdown(port: Port) {.thread.} =
|
||||
let clientContext = newContext(verifyMode = CVerifyNone)
|
||||
var client = newSocket(buffered = false)
|
||||
clientContext.wrapSocket(client)
|
||||
@@ -20,11 +23,16 @@ proc connector(port: Port) {.thread.} =
|
||||
discard client.recvLine()
|
||||
client.getFd.close()
|
||||
|
||||
proc main() =
|
||||
let serverContext = newContext(verifyMode = CVerifyNone,
|
||||
certFile = "tests/testdata/mycert.pem",
|
||||
keyFile = "tests/testdata/mycert.pem")
|
||||
proc notifiedShutdown(port: Port) {.thread.} =
|
||||
let clientContext = newContext(verifyMode = CVerifyNone)
|
||||
var client = newSocket(buffered = false)
|
||||
clientContext.wrapSocket(client)
|
||||
client.connect("localhost", port)
|
||||
|
||||
discard client.recvLine()
|
||||
client.close()
|
||||
|
||||
proc main() =
|
||||
when defined(posix):
|
||||
var
|
||||
ignoreAction = SigAction(sa_handler: SIG_IGN)
|
||||
@@ -34,7 +42,11 @@ proc main() =
|
||||
if sigaction(SIGPIPE, ignoreAction, oldSigPipeHandler) == -1:
|
||||
raiseOSError(osLastError(), "Couldn't ignore SIGPIPE")
|
||||
|
||||
block peer_close_without_shutdown:
|
||||
let serverContext = newContext(verifyMode = CVerifyNone,
|
||||
certFile = "tests/testdata/mycert.pem",
|
||||
keyFile = "tests/testdata/mycert.pem")
|
||||
|
||||
block peer_close_during_write_without_shutdown:
|
||||
var server = newSocket(buffered = false)
|
||||
defer: server.close()
|
||||
serverContext.wrapSocket(server)
|
||||
@@ -43,7 +55,7 @@ proc main() =
|
||||
server.listen()
|
||||
|
||||
var clientThread: Thread[Port]
|
||||
createThread(clientThread, connector, port)
|
||||
createThread(clientThread, abruptShutdown, port)
|
||||
|
||||
var peer: Socket
|
||||
try:
|
||||
@@ -60,4 +72,63 @@ proc main() =
|
||||
finally:
|
||||
peer.close()
|
||||
|
||||
when defined(posix):
|
||||
if sigaction(SIGPIPE, oldSigPipeHandler, nil) == -1:
|
||||
raiseOSError(osLastError(), "Couldn't restore SIGPIPE handler")
|
||||
|
||||
block peer_close_before_received_shutdown:
|
||||
var server = newSocket(buffered = false)
|
||||
defer: server.close()
|
||||
serverContext.wrapSocket(server)
|
||||
server.bindAddr(address = "localhost")
|
||||
let (_, port) = server.getLocalAddr()
|
||||
server.listen()
|
||||
|
||||
var clientThread: Thread[Port]
|
||||
createThread(clientThread, abruptShutdown, port)
|
||||
|
||||
var peer: Socket
|
||||
try:
|
||||
server.accept(peer)
|
||||
peer.send(DummyData)
|
||||
|
||||
joinThread clientThread
|
||||
|
||||
# Tell the OS to close off the write side so shutdown attempts will
|
||||
# be met with SIGPIPE.
|
||||
when defined(posix):
|
||||
discard peer.getFd.shutdown(SHUT_WR)
|
||||
else:
|
||||
discard peer.getFd.shutdown(SD_SEND)
|
||||
finally:
|
||||
peer.close()
|
||||
|
||||
block peer_close_after_received_shutdown:
|
||||
var server = newSocket(buffered = false)
|
||||
defer: server.close()
|
||||
serverContext.wrapSocket(server)
|
||||
server.bindAddr(address = "localhost")
|
||||
let (_, port) = server.getLocalAddr()
|
||||
server.listen()
|
||||
|
||||
var clientThread: Thread[Port]
|
||||
createThread(clientThread, notifiedShutdown, port)
|
||||
|
||||
var peer: Socket
|
||||
try:
|
||||
server.accept(peer)
|
||||
peer.send(DummyData)
|
||||
|
||||
doAssert peer.recv(1024) == "" # Get the shutdown notification
|
||||
joinThread clientThread
|
||||
|
||||
# Tell the OS to close off the write side so shutdown attempts will
|
||||
# be met with SIGPIPE.
|
||||
when defined(posix):
|
||||
discard peer.getFd.shutdown(SHUT_WR)
|
||||
else:
|
||||
discard peer.getFd.shutdown(SD_SEND)
|
||||
finally:
|
||||
peer.close()
|
||||
|
||||
when isMainModule: main()
|
||||
|
||||
Reference in New Issue
Block a user