/usr/share/picolisp/src64/net.l is in picolisp 15.11-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 | # 30oct15abu
# (c) Software Lab. Alexander Burger
# (port ['T] 'cnt|(cnt . cnt) ['var]) -> cnt
(code 'doPort 2)
push X
push Y
push Z
ld X E
ld Y (E CDR) # Y on args
ld Z SOCK_STREAM # Type defaults to TCP
ld E (Y) # Eval first arg
eval
cmp E TSym # 'T'?
if eq # Yes
ld Z SOCK_DGRAM # Type UDP
ld Y (Y CDR) # Eval next arg
ld E (Y)
eval
end
cc socket(AF_INET6 Z 0) # Create socket
nul4 # OK?
js ipSocketErrX # No
ld C A # Keep socket in C
call closeOnExecAX
ld A 0 # Socket option "off"
st4 (Buf) # Store into 'optval'
cc setsockopt(C IPPROTO_IPV6 IPV6_V6ONLY Buf 4) # "Not only IPv6" option
nul4 # OK?
js ipV6onlyErrX # No
ld B 0 # Clear socket structure
mset (Addr) SOCKADDR_IN6
ld A AF_INET6
st2 (Addr SIN6_FAMILY)
ld B 0 # Clear sin6_addr
mset (Addr SIN6_ADDR) 16 # "::" (16 null-bytes)
cnt E # Single port-argument?
if nz # Yes
shr E 4 # Port zero?
if nz # No
ld A 1 # Socket option "on"
st4 (Buf) # Store into 'optval'
cc setsockopt(C SOL_SOCKET SO_REUSEADDR Buf 4) # "Reuse socket" option
nul4 # OK?
js ipReuseaddrErrX # No
end
push 0 # <S> No range limit
else
atom E # Port range?
jnz argErrEX # No
ld A (E CDR) # Get second port
ld E (E) # First port
shr E 4 # Range start
shr A 4 # Normalize second port
push A # <S> Range limit
end
do
cc htons(E) # Convert port to network order
st2 (Addr SIN6_PORT) # Store as port
cc bind(C Addr SOCKADDR_IN6) # Try to bind socket
nul4 # OK?
while s # No
inc E # Next port in range
cmp E (S) # Exceeded limit?
if gt # Yes
cc close(C) # Close socket
jmp ipBindErrX
end
loop
add S I # Drop range limit
cmp Z SOCK_STREAM # TCP socket?
if eq # Yes
cc listen(C 5) # Mark as server socket
nul4 # OK?
if s # No
cc close(C) # Close socket
jmp ipListenErrX
end
end
ld Z C # Keep socket in Z
ld Y (Y CDR) # Eval 'var'
ld E (Y)
eval
cmp E Nil # Any?
if ne # Yes
ld A SOCKADDR_IN6 # Structure size
st4 (Buf) # Store into 'namelen'
cc getsockname(Z Addr Buf) # Get socket name
nul4 # OK?
if s # No
cc close(Z) # Close socket
jmp ipGetsocknameErrX
end
call needVarEX # Need variable
ld2 (Addr SIN6_PORT) # Get port
cc ntohs(A) # Convert to host byte order
shl A 4 # Make short number
or A CNT
ld (E) A # Store in variable
end
ld E Z # Get socket
shl E 4 # Make short number
or E CNT
pop Z
pop Y
pop X
ret
(code 'tcpAcceptA_FE)
ld E A # Save socket in E
call nonblockingA_A # Set socket to non-blocking
push A # <S> Old socket status flags
ld C 200 # Maximally 20 seconds
do
ld A SOCKADDR_IN6 # Structure size
st4 (Buf) # Store into 'addrlen'
cc accept(E Addr Buf) # Accept connection
nul4 # OK?
if ns # Yes
xchg A (S) # Save new socket, retrieve flags
cc fcntl(E F_SETFL A) # Restore socket status flags
? (<> *TargetOS "Linux") # Non-Linux (BSD sockets)?
cc fcntl((S) F_SETFL 0) # Yes: Set new socket to non-blocking
=
sub S (%% INET6_ADDRSTRLEN) # Allocate name buffer
cc inet_ntop(AF_INET6 &(Addr SIN6_ADDR) S INET6_ADDRSTRLEN)
ld E S
call mkStrE_E # Make transient symbol
ld (Adr) E # Store in '*Adr'
add S (%% INET6_ADDRSTRLEN) # Drop buffer
ld A (S) # Get socket
call initInFileA_A # Init input file
ld A (S)
call initOutFileA_A # and output file
pop E # Get new socket
shl E 4 # Make short number
or E CNT # Return 'nz'
ret
end
cc usleep(100000) # Sleep 100 milliseconds
dec C # Done?
until z # Yes
cc fcntl(E F_SETFL pop) # Restore socket status flags
eq # Return 'z'
ret
# (accept 'cnt) -> cnt | NIL
(code 'doAccept 2)
push X
ld X E
ld E ((E CDR)) # Eval socket descriptor
call evCntEX_FE
ld A E # Accept connection
call tcpAcceptA_FE # OK?
ldz E Nil # No
pop X
ret
# (listen 'cnt1 ['cnt2]) -> cnt | NIL
(code 'doListen 2)
push X
push Y
push Z
ld X E
ld Y (E CDR) # Y on args
call evCntXY_FE # Eval 'cnt1'
ld Z E # Keep socket descriptor in Z
ld Y (Y CDR) # Next arg
ld E (Y)
eval # Eval 'cnt2'
cmp E Nil # Given?
ldz Y -1 # No timeout
if ne # Yes
call xCntEX_FE # Milliseconds
ld Y E
end
do
ld C Z # Socket descriptor
ld E Y # Milliseconds
call waitFdCEX_A # Wait for events
ld E Nil # Preload NIL
null A # Timeout?
while nz # No
ld A Z # Accept connection
call tcpAcceptA_FE # OK?
until nz # Yes
pop Z
pop Y
pop X
ret
# (host 'any) -> sym
(code 'doHost 2)
push Z
ld E ((E CDR)) # Eval IP address
call evSymE_E
sub S I # 'lst' buffer
call bufStringE_SZ # Write to stack buffer
cc getaddrinfo(S 0 0 Z) # Get address info
ld S Z # Drop buffer
pop Z # Get 'lst' into Z
ld E Nil # Preset return value
nul4 # Address valid?
if z # Yes
sub S (%% NI_MAXHOST) # <S> Hostname buffer
ld C Z # Get 'lst'
do
nulp C # Any?
while nz # Yes
ld4 (C AI_ADDRLEN)
cc getnameinfo((C AI_ADDR) A S NI_MAXHOST 0 0 NI_NAMEREQD)
nul4 # OK?
if z # Yes
ld E S
call mkStrE_E # Make transient symbol
break T
end
ld C (C AI_NEXT) # Try next
loop
add S (%% NI_MAXHOST) # Drop buffer
cc freeaddrinfo(Z)
end
pop Z
ret
# (connect 'any1 'any2) -> cnt | NIL
(code 'doConnect 2)
push X
push Y
push Z
ld X E
ld Y (E CDR) # Y on args
call evSymY_E # Eval host
ld Y (Y CDR) # Next arg
ld C SOCK_STREAM
call serverCEY_FE # Found server?
if z # Yes
ld Z E # Keep list in Z
do
nulp E # Any?
while nz # Yes
ld4 (E AI_SOCKTYPE) # Create socket
ld C A
ld4 (E AI_FAMILY)
cc socket(A C 0)
nul4 # OK?
if ns # Yes
ld Y A # Keep socket in Y
ld4 (E AI_ADDRLEN)
cc connect(Y (E AI_ADDR) A) # Try to connect
nul4 # OK?
if z # Yes
ld A Y
call closeOnExecAX
ld A Y # Get socket
call initInFileA_A # Init input file
ld A Y
call initOutFileA_A # and output file
ld E Y # Return socket
shl E 4 # Make short number
or E CNT
jmp 80
end
cc close(Y) # Close socket
end
ld E (E AI_NEXT) # Try next
loop
ld E Nil # Return NIL
80 cc freeaddrinfo(Z)
end
pop Z
pop Y
pop X
ret
(code 'serverCEY_FE)
link
push E # <L I> Host
link
sub S (%% ADDRINFO) # <S> Hints
ld B 0 # Clear hints
mset (S) ADDRINFO
ld A AF_UNSPEC # Accept IPv4 and IPv6
st4 (S AI_FAMILY) # Store into 'ai_family'
ld A C # Get type
st4 (S AI_SOCKTYPE) # Store into 'ai_socktype'
call evSymY_E # Eval service
call bufStringE_SZ # Write to stack buffer
push Z # Save pointer to hints
ld E (L I) # Get host
call bufStringE_SZ # Write to stack buffer
sub S I # 'lst' buffer
cc getaddrinfo(&(S I) &(Z I) (Z) S) # Get address info
pop E # Into 'lst'
ld S (Z) # Clean up
add S (%% ADDRINFO)
nul4 # Address valid -> 'z'
ldnz E Nil
drop
ret
# (udp 'any1 'any2 'any3) -> any
# (udp 'cnt) -> any
(code 'doUdp 2)
push X
push Y
push Z
sub S UDPMAX # Allocate udp buffer
ld X E
ld Y (E CDR) # Y on args
ld E (Y) # Eval first
eval # 'any1' or 'cnt'
ld Y (Y CDR) # Next arg?
atom Y
if nz # No
call xCntEX_FE # 'cnt'
cc recv(E S UDPMAX 0) # Receive message
null A # OK?
js 10 # No
ld Z S # Buffer pointer
lea (BufEnd) (Z UDPMAX) # Calculate buffer end
ld (GetBinZ_FB) getUdpZ_FB # Set binary read function
ld (Extn) (ExtN) # Set external symbol offset
call binReadZ_FE # Read item?
if lt # No
10 ld E Nil # Return NIL
end
else
call xSymE_E # Host
ld C SOCK_DGRAM
call serverCEY_FE # Found server?
if z # Yes
ld X E # Keep list in X
ld Y (Y CDR) # Next arg
ld E (Y) # Eval 'any2'
eval
ld Y E # Keep return value in Y
ld Z S # Buffer pointer
lea (BufEnd) (Z UDPMAX) # Calculate buffer end
ld (PutBinBZ) putUdpBZ # Set binary print function
ld (Extn) (ExtN) # Set external symbol offset
call binPrintEZ # Print item
ld E X # Get list
do
nulp E # Any?
while nz # Yes
ld4 (E AI_SOCKTYPE) # Create socket
ld C A
ld4 (E AI_FAMILY)
cc socket(A C 0)
nul4 # OK?
if ns # Yes
ld C A # Keep socket in C
sub Z S # Data length
ld4 (E AI_ADDRLEN)
cc sendto(C S Z 0 (E AI_ADDR) A) # Transmit message
cc close(C) # Close socket
ld E Y # Get return value
jmp 80
end
ld E (E AI_NEXT) # Try next
loop
ld E Nil # Return NIL
80 cc freeaddrinfo(X)
end
end
add S UDPMAX # Drop buffer
pop Z
pop Y
pop X
ret
(code 'getUdpZ_FB 0)
cmp Z (BufEnd) # End of buffer data?
jeq retLt # Yes: Return 'lt'
ld B (Z) # Next byte
add Z 1 # (gt)
ret
(code 'putUdpBZ 0)
cmp Z (BufEnd) # End of buffer data?
jeq udpOvflErr # Yes
ld (Z) B # Store byte
inc Z # Increment pointer
ret
# vi:et:ts=3:sw=3
|