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