1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
|
discard """
joinable: false
disabled: "freebsd"
disabled: "openbsd"
"""
# disabled: pending bug #15713
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 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()
|