Skip to content

Instantly share code, notes, and snippets.

@Brian-ED
Created March 29, 2024 05:06
Show Gist options
  • Save Brian-ED/5bd3d5f54a92aff9f40a0f09f5c922a1 to your computer and use it in GitHub Desktop.
Save Brian-ED/5bd3d5f54a92aff9f40a0f09f5c922a1 to your computer and use it in GitHub Desktop.
BQN's most basic client/server
#! /usr/bin/env bqn
# linux only.
# Only tested on one 64 bit machine.
# a lot of macros were manually resolved
# by using the c version of this: https://gist.github.com/jdah/08eb80c74b13176027c08cbf48b239c9
# and `clang -E server.c > test.c`, and finally looking
# through test.c and finding the actual values of macros.
# I have no idea if the macros are machine-independant or not
# the size of some ints could be different on 32 bit machines.
# Types of sockets
socket_type ← {
sock_stream ⇐ 1 # Sequenced, reliable, connection-based byte streams
sock_dgram ⇐ 2 # Connectionless, unreliable datagrams of fixed maximum length.
sock_raw ⇐ 3 # Raw protocol interface.
sock_rdm ⇐ 4 # Reliably-delivered messages.
sock_seqpacket ⇐ 5 # Sequenced, reliable, connection-based, datagrams of fixed maximum length.
sock_dccp ⇐ 6 # Datagram Congestion Control Protocol.
sock_packet ⇐ 10 # Linux specific way of getting packets at the dev level. For writing rarp and other similar things on the user level.
# Flags to be ORed into the type parameter of socket and socketpair and used for the flags parameter of paccept.
sock_cloexec ⇐ 02000000 # Atomically set close-on-exec flag for the new descriptor(s).
sock_nonblock ⇐ 00004000 # Atomically mark descriptor(s) as non-blocking.
}
pf_inet ← 2 # IP protocol family.
af_inet ← pf_inet
sockaddr_in ← "{u16,u16,{u32},[8]u8}"
# {
# sin_family # u16
# sin_port # u16
# sin_addr # {u32}
# sin_zero # u8[8]
# }
sockaddr_storage ← "{u16,[118]u8,u64}"
# {
# ss_family # u16
# __ss_padding # u8[(128 - (sizeof (unsigned short int)) - sizeof (unsigned long int))]
# __ss_align # u64
# }
ni_maxhost‿ni_maxserv ← 1025‿32
# sizeof(addr) ← 16
sockaddr ← "{u16,[14]u8}"
socketPath ← "/usr/lib/x86_64-linux-gnu/libsocket++.so.1"
socket ← socketPath •FFI "i32"‿"socket"‿"i32"‿"i32"‿"i32"
htons ← socketPath •FFI "u16"‿"htons"‿">u16"
send ← socketPath •FFI "i64"‿"send"‿"i32"‿"*u8"‿"u64"‿"i32"
connect ← socketPath •FFI "i32"‿"connect"‿"i32"‿"*{u16,u16,{u32},[8]u8}"‿"u32"
close ← socketPath •FFI "i32"‿"close"‿">i32"
recv ← socketPath •FFI "i64"‿"recv"‿"i32"‿"&u8"‿"u64"‿"i32"
accept ← socketPath •FFI "i32"‿"accept"‿"i32"‿"*"‿"&u32" # THIS POINTER MAY NEED TO BE A REFERENCE
bind ← socketPath •FFI "i32"‿"bind"‿"i32"‿"*"‿"u32"
getsockname ← socketPath •FFI "i32"‿"getsockname"‿"i32"‿"*"‿"&u32" # THIS POINTER MAY NEED TO BE A REFERENCE
ntohs ← socketPath •FFI "u16"‿"ntohs"‿">u16"
listen ← socketPath •FFI "i32"‿"listen"‿"i32"‿"i32"
inet_pton ← socketPath •FFI "i32"‿"inet_pton"‿"i32"‿"*u8"‿"&u32"
snprintf ← @•FFI "i32"‿"snprintf"‿"&u8"‿"u64"‿"*u8"
calloc ← @•FFI "*"‿"calloc"‿">u64"
Server ← {𝕊:
# create socket
fd ← Socket⟨pf_inet, socket_type.sock_stream, 0⟩
# bind to open port
addr_len ← 16
addr ← (CAlloc addr_len).Cast sockaddr_in
addr.Write ⟨af_inet,0,⟨0⟩,8⥊0⟩
"bind error:"!¬Bind⟨fd, addr, 16⟩
# read port
Getsockname⟨fd, addr, ⟨addr_len⟩⟩
•Out "server is on port "∾ •Repr ⌊ Ntohs 1⊑addr.Read 0
"listen error:"!¬Listen⟨fd, 1⟩
# accept incoming connection
caddr_len ← 128
caddr ← CAlloc caddr_len
⟨cfd⋄·⟩ ← Accept⟨fd, caddr, ⟨caddr_len⟩⟩
# read from client with recv!
⟨err ⋄ buf⟩ ← Recv ⟨cfd, 1024⥊0, 1024, 0⟩
# print without looking
•Out "client says:"
•Out " "∾@+buf
Close cfd
Close fd
}
Client ← {𝕊port:
fd ← Socket⟨pf_inet, socket_type.sock_stream, 0⟩
# connect to local machine at specified port
addrstr ← 0⥊˜ni_maxhost + ni_maxserv + 1
⟨· ⋄ addrstr⟩ ↩ Snprintf⟨addrstr, ≠addrstr, @-˜@∾˜"127.0.0.1:"∾•Repr port⟩
# parse into address
⟨·⋄⟨sin_addr⟩⟩ ← Inet_pton⟨af_inet, addrstr, ⟨0⟩⟩
addr_len ← 16
# connect to server
"connect error:"!¬Connect⟨fd, ⟨⟨af_inet ⋄ Htons port ⋄ ⟨sin_addr⟩ ⋄ 8⥊0⟩⟩, addr_len⟩
# say hey with send!
msg ← "the client says hello!"∾@
Send⟨fd, msg-@, ≠msg, 0⟩
Close fd
}
⊢◶{𝕊
"not enough args!"!2=≠•args
port ← •ParseFloat 1⊑•args
Client port
}‿Server "client"≢⊑1↑•args
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment