summary refs log tree commit diff stats
path: root/tests/stdlib/tssl.nim
diff options
context:
space:
mode:
Diffstat (limited to 'tests/stdlib/tssl.nim')
-rw-r--r--tests/stdlib/tssl.nim138
1 files changed, 138 insertions, 0 deletions
diff --git a/tests/stdlib/tssl.nim b/tests/stdlib/tssl.nim
new file mode 100644
index 000000000..1628b9326
--- /dev/null
+++ b/tests/stdlib/tssl.nim
@@ -0,0 +1,138 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  joinable: false
+  disabled: "freebsd" # see #15713
+  disabled: "openbsd" # see #15713
+  disabled: "netbsd" # see #15713
+"""
+
+import std/[net, nativesockets, assertions, typedthreads]
+
+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 abruptShutdown(port: Port) {.thread.} =
+  let clientContext = newContext(verifyMode = CVerifyNone)
+  var client = newSocket(buffered = false)
+  clientContext.wrapSocket(client)
+  client.connect("localhost", port)
+
+  discard client.recvLine()
+  client.getFd.close()
+
+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)
+      oldSigPipeHandler: Sigaction
+    if sigemptyset(ignoreAction.sa_mask) == -1:
+      raiseOSError(osLastError(), "Couldn't create an empty signal set")
+    if sigaction(SIGPIPE, ignoreAction, oldSigPipeHandler) == -1:
+      raiseOSError(osLastError(), "Couldn't ignore SIGPIPE")
+
+  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)
+    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
+
+      while true:
+        # Send data until we get EPIPE.
+        peer.send(DummyData, {})
+    except OSError:
+      discard
+    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()