/
ssl_connection.pony
158 lines (134 loc) · 3.45 KB
/
ssl_connection.pony
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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
use "collections"
use "net"
class SSLConnection is TCPConnectionNotify
"""
Wrap another protocol in an SSL connection.
"""
let _notify: TCPConnectionNotify
let _ssl: SSL
var _connected: Bool = false
var _expect: USize = 0
var _closed: Bool = false
let _pending: List[ByteSeq] = _pending.create()
new iso create(notify: TCPConnectionNotify iso, ssl: SSL iso) =>
"""
Initialise with a wrapped protocol and an SSL session.
"""
_notify = consume notify
_ssl = consume ssl
fun ref accepted(conn: TCPConnection ref) =>
"""
Forward to the wrapped protocol.
"""
_notify.accepted(conn)
fun ref connecting(conn: TCPConnection ref, count: U32) =>
"""
Forward to the wrapped protocol.
"""
_notify.connecting(conn, count)
fun ref connected(conn: TCPConnection ref) =>
"""
Swallow this event until the handshake is complete.
"""
_poll(conn)
fun ref connect_failed(conn: TCPConnection ref) =>
"""
Forward to the wrapped protocol.
"""
_notify.connect_failed(conn)
fun ref sent(conn: TCPConnection ref, data: ByteSeq): ByteSeq =>
"""
Pass the data to the SSL session and check for both new application data
and new destination data.
"""
let notified = _notify.sent(conn, data)
if _connected then
try
_ssl.write(notified)
else
return ""
end
else
_pending.push(notified)
end
_poll(conn)
""
fun ref sentv(conn: TCPConnection ref, data: ByteSeqIter): ByteSeqIter =>
for bytes in data.values() do
sent(conn, bytes)
end
recover val Array[ByteSeq] end
fun ref received(conn: TCPConnection ref, data: Array[U8] iso,
times: USize): Bool
=>
"""
Pass the data to the SSL session and check for both new application data
and new destination data.
"""
_ssl.receive(consume data)
_poll(conn)
true
fun ref expect(conn: TCPConnection ref, qty: USize): USize =>
"""
Keep track of the expect count for the wrapped protocol. Always tell the
TCPConnection to read all available data.
"""
_expect = _notify.expect(conn, qty)
0
fun ref closed(conn: TCPConnection ref) =>
"""
Forward to the wrapped protocol.
"""
_closed = true
_poll(conn)
_ssl.dispose()
_connected = false
_pending.clear()
_notify.closed(conn)
fun ref _poll(conn: TCPConnection ref) =>
"""
Checks for both new application data and new destination data. Informs the
wrapped protocol that is has connected when the handshake is complete.
"""
match _ssl.state()
| SSLReady =>
if not _connected then
_connected = true
_notify.connected(conn)
try
while _pending.size() > 0 do
_ssl.write(_pending.shift())
end
end
end
| SSLAuthFail =>
_notify.auth_failed(conn)
if not _closed then
conn.close()
end
return
| SSLError =>
if not _closed then
conn.close()
end
return
end
try
var received_called: USize = 0
while true do
let r = _ssl.read(_expect)
if r isnt None then
received_called = received_called + 1
_notify.received(conn,
(consume r) as Array[U8] iso^,
received_called)
else
break
end
end
end
try
while _ssl.can_send() do
conn.write_final(_ssl.send())
end
end