@@ -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,118 @@ 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+ try :
77+ await stream.write (newSeq [byte ](toSend))
78+ except StreamError :
79+ echo " STREAM ERROR 1"
80+ quit (1 )
81+ remainingToSend -= toSend
82+
83+ stream.close ()
84+
85+ # Start server handler
86+ asyncSpawn serverHandler ()
87+
88+ let startTime = Moment .now ()
89+
90+ # Step 1: Send download size, activate stream first
91+ let clientStream = await outgoingConn.openStream ()
92+ try :
93+ await clientStream.write (toSeq (downloadSize.uint64 .toBytesBE ()))
94+ except StreamError :
95+ echo " STREAM ERROR 2"
96+ quit (1 )
97+ # Step 2: Send upload data in chunks
98+ var remainingToSend = uploadSize
99+ while remainingToSend > 0 :
100+ let toSend = min (remainingToSend, chunkSize)
101+ try :
102+ await clientStream.write (newSeq [byte ](toSend))
103+ except StreamError :
104+ echo " STRAM ERROR 4"
105+ quit (1 )
106+ remainingToSend -= toSend
107+
108+ # Step 3: Close write side
109+ clientStream.close ()
110+
111+ # Step 4: Start reading download data
112+ var totalDownloaded = 0
113+ while totalDownloaded < downloadSize:
114+ let chunk = await clientStream.read ()
115+ totalDownloaded += chunk.len
116+
117+ let duration = Moment .now () - startTime
118+
119+ # TODO : use waitgroup
120+ await sleepAsync (5 .seconds)
121+
122+ await listener.stop ()
123+ await client.stop ()
124+
125+ return duration
126+
127+ suite " perf protocol simulation" :
128+ asyncTest " test" :
129+ var total: Duration
130+ for i in 0 ..< runs:
131+ let duration = await runPerf ()
132+ total += duration
133+ echo " \t run #" & $ (i + 1 ) & " duration: " & $ duration
27134
135+ echo " \t avrg duration: " & $ (total div runs)
136+
137+ suite " tests" :
28138 asyncTest " test" :
29139 let logger = struct_lsquic_logger_if (log_buf: logging)
30140 discard lsquic_set_log_level (" debug" )
@@ -76,7 +186,6 @@ suite "connections":
76186
77187 let incomingBehaviour = proc () {.async .} =
78188 try :
79- echo " HERE"
80189 let stream = await incomingConn.incomingStream ()
81190 echo " Received stream in server"
82191
@@ -107,12 +216,15 @@ suite "connections":
107216 outgoingConn.close ()
108217 incomingConn.close ()
109218
219+ # Cannot create a stream once closed
220+ expect ConnectionError :
221+ discard await outgoingConn.openStream ()
222+
110223 await sleepAsync (1 .seconds)
111224
112225 await client.stop ()
113226 await listener.stop ()
114227
115- # TODO : perf example
116228 # TODO : destructors: (nice to have:)
117229 # - lsquic_global_cleanup() to free global resources.
118230 # - lsquic_engine_destroy(engine)
0 commit comments