Created
March 29, 2024 05:06
-
-
Save Brian-ED/5bd3d5f54a92aff9f40a0f09f5c922a1 to your computer and use it in GitHub Desktop.
BQN's most basic client/server
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#! /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