Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion frameworks/typev/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ WORKDIR /app
# typev VM — binary + FFI plugins (json, stdcore, stdsocket, ...). Pre-built
# (-O3 -march=x86-64-v3, static liburing) and fetched from object storage
RUN wget -q -O /tmp/typev.zip \
https://typev.s3.fr-par.scw.cloud/typev-17-05-2026.zip && \
https://typev.s3.fr-par.scw.cloud/typev-19-05-2026.zip && \
unzip -q /tmp/typev.zip -d /app && \
rm /tmp/typev.zip

Expand Down
139 changes: 5 additions & 134 deletions frameworks/typev/bundle/benchmark-code/src/ws.tc
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,9 @@
// frame echo loop: read masked client frames, echo them unmasked.

from std.socket import tcp_write, tcp_read
from std.internal.socket import socket
from response import writeBytes

// Low 32 bits mask — SHA-1 is 32-bit arithmetic; typev `uint` is 64-bit.
let local const M32: uint = 4294967295u

let local const B64: byte[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".bytes()
let local const WS_GUID: byte[] = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11".bytes()
let local const WS_101: byte[] = "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: ".bytes()
let local const WS_CRLF2: byte[] = "\r\n\r\n".bytes()
let local const WS_BAD: byte[] = "HTTP/1.1 400 Bad Request\r\nContent-Length: 0\r\nConnection: close\r\n\r\n".bytes()
Expand All @@ -36,136 +32,11 @@ local fn wsSend(fd: int, b: byte[], len: uint) -> bool {
return true
}

// 32-bit rotate-left.
local fn rotl32(x: uint, n: uint) -> uint {
return ((x << n) | (x >> (32u - n))) & M32
}

// SHA-1 of data[0..n) — returns the 20-byte digest.
local fn sha1(data: byte[], n: uint) -> byte[] {
let padded: uint = ((n + 8u) / 64u + 1u) * 64u
let msg: byte[] = new byte[](padded)
foreach i: uint in 0u, n {
msg[i] = data[i]
}
msg[n] = 128 as byte
foreach i: uint in n + 1u, padded {
msg[i] = 0 as byte
}
let bits: uint = n * 8u
foreach i: uint in 0u, 8u {
msg[padded - 1u - i] = ((bits >> (8u * i)) & 255u) as byte
}

let h0: uint = 1732584193u
let h1: uint = 4023233417u
let h2: uint = 2562383102u
let h3: uint = 271733878u
let h4: uint = 3285377520u
let w: uint[] = new uint[](80)
let blocks: uint = padded / 64u

foreach b: uint in 0u, blocks {
let base: uint = b * 64u
foreach t: uint in 0u, 16u {
let o: uint = base + t * 4u
w[t] = (((msg[o] as uint) << 24u) | ((msg[o + 1u] as uint) << 16u)
| ((msg[o + 2u] as uint) << 8u) | (msg[o + 3u] as uint)) & M32
}
foreach t: uint in 16u, 80u {
w[t] = rotl32((w[t - 3u] ^ w[t - 8u] ^ w[t - 14u] ^ w[t - 16u]) & M32, 1u)
}
let a: uint = h0
let bb: uint = h1
let c: uint = h2
let d: uint = h3
let e: uint = h4
foreach t: uint in 0u, 80u {
let f: uint = 0u
let k: uint = 0u
if t < 20u {
f = (bb & c) | ((M32 ^ bb) & d)
k = 1518500249u
} else if t < 40u {
f = bb ^ c ^ d
k = 1859775393u
} else if t < 60u {
f = (bb & c) | (bb & d) | (c & d)
k = 2400959708u
} else {
f = bb ^ c ^ d
k = 3395469782u
}
let tt: uint = (rotl32(a, 5u) + (f & M32) + e + k + w[t]) & M32
e = d
d = c
c = rotl32(bb, 30u)
bb = a
a = tt
}
h0 = (h0 + a) & M32
h1 = (h1 + bb) & M32
h2 = (h2 + c) & M32
h3 = (h3 + d) & M32
h4 = (h4 + e) & M32
}

let digest: byte[] = new byte[](20)
let hs: uint[] = [h0, h1, h2, h3, h4]
foreach i: uint in 0u, 5u {
let v: uint = hs[i]
digest[i * 4u] = ((v >> 24u) & 255u) as byte
digest[i * 4u + 1u] = ((v >> 16u) & 255u) as byte
digest[i * 4u + 2u] = ((v >> 8u) & 255u) as byte
digest[i * 4u + 3u] = (v & 255u) as byte
}
return digest
}

// Base64-encode data[0..n).
local fn b64encode(data: byte[], n: uint) -> byte[] {
let outLen: uint = ((n + 2u) / 3u) * 4u
let out: byte[] = new byte[](outLen)
let i: uint = 0u
let o: uint = 0u
while i + 3u <= n {
let x: uint = ((data[i] as uint) << 16u) | ((data[i + 1u] as uint) << 8u) | (data[i + 2u] as uint)
out[o] = B64[(x >> 18u) & 63u]
out[o + 1u] = B64[(x >> 12u) & 63u]
out[o + 2u] = B64[(x >> 6u) & 63u]
out[o + 3u] = B64[x & 63u]
i = i + 3u
o = o + 4u
}
let rem: uint = n - i
if rem == 1u {
let x: uint = (data[i] as uint) << 16u
out[o] = B64[(x >> 18u) & 63u]
out[o + 1u] = B64[(x >> 12u) & 63u]
out[o + 2u] = 61 as byte
out[o + 3u] = 61 as byte
} else if rem == 2u {
let x: uint = ((data[i] as uint) << 16u) | ((data[i + 1u] as uint) << 8u)
out[o] = B64[(x >> 18u) & 63u]
out[o + 1u] = B64[(x >> 12u) & 63u]
out[o + 2u] = B64[(x >> 6u) & 63u]
out[o + 3u] = 61 as byte
}
return out
}

// Sec-WebSocket-Accept = base64(SHA1(key + GUID)).
// Sec-WebSocket-Accept = base64(SHA1(key + GUID)) — computed natively.
local fn wsAccept(key: byte[], keyStart: uint, keyEnd: uint) -> byte[] {
let keyLen: uint = keyEnd - keyStart
let concat: byte[] = new byte[](keyLen + WS_GUID.length)
foreach i: uint in 0u, keyLen {
concat[i] = key[keyStart + i]
}
foreach i: uint in 0u, WS_GUID.length {
concat[keyLen + i] = WS_GUID[i]
}
let digest: byte[] = sha1(concat, concat.length)
return b64encode(digest, 20u)
let out: byte[] = new byte[](28)
socket.socket_ws_accept(key, keyStart, keyEnd - keyStart, out)
return out
}

// Send the 101 upgrade response; `scratch` is the caller's output buffer.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -234,4 +234,11 @@ extern socket from "stdsocket" = {
* Returns the number of complete request terminators found.
*/
fn count_http_terminators(buf: uint[], n: uint) -> uint

/**
* WebSocket Sec-WebSocket-Accept = base64(SHA1(key + GUID)), written as
* 28 bytes into `out`. Native — the whole handshake digest in one call.
* Returns 0, or -1 if out < 28.
*/
fn socket_ws_accept(key: uint[], start: uint, len: uint, out: uint[]) -> int
}
Binary file modified frameworks/typev/bundle/output.tvbc
Binary file not shown.