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:
alaviss
2020-08-01 19:27:55 +00:00
committed by GitHub
parent 3ce32a7e40
commit c619cedd7c
3 changed files with 177 additions and 15 deletions

View File

@@ -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()