summary refs log tree commit diff stats
path: root/tests/stdlib/tssl.nim
blob: 7625f369454b135b56aea623058c4572731e05e9 (plain) (blame)
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()