@@ -11,6 +11,8 @@ import ./helpers/certificate
1111import lsquic/ certificateverifier
1212import lsquic/ stream
1313import lsquic/ lsquic_ffi
14+ import stew/ endians2
15+ import sequtils
1416
1517proc logging (ctx: pointer , buf: cstring , len: csize_t ): cint {.cdecl .} =
1618 echo $ buf
@@ -21,10 +23,119 @@ proc certificateCb(
2123): bool {.gcsafe .} =
2224 return derCertificates.len > 0
2325
24- suite " connections" :
25- setup:
26- let address = initTAddress (" 127.0.0.1:12345" )
26+ let address = initTAddress (" 127.0.0.1:12345" )
27+
28+ const
29+ runs = 1
30+ uploadSize = 100000 # 100KB
31+ downloadSize = 100000000 # 100MB
32+ chunkSize = 65536 # 64KB chunks like perf
33+
34+ proc runPerf (): Future [Duration ] {.async .} =
35+ let customCertVerif: CertificateVerifier =
36+ CustomCertificateVerifier .init (certificateCb)
37+ let clientTLSConfig = TLSConfig .new (
38+ testCertificate (),
39+ testPrivateKey (),
40+ @ [" test" ].toHashSet (),
41+ Opt .some (customCertVerif),
42+ )
43+ let serverTLSConfig = TLSConfig .new (
44+ testCertificate (),
45+ testPrivateKey (),
46+ @ [" test" ].toHashSet (),
47+ Opt .some (customCertVerif),
48+ )
49+ let client = QuicClient .new (clientTLSConfig)
50+ let server = QuicServer .new (serverTLSConfig)
51+ let listener = server.listen (address)
52+ let accepting = listener.accept ()
53+ let dialing = client.dial (address)
54+
55+ let outgoingConn = await dialing
56+ let incomingConn = await accepting
57+
58+ let serverDone = newFuture [void ]()
59+ let serverHandler = proc () {.async .} =
60+ let stream = await incomingConn.incomingStream ()
61+
62+ # Step 1: Read download size (8 bytes)
63+ let clientDownloadSize = await stream.read ()
64+
65+ # Step 2: Read upload data until EOF
66+ var totalBytesRead = 0
67+ while true :
68+ let chunk = await stream.read ()
69+ if chunk.len == 0 :
70+ break
71+ totalBytesRead += chunk.len
72+
73+ # Step 3: Send download data back
74+ var remainingToSend = uint64 .fromBytesBE (clientDownloadSize)
75+ while remainingToSend > 0 :
76+ let toSend = min (remainingToSend, chunkSize)
77+ try :
78+ await stream.write (newSeq [byte ](toSend))
79+ except StreamError :
80+ echo " STREAM ERROR 1"
81+ quit (1 )
82+ remainingToSend -= toSend
83+
84+ await stream.close ()
85+ serverDone.complete ()
86+
87+ # Start server handler
88+ asyncSpawn serverHandler ()
89+
90+ let startTime = Moment .now ()
91+
92+ # Step 1: Send download size, activate stream first
93+ let clientStream = await outgoingConn.openStream ()
94+ try :
95+ await clientStream.write (toSeq (downloadSize.uint64 .toBytesBE ()))
96+ except StreamError :
97+ echo " STREAM ERROR 2"
98+ quit (1 )
99+ # Step 2: Send upload data in chunks
100+ var remainingToSend = uploadSize
101+ while remainingToSend > 0 :
102+ let toSend = min (remainingToSend, chunkSize)
103+ try :
104+ await clientStream.write (newSeq [byte ](toSend))
105+ except StreamError :
106+ echo " STRAM ERROR 4"
107+ quit (1 )
108+ remainingToSend -= toSend
109+
110+ # Step 3: Close write side
111+ await clientStream.close ()
112+
113+ # Step 4: Start reading download data
114+ var totalDownloaded = 0
115+ while totalDownloaded < downloadSize:
116+ let chunk = await clientStream.read ()
117+ totalDownloaded += chunk.len
118+
119+ let duration = Moment .now () - startTime
120+
121+ await serverDone
122+
123+ await listener.stop ()
124+ await client.stop ()
125+
126+ return duration
127+
128+ suite " perf protocol simulation" :
129+ asyncTest " test" :
130+ var total: Duration
131+ for i in 0 ..< runs:
132+ let duration = await runPerf ()
133+ total += duration
134+ echo " \t run #" & $ (i + 1 ) & " duration: " & $ duration
27135
136+ echo " \t avrg duration: " & $ (total div runs)
137+
138+ suite " tests" :
28139 asyncTest " test" :
29140 let logger = struct_lsquic_logger_if (log_buf: logging)
30141 discard lsquic_set_log_level (" debug" )
@@ -69,14 +180,13 @@ suite "connections":
69180 echo " Closing client stream"
70181
71182 echo " Client closed"
72- stream.close ()
183+ await stream.close ()
73184
74185 # echo "Client aborted"
75186 # stream.abort() # Not interested in RW anything else
76187
77188 let incomingBehaviour = proc () {.async .} =
78189 try :
79- echo " HERE"
80190 let stream = await incomingConn.incomingStream ()
81191 echo " Received stream in server"
82192
@@ -91,7 +201,7 @@ suite "connections":
91201 stream.isEof
92202
93203 echo " Server closed"
94- stream.close ()
204+ await stream.close ()
95205
96206 # echo "Server aborted"
97207 # stream.abort() # Not interested in RW anything else
@@ -102,17 +212,20 @@ suite "connections":
102212
103213 discard allFutures (outgoingBehaviour (), incomingBehaviour ())
104214
105- await sleepAsync (1 .seconds)
215+ await sleepAsync (10 .seconds)
106216
107217 outgoingConn.close ()
108218 incomingConn.close ()
109219
220+ # Cannot create a stream once closed
221+ expect ConnectionError :
222+ discard await outgoingConn.openStream ()
223+
110224 await sleepAsync (1 .seconds)
111225
112226 await client.stop ()
113227 await listener.stop ()
114228
115- # TODO : perf example
116229 # TODO : destructors: (nice to have:)
117230 # - lsquic_global_cleanup() to free global resources.
118231 # - lsquic_engine_destroy(engine)
0 commit comments