-
Notifications
You must be signed in to change notification settings - Fork 5
/
NativeSocket.lua
209 lines (162 loc) · 4.44 KB
/
NativeSocket.lua
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
local ffi = require "ffi"
local WinSock = require "WinSock_Utils"
local wsock = require "win_socket"
local SocketType = wsock.SocketType
local Protocol = wsock.Protocol
ffi.cdef[[
typedef struct {
SOCKET Handle;
int id;
} Socket_Win32;
]]
local NativeSocket = ffi.typeof("Socket_Win32");
local NativeSocket_mt = {
__gc = function(self)
-- Force close on socket
-- To ensure it's really closed
print("GC: NativeSocket: ", self.id);
self:ForceClose();
end,
__new = function(ct, handle, family, socktype, protocol, flags)
family = family or AF_INET;
socktype = socktype or SocketType.SOCK_STREAM;
protocol = protocol or 0;
flags = flags or WSA_FLAG_OVERLAPPED;
if not handle then
handle, err = WinSock.WSASocket(family, socktype, protocol, nil, 0, WSA_FLAG_OVERLAPPED);
if not handle then
return nil, err
end
end
return ffi.new(ct, handle);
end,
__index = {
--[[
Setting various options
--]]
SetKeepAlive = function(self, keepalive, delay)
local oneint = ffi.new("int[1]");
if keepalive then
oneint[0] = 1
end
local success, err = WinSock.setsockopt(self.Handle, SOL_SOCKET, SO_KEEPALIVE, oneint, ffi.sizeof(oneint))
if not success then
return false, err
end
if keepalive and delay then
oneint[0] = delay
success, err = WinSock.setsockopt(self.Handle, Protocol.IPPROTO_TCP, TCP_KEEPALIVE, oneint, ffi.sizeof(oneint))
end
return success, err
end,
SetNoDelay = function(self, nodelay)
local oneint = ffi.new("int[1]");
if nodelay then
oneint[0] = 1
end
return WinSock.setsockopt(self.Handle, Protocol.IPPROTO_TCP, TCP_NODELAY, oneint, ffi.sizeof(oneint))
end,
SetNonBlocking = function(self, nonblocking)
local oneint = ffi.new("int[1]");
if nonblocking then
oneint[0] = 1
end
return WinSock.ioctlsocket(self.Handle, FIONBIO, oneint);
end,
SetReuseAddress = function(self, reuse)
local oneint = ffi.new("int[1]");
if reuse then
oneint[0] = 1
end
return WinSock.setsockopt(self.Handle, SOL_SOCKET, SO_REUSEADDR, oneint, ffi.sizeof(oneint))
end,
--[[
Connection Management
--]]
CloseDown = function(self)
local success, err = WinSock.shutdown(self.Handle, SD_SEND)
if not success then
return false, err
end
return WinSock.closesocket(self.Handle);
end,
ForceClose = function(self)
return WinSock.closesocket(self.Handle);
end,
Shutdown = function(self, how)
how = how or SD_SEND
return WinSock.shutdown(self.Handle, how)
end,
ShutdownReceive = function(self)
return WinSock.shutdown(self.Handle, SD_RECEIVE)
end,
ShutdownSend = function(self)
return WinSock.shutdown(self.Handle, SD_SEND)
end,
--[[
Client Socket Routines
--]]
ConnectTo = function(self, address)
local name = ffi.cast("const struct sockaddr *", address)
local namelen = ffi.sizeof(address)
return WinSock.connect(self.Handle, name, namelen);
end,
--[[
Server socket routines
--]]
MakePassive = function(self, backlog)
backlog = backlog or 5
return WinSock.listen(self.Handle, backlog)
end,
Accept = function(self)
local handle, err = WinSock.accept(self.Handle, nil, nil);
if not handle then
return false, err
end
return NativeSocket(handle)
end,
Bind = function(self, addr, addrlen)
return WinSock.bind(self.Handle, addr, addrlen)
end,
--[[
Data Transport
--]]
CanReadWithoutBlocking = function(self)
local fdarray = WSAPOLLFD()
fdarray.fd = self.Handle;
fdarray.events = POLLRDNORM;
-- wait up to 15 milliseconds to see if there's
-- anything waiting
local success, err = WinSock.WSAPoll(fdarray, 1, 15);
if not success then
return false, err
end
if success > 0 then
return true;
end
return false, "wouldblock";
end,
CanWriteWithoutBlocking = function(self)
local fdarray = WSAPOLLFD()
fdarray.fd = self.Handle;
fdarray.events = POLLWRNORM;
local success, err = WinSock.WSAPoll(fdarray, 1, 15);
if not success then
return false, err
end
if ret == 0 then
return false, "wouldblock"
end
return true
end,
Send = function(self, buff, bufflen)
bufflen = bufflen or #buff
return WinSock.send(self.Handle, buff, bufflen);
end,
Receive = function(self, buff, bufflen)
return WinSock.recv(self.Handle, buff, bufflen);
end,
},
}
NativeSocket = ffi.metatype(NativeSocket, NativeSocket_mt);
return NativeSocket;