@@ -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,104 @@ 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 serverHandler = proc () {.async .} =
59+ let stream = await incomingConn.incomingStream ()
60+
61+ # Step 1: Read download size (8 bytes)
62+ let clientDownloadSize = await stream.read ()
63+
64+ # Step 2: Read upload data until EOF
65+ var totalBytesRead = 0
66+ while true :
67+ let chunk = await stream.read ()
68+ if chunk.len == 0 :
69+ break
70+ totalBytesRead += chunk.len
71+
72+ # Step 3: Send download data back
73+ var remainingToSend = uint64 .fromBytesBE (clientDownloadSize)
74+ while remainingToSend > 0 :
75+ let toSend = min (remainingToSend, chunkSize)
76+ await stream.write (newSeq [byte ](toSend))
77+ remainingToSend -= toSend
78+
79+ stream.close ()
80+
81+ # Start server handler
82+ asyncSpawn serverHandler ()
83+
84+ let startTime = Moment .now ()
85+
86+ # Step 1: Send download size, activate stream first
87+ let clientStream = await outgoingConn.openStream ()
88+ await clientStream.write (toSeq (downloadSize.uint64 .toBytesBE ()))
89+
90+ # Step 2: Send upload data in chunks
91+ var remainingToSend = uploadSize
92+ while remainingToSend > 0 :
93+ let toSend = min (remainingToSend, chunkSize)
94+ await clientStream.write (newSeq [byte ](toSend))
95+ remainingToSend -= toSend
96+
97+ # Step 3: Close write side
98+ clientStream.close ()
99+
100+ # Step 4: Start reading download data
101+ var totalDownloaded = 0
102+ while totalDownloaded < downloadSize:
103+ let chunk = await clientStream.read ()
104+ totalDownloaded += chunk.len
105+
106+ let duration = Moment .now () - startTime
107+
108+ await listener.stop ()
109+ await client.stop ()
110+
111+ return duration
112+
113+ suite " perf protocol simulation" :
114+ asyncTest " test" :
115+ var total: Duration
116+ for i in 0 ..< runs:
117+ let duration = await runPerf ()
118+ total += duration
119+ echo " \t run #" & $ (i + 1 ) & " duration: " & $ duration
120+
121+ echo " \t avrg duration: " & $ (total div runs)
27122
123+ suite " tests" :
28124 asyncTest " test" :
29125 let logger = struct_lsquic_logger_if (log_buf: logging)
30126 discard lsquic_set_log_level (" debug" )
@@ -76,7 +172,6 @@ suite "connections":
76172
77173 let incomingBehaviour = proc () {.async .} =
78174 try :
79- echo " HERE"
80175 let stream = await incomingConn.incomingStream ()
81176 echo " Received stream in server"
82177
@@ -107,12 +202,15 @@ suite "connections":
107202 outgoingConn.close ()
108203 incomingConn.close ()
109204
205+ # Cannot create a stream once closed
206+ expect ConnectionError :
207+ discard await outgoingConn.openStream ()
208+
110209 await sleepAsync (1 .seconds)
111210
112211 await client.stop ()
113212 await listener.stop ()
114213
115- # TODO : perf example
116214 # TODO : destructors: (nice to have:)
117215 # - lsquic_global_cleanup() to free global resources.
118216 # - lsquic_engine_destroy(engine)
0 commit comments