268 lines
7.5 KiB
LLVM
268 lines
7.5 KiB
LLVM
; ============================================================================
|
|
; udp_win.ll — UDP datagrams behind Udp.* (Windows, Winsock 2).
|
|
;
|
|
; The interface of udp.ll over ws2_32: WSAStartup on first use, a SOCKET per handle (64 bits,
|
|
; kept in the table), ioctlsocket(FIONBIO) for non-blocking reads, and the Windows
|
|
; sockaddr_in (a 16-bit family, no length byte). See udp.ll for the interface.
|
|
; ============================================================================
|
|
|
|
declare i32 @WSAStartup(i16, ptr)
|
|
declare i64 @socket(i32, i32, i32)
|
|
declare i32 @bind(i64, ptr, i32)
|
|
declare i32 @connect(i64, ptr, i32)
|
|
declare i32 @getsockname(i64, ptr, ptr)
|
|
declare i32 @ioctlsocket(i64, i32, ptr)
|
|
declare i32 @sendto(i64, ptr, i32, i32, ptr, i32)
|
|
declare i32 @recvfrom(i64, ptr, i32, i32, ptr, ptr)
|
|
declare i32 @closesocket(i64)
|
|
declare i32 @getaddrinfo(ptr, ptr, ptr, ptr)
|
|
declare void @freeaddrinfo(ptr)
|
|
declare i32 @llvm.bswap.i32(i32)
|
|
declare i16 @llvm.bswap.i16(i16)
|
|
declare void @llvm.memset.p0.i64(ptr, i8, i64, i1)
|
|
|
|
@LU_sock = internal global [16 x i64] zeroinitializer ; SOCKET + 1 per handle, 0 = free
|
|
@LU_wsa = internal global i32 0
|
|
@LU_wsadata = internal global [512 x i8] zeroinitializer
|
|
|
|
define internal void @lu_start() {
|
|
entry:
|
|
%s = load i32, ptr @LU_wsa
|
|
%ok = icmp ne i32 %s, 0
|
|
br i1 %ok, label %done, label %go
|
|
go:
|
|
%r = call i32 @WSAStartup(i16 514, ptr @LU_wsadata)
|
|
store i32 1, ptr @LU_wsa
|
|
br label %done
|
|
done:
|
|
ret void
|
|
}
|
|
|
|
; sockaddr_in (Winsock): family (u16), port (network order), addr (network order), 8 zero
|
|
define internal void @lu_addr(ptr %sa, i32 %ip, i32 %port) {
|
|
entry:
|
|
store i64 0, ptr %sa
|
|
%z8 = getelementptr i8, ptr %sa, i64 8
|
|
store i64 0, ptr %z8
|
|
store i16 2, ptr %sa
|
|
%p16 = trunc i32 %port to i16
|
|
%pn = call i16 @llvm.bswap.i16(i16 %p16)
|
|
%pp = getelementptr i8, ptr %sa, i64 2
|
|
store i16 %pn, ptr %pp
|
|
%in = call i32 @llvm.bswap.i32(i32 %ip)
|
|
%ap = getelementptr i8, ptr %sa, i64 4
|
|
store i32 %in, ptr %ap
|
|
ret void
|
|
}
|
|
|
|
define internal i64 @lu_sock_of(i32 %h) {
|
|
entry:
|
|
%lo = icmp slt i32 %h, 1
|
|
%hi = icmp sgt i32 %h, 16
|
|
%bad = or i1 %lo, %hi
|
|
br i1 %bad, label %none, label %look
|
|
look:
|
|
%i = sub i32 %h, 1
|
|
%slot = getelementptr [16 x i64], ptr @LU_sock, i32 0, i32 %i
|
|
%v = load i64, ptr %slot
|
|
%s = sub i64 %v, 1
|
|
ret i64 %s
|
|
none:
|
|
ret i64 -1
|
|
}
|
|
|
|
; open: every interface (a party's port, reached from the LAN and beyond)
|
|
define i32 @lu_udp_open(i32 %port) {
|
|
entry:
|
|
%h = call i32 @lu_udp_open_at(i32 0, i32 %port)
|
|
ret i32 %h
|
|
}
|
|
|
|
; open_local: 127.0.0.1 only - a port for this machine's own tools, never reachable from the LAN
|
|
define i32 @lu_udp_open_local(i32 %port) {
|
|
entry:
|
|
%h = call i32 @lu_udp_open_at(i32 2130706433, i32 %port)
|
|
ret i32 %h
|
|
}
|
|
|
|
; bound to one address (host order: 0 any, 0x7f000001 loopback), non-blocking, in a free slot
|
|
define internal i32 @lu_udp_open_at(i32 %ip, i32 %port) {
|
|
entry:
|
|
call void @lu_start()
|
|
%sa = alloca [16 x i8]
|
|
%arg = alloca i32
|
|
%s = call i64 @socket(i32 2, i32 2, i32 17)
|
|
%bad = icmp eq i64 %s, -1
|
|
br i1 %bad, label %fail, label %bindit
|
|
bindit:
|
|
call void @lu_addr(ptr %sa, i32 %ip, i32 %port)
|
|
%b = call i32 @bind(i64 %s, ptr %sa, i32 16)
|
|
%bb = icmp ne i32 %b, 0
|
|
br i1 %bb, label %closefail, label %nonblock
|
|
nonblock:
|
|
store i32 1, ptr %arg
|
|
; FIONBIO = 0x8004667E
|
|
%nb = call i32 @ioctlsocket(i64 %s, i32 -2147195266, ptr %arg)
|
|
br label %find
|
|
find:
|
|
%i = phi i32 [ 0, %nonblock ], [ %inext, %next ]
|
|
%done = icmp sge i32 %i, 16
|
|
br i1 %done, label %closefail, label %check
|
|
check:
|
|
%slot = getelementptr [16 x i64], ptr @LU_sock, i32 0, i32 %i
|
|
%v = load i64, ptr %slot
|
|
%free = icmp eq i64 %v, 0
|
|
br i1 %free, label %take, label %next
|
|
next:
|
|
%inext = add i32 %i, 1
|
|
br label %find
|
|
take:
|
|
%s1 = add i64 %s, 1
|
|
store i64 %s1, ptr %slot
|
|
%h = add i32 %i, 1
|
|
ret i32 %h
|
|
closefail:
|
|
%c = call i32 @closesocket(i64 %s)
|
|
br label %fail
|
|
fail:
|
|
ret i32 0
|
|
}
|
|
|
|
define i32 @lu_udp_port(i32 %h) {
|
|
entry:
|
|
%sa = alloca [16 x i8]
|
|
%len = alloca i32
|
|
store i32 16, ptr %len
|
|
%s = call i64 @lu_sock_of(i32 %h)
|
|
%bad = icmp eq i64 %s, -1
|
|
br i1 %bad, label %none, label %ask
|
|
ask:
|
|
%r = call i32 @getsockname(i64 %s, ptr %sa, ptr %len)
|
|
%rb = icmp ne i32 %r, 0
|
|
br i1 %rb, label %none, label %read
|
|
read:
|
|
%pp = getelementptr i8, ptr %sa, i64 2
|
|
%pn = load i16, ptr %pp
|
|
%ph = call i16 @llvm.bswap.i16(i16 %pn)
|
|
%p = zext i16 %ph to i32
|
|
ret i32 %p
|
|
none:
|
|
ret i32 0
|
|
}
|
|
|
|
define i32 @lu_udp_send(i32 %h, i32 %ip, i32 %port, ptr %buf, i32 %n) {
|
|
entry:
|
|
%sa = alloca [16 x i8]
|
|
%s = call i64 @lu_sock_of(i32 %h)
|
|
%bad = icmp eq i64 %s, -1
|
|
br i1 %bad, label %none, label %go
|
|
go:
|
|
call void @lu_addr(ptr %sa, i32 %ip, i32 %port)
|
|
%r = call i32 @sendto(i64 %s, ptr %buf, i32 %n, i32 0, ptr %sa, i32 16)
|
|
ret i32 %r
|
|
none:
|
|
ret i32 -1
|
|
}
|
|
|
|
define i32 @lu_udp_recv(i32 %h, ptr %buf, i32 %cap, ptr %ipport) {
|
|
entry:
|
|
%sa = alloca [16 x i8]
|
|
%len = alloca i32
|
|
store i32 16, ptr %len
|
|
%s = call i64 @lu_sock_of(i32 %h)
|
|
%bad = icmp eq i64 %s, -1
|
|
br i1 %bad, label %none, label %go
|
|
go:
|
|
%r = call i32 @recvfrom(i64 %s, ptr %buf, i32 %cap, i32 0, ptr %sa, ptr %len)
|
|
%got = icmp sgt i32 %r, 0
|
|
br i1 %got, label %from, label %none
|
|
from:
|
|
%ap = getelementptr i8, ptr %sa, i64 4
|
|
%an = load i32, ptr %ap
|
|
%ah = call i32 @llvm.bswap.i32(i32 %an)
|
|
store i32 %ah, ptr %ipport
|
|
%pp = getelementptr i8, ptr %sa, i64 2
|
|
%pn = load i16, ptr %pp
|
|
%ph = call i16 @llvm.bswap.i16(i16 %pn)
|
|
%p = zext i16 %ph to i32
|
|
%o = getelementptr i8, ptr %ipport, i64 4
|
|
store i32 %p, ptr %o
|
|
ret i32 %r
|
|
none:
|
|
ret i32 0
|
|
}
|
|
|
|
define void @lu_udp_close(i32 %h) {
|
|
entry:
|
|
%s = call i64 @lu_sock_of(i32 %h)
|
|
%bad = icmp eq i64 %s, -1
|
|
br i1 %bad, label %done, label %go
|
|
go:
|
|
%c = call i32 @closesocket(i64 %s)
|
|
%i = sub i32 %h, 1
|
|
%slot = getelementptr [16 x i64], ptr @LU_sock, i32 0, i32 %i
|
|
store i64 0, ptr %slot
|
|
br label %done
|
|
done:
|
|
ret void
|
|
}
|
|
|
|
; addrinfo (Winsock): flags, family, socktype, protocol (i32 each), addrlen (size_t at 16),
|
|
; then canonname, addr, next (pointers at 24, 32, 40)
|
|
define i32 @lu_udp_resolve(ptr %name) {
|
|
entry:
|
|
call void @lu_start()
|
|
%hints = alloca [48 x i8]
|
|
%res = alloca ptr
|
|
store ptr null, ptr %res
|
|
call void @llvm.memset.p0.i64(ptr %hints, i8 0, i64 48, i1 false)
|
|
%fam = getelementptr i8, ptr %hints, i64 4
|
|
store i32 2, ptr %fam
|
|
%st = getelementptr i8, ptr %hints, i64 8
|
|
store i32 2, ptr %st
|
|
%r = call i32 @getaddrinfo(ptr %name, ptr null, ptr %hints, ptr %res)
|
|
%rb = icmp ne i32 %r, 0
|
|
br i1 %rb, label %none, label %read
|
|
read:
|
|
%ai = load ptr, ptr %res
|
|
%isnull = icmp eq ptr %ai, null
|
|
br i1 %isnull, label %none, label %addr
|
|
addr:
|
|
%sap = getelementptr i8, ptr %ai, i64 32
|
|
%sa = load ptr, ptr %sap
|
|
%ap = getelementptr i8, ptr %sa, i64 4
|
|
%an = load i32, ptr %ap
|
|
%ah = call i32 @llvm.bswap.i32(i32 %an)
|
|
call void @freeaddrinfo(ptr %ai)
|
|
ret i32 %ah
|
|
none:
|
|
ret i32 0
|
|
}
|
|
|
|
define i32 @lu_udp_local_ip() {
|
|
entry:
|
|
call void @lu_start()
|
|
%sa = alloca [16 x i8]
|
|
%len = alloca i32
|
|
%s = call i64 @socket(i32 2, i32 2, i32 17)
|
|
%bad = icmp eq i64 %s, -1
|
|
br i1 %bad, label %none, label %go
|
|
go:
|
|
call void @lu_addr(ptr %sa, i32 134744072, i32 53)
|
|
%c = call i32 @connect(i64 %s, ptr %sa, i32 16)
|
|
%cb = icmp ne i32 %c, 0
|
|
br i1 %cb, label %closenone, label %ask
|
|
ask:
|
|
store i32 16, ptr %len
|
|
%r = call i32 @getsockname(i64 %s, ptr %sa, ptr %len)
|
|
%ap = getelementptr i8, ptr %sa, i64 4
|
|
%an = load i32, ptr %ap
|
|
%ah = call i32 @llvm.bswap.i32(i32 %an)
|
|
%x = call i32 @closesocket(i64 %s)
|
|
ret i32 %ah
|
|
closenone:
|
|
%y = call i32 @closesocket(i64 %s)
|
|
br label %none
|
|
none:
|
|
ret i32 0
|
|
}
|