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
|
#import "fmt.odin" as fmt
#foreign_system_library "Ws2_32"
SOCKET :: type uint
INVALID_SOCKET :: ~(0 as SOCKET)
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 #dll_import
WSACleanup :: proc() -> i32 #foreign #dll_import
getaddrinfo :: proc(node_name, service_name: ^u8, hints: ^addrinfo, result: ^^addrinfo) -> i32 #foreign #dll_import
freeaddrinfo :: proc(ai: ^addrinfo) #foreign #dll_import
socket :: proc(af, type_, protocol: i32) -> SOCKET #foreign #dll_import
closesocket :: proc(s: SOCKET) -> i32 #foreign #dll_import
bind :: proc(s: SOCKET, name: ^sockaddr, name_len: i32) -> i32 #foreign #dll_import
listen :: proc(s: SOCKET, back_log: i32) -> i32 #foreign #dll_import
accept :: proc(s: SOCKET, addr: ^sockaddr, addr_len: i32) -> SOCKET #foreign #dll_import
recv :: proc(s: SOCKET, buf: ^byte, len: i32, flags: i32) -> i32 #foreign #dll_import
send :: proc(s: SOCKET, buf: ^byte, len: i32, flags: i32) -> i32 #foreign #dll_import
shutdown :: proc(s: SOCKET, how: i32) -> i32 #foreign #dll_import
WSAGetLastError :: proc() -> i32 #foreign #dll_import
to_c_string :: proc(s: string) -> ^byte {
c_str := new_slice(byte, s.count+1)
assert(c_str.data != null)
copy(c_str, s as []byte)
c_str[s.count] = 0
return c_str.data
}
run :: proc() {
wsa: WSADATA
res: ^addrinfo = null
hints: addrinfo
s, client: SOCKET
if WSAStartup(2 | (2 << 8), ^wsa) != 0 {
fmt.println("WSAStartup failed: ", WSAGetLastError())
return
}
defer WSACleanup()
hints.family = AF.INET as i32
hints.socktype = SOCK_STREAM
hints.protocol = IPPROTO_TCP
hints.flags = AI_PASSIVE
if getaddrinfo(null, 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, res.addrlen as i32)
listen(s, SOMAXCONN)
client = accept(s, null, null)
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], buf.count as i32, 0)
if bytes > 0 {
// fmt.println(buf[:bytes] as string)
bytes_sent := send(client, html.data, (html.count-1) as i32, 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)
}
|