123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180 |
- #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);
- }
|