mirror of
https://github.com/odin-lang/Odin.git
synced 2025-12-29 17:34:34 +00:00
181 lines
5.3 KiB
Odin
181 lines
5.3 KiB
Odin
#import "fmt.odin";
|
|
|
|
#foreign_system_library ws2 "Ws2_32.lib" when ODIN_OS == "windows";
|
|
|
|
|
|
SOCKET :: #type uint;
|
|
INVALID_SOCKET :: ~(cast(SOCKET)0);
|
|
|
|
AF :: enum i32 {
|
|
UNSPEC = 0, // unspecified
|
|
UNIX = 1, // local to host (pipes, portals)
|
|
INET = 2, // internetwork: UDP, TCP, etc.
|
|
IMPLINK = 3, // arpanet imp addresses
|
|
PUP = 4, // pup protocols: e.g. BSP
|
|
CHAOS = 5, // mit CHAOS protocols
|
|
NS = 6, // XEROX NS protocols
|
|
ISO = 7, // ISO protocols
|
|
OSI = ISO, // OSI is ISO
|
|
ECMA = 8, // european computer manufacturers
|
|
DATAKIT = 9, // datakit protocols
|
|
CCITT = 10, // CCITT protocols, X.25 etc
|
|
SNA = 11, // IBM SNA
|
|
DECnet = 12, // DECnet
|
|
DLI = 13, // Direct data link interface
|
|
LAT = 14, // LAT
|
|
HYLINK = 15, // NSC Hyperchannel
|
|
APPLETALK = 16, // AppleTalk
|
|
ROUTE = 17, // Internal Routing Protocol
|
|
LINK = 18, // Link layer interface
|
|
XTP = 19, // eXpress Transfer Protocol (no AF)
|
|
COIP = 20, // connection-oriented IP, aka ST II
|
|
CNT = 21, // Computer Network Technology
|
|
RTIP = 22, // Help Identify RTIP packets
|
|
IPX = 23, // Novell Internet Protocol
|
|
SIP = 24, // Simple Internet Protocol
|
|
PIP = 25, // Help Identify PIP packets
|
|
MAX = 26,
|
|
};
|
|
|
|
SOCK_STREAM :: 1;
|
|
SOCKET_ERROR :: -1;
|
|
IPPROTO_TCP :: 6;
|
|
AI_PASSIVE :: 0x0020;
|
|
SOMAXCONN :: 128;
|
|
|
|
SD_RECEIVE :: 0;
|
|
SD_SEND :: 1;
|
|
SD_BOTH :: 2;
|
|
|
|
WSADESCRIPTION_LEN :: 256;
|
|
WSASYS_STATUS_LEN :: 128;
|
|
WSADATA :: struct #ordered {
|
|
version: i16,
|
|
high_version: i16,
|
|
|
|
|
|
// NOTE(bill): This is x64 ordering
|
|
max_sockets: u16,
|
|
max_udp_dg: u16,
|
|
vendor_info: ^byte,
|
|
description: [WSADESCRIPTION_LEN+1]byte,
|
|
system_status: [WSASYS_STATUS_LEN+1]byte,
|
|
}
|
|
|
|
addrinfo :: struct #ordered {
|
|
flags: i32,
|
|
family: i32,
|
|
socktype: i32,
|
|
protocol: i32,
|
|
addrlen: uint,
|
|
canonname: ^u8,
|
|
addr: ^sockaddr,
|
|
next: ^addrinfo,
|
|
}
|
|
|
|
sockaddr :: struct #ordered {
|
|
family: u16,
|
|
data: [14]byte,
|
|
}
|
|
|
|
|
|
WSAStartup :: proc(version_requested: i16, data: ^WSADATA) -> i32 #foreign ws2;
|
|
WSACleanup :: proc() -> i32 #foreign ws2;
|
|
getaddrinfo :: proc(node_name, service_name: ^u8, hints: ^addrinfo, result: ^^addrinfo) -> i32 #foreign ws2;
|
|
freeaddrinfo :: proc(ai: ^addrinfo) #foreign ws2;
|
|
socket :: proc(af, type_, protocol: i32) -> SOCKET #foreign ws2;
|
|
closesocket :: proc(s: SOCKET) -> i32 #foreign ws2;
|
|
bind :: proc(s: SOCKET, name: ^sockaddr, name_len: i32) -> i32 #foreign ws2;
|
|
listen :: proc(s: SOCKET, back_log: i32) -> i32 #foreign ws2;
|
|
accept :: proc(s: SOCKET, addr: ^sockaddr, addr_len: i32) -> SOCKET #foreign ws2;
|
|
recv :: proc(s: SOCKET, buf: ^byte, len: i32, flags: i32) -> i32 #foreign ws2;
|
|
send :: proc(s: SOCKET, buf: ^byte, len: i32, flags: i32) -> i32 #foreign ws2;
|
|
shutdown :: proc(s: SOCKET, how: i32) -> i32 #foreign ws2;
|
|
WSAGetLastError :: proc() -> i32 #foreign ws2;
|
|
|
|
to_c_string :: proc(s: string) -> ^byte {
|
|
c_str := new_slice(byte, s.count+1);
|
|
assert(c_str.data != nil);
|
|
copy(c_str, cast([]byte)s);
|
|
c_str[s.count] = 0;
|
|
return c_str.data;
|
|
}
|
|
|
|
run :: proc() {
|
|
wsa: WSADATA;
|
|
res: ^addrinfo = nil;
|
|
hints: addrinfo;
|
|
s, client: SOCKET;
|
|
|
|
if WSAStartup(2 | (2 << 8), ^wsa) != 0 {
|
|
fmt.println("WSAStartup failed: ", WSAGetLastError());
|
|
return;
|
|
}
|
|
defer WSACleanup();
|
|
|
|
hints.family = cast(i32)AF.INET;
|
|
hints.socktype = SOCK_STREAM;
|
|
hints.protocol = IPPROTO_TCP;
|
|
hints.flags = AI_PASSIVE;
|
|
|
|
if getaddrinfo(nil, to_c_string("8080"), ^hints, ^res) != 0 {
|
|
fmt.println("getaddrinfo failed: ", WSAGetLastError());
|
|
return;
|
|
}
|
|
defer freeaddrinfo(res);
|
|
|
|
s = socket(res.family, res.socktype, res.protocol);
|
|
if s == INVALID_SOCKET {
|
|
fmt.println("socket failed: ", WSAGetLastError());
|
|
return;
|
|
}
|
|
defer closesocket(s);
|
|
|
|
bind(s, res.addr, cast(i32)res.addrlen);
|
|
listen(s, SOMAXCONN);
|
|
|
|
client = accept(s, nil, 0);
|
|
if client == INVALID_SOCKET {
|
|
fmt.println("socket failed: ", WSAGetLastError());
|
|
return;
|
|
}
|
|
defer closesocket(client);
|
|
|
|
html :=
|
|
`HTTP/1.1 200 OK
|
|
Connection: close
|
|
Content-type: text/html
|
|
|
|
<html>
|
|
<head>
|
|
<title>Demo Title</title>
|
|
</head>
|
|
<body>
|
|
<h1 style="color: orange;">Odin Server Demo</h1>
|
|
</body>
|
|
</html>
|
|
`;
|
|
|
|
buf: [1024]byte;
|
|
for {
|
|
bytes := recv(client, ^buf[0], cast(i32)buf.count, 0);
|
|
if bytes > 0 {
|
|
// fmt.println(buf[:bytes] as string)
|
|
bytes_sent := send(client, html.data, cast(i32)(html.count-1), 0);
|
|
if bytes_sent == SOCKET_ERROR {
|
|
fmt.println("send failed: ", WSAGetLastError());
|
|
return;
|
|
}
|
|
break;
|
|
} else if bytes == 0 {
|
|
fmt.println("Connection closing...");
|
|
break;
|
|
} else {
|
|
fmt.println("recv failed: ", WSAGetLastError());
|
|
return;
|
|
}
|
|
}
|
|
|
|
shutdown(client, SD_SEND);
|
|
}
|