gm_litesocket - LuaSocket is back!

Here it is - simple socket module with required minimum of functions, working in beta!
This module is single-threaded, which means it’s up to you to check sockets for incoming data. Example of that is shown below.
Full support for binary strings included in Beta module.
Supports both TCP and UDP.

[release]


Download:

Non-Beta:
Windows
Linux
Sources
Beta:
Windows
Sources
[/release]

[release]


FAQ:

Q: This is single-threaded - it means it will block when I call recv()!
A: You can set timeout to 0 and then call recv(). If there is no data, it will just return, instantly, without blocking.

Q: Does this support sending/receiving of strings with nulls in them?
A: Yes. This is new feature of Beta’s Lua interface, and it all works pretty much as you would expect it to work.

Q: How do I decode data from strings with nulls?
A: If data format is fixed - use pattern matching. You can read about it at lua.org . Otherwise (I have no idea what it can be, if it is your own server-to-server communication - why not use strings without nulls?) - write your own binary reader in lua. Of course it will be slower that C++ binary reader, but I’m not sure if you need it.

Q: Is there any way to use hostnames with this module?
A: No, sorry. You might want to use another module to get IPs of hostnames, or just hardcode IPs.
[/release]
[release]


Manual for Beta module:

[lua]–Global functions:

–creates a new socket
–protocol is either IPPROTO_TCP or IPPROTO_UDP
socket = Socket(protocol)

–functions in socket metatable:

–accept incoming connection
–currently ignores timeout and may block
–returns socket
socket = s:Accept()

–binds a socket to ip and port
–ip may be “*” and port 0 to let the system to choose any free port
s:Bind(ip,port)

–closes socket
–no more reading or writing should be done on closed sockets
s:Close()

–connects socket to ip/port
–should be used only on tcp sockets
–this DOES NOT resolve hostnames. You can connect only to IP.
–ignores timeout, may block
s:Connect(ip,port)

–sets timeout for Recv functions
–by default timeout is 0, it means do not wait for any data if there is no data
s:SetTimeout(seconds)

–send string to connected server
–should be used only with tcp sockets
–returns nil/false and error message or true
success, error = s:Send(data)

–send string to specified ip/port
–returns nil/false and error message or true
success, error = s:SendTo(data,ip,port)

–receive data from connected peer
–should be used only on TCP sockets
–size is size of receive buffer, default is 8192 bytes
–if an error occurs (including timeout), data is nil and err is error
data, err = s:Recv([size])

–receive data and return ip/port where it came from
–recommended for UDP sockets
–size is size of receive buffer, default is 8192 bytes
–if an error occurs (including timeout), data is nil and ip is error
data, ip, port = s:RecvFrom([size])
[/lua]

All errors returned are strings describing error, i.e. “timeout” or “connection refused”.
[/release]

[release]


Examples:

Source Server Query with callbacks, for Beta:
[lua]–this code requires players on server to work
–because it uses think
local querystring = string.char(255):rep(4)…“TSource Engine Query\0”
local wait_table = {}
local callback_table = {}

hook.Add(“Think”,“CheckReadySourceQueries”,function()
for k,v in pairs(wait_table) do
local d, ip, port = v:RecvFrom()
if d then
local servername, map, game, gamemode, nump, maxp, dedi, os, pwd, secure, ver = d:match("\015(%Z+)%z(%Z+)%z(%Z+)%z(%Z+)%z…(.)(.).(.)(.)(.)(.)(%Z+)") --If you are wondering what is match and what are all these %Zs for, go read lua manual
nump, maxp, pwd, secure = string.byte(nump), string.byte(maxp), string.byte(pwd), string.byte(secure)
callback_table[v](ip,port,servername, map, game, gamemode, nump, maxp, dedi, os, pwd, secure, ver)
v:Close()
wait_table[k] = nil
callback_table[v] = nil
end
end
end)

function QuerySourceServer(ip,port,callback)
local nsc = Socket(IPPROTO_UDP)
nsc:Bind("*",0)
nsc:SendTo(querystring,ip,port)
wait_table[nsc] = nsc
callback_table[nsc] = callback
end

QuerySourceServer(“88.191.102.162”,27015,print)
–output:
–lua_openscript test.lua
–Running script test.lua…
–88.191.102.162 27015 Python1320 and CapsAdmin’s Server gm_construct_flatgrass_v5 garrysmod QBox 12 15 d l 0 1 1.0.0.94[/lua]
[/release]

It’s annoying when people put down other people’s work to make their own look better. Threading and queuing are not useless functions, and when you use OOSocks right you don’t crash.

I have no problem with you writing this. Infact all you had to do was download the old OOSocks code before it was multi threaded.

But I don’t understand why you take no pride in your work. This entire thing looks like a copy paste job from other peoples work, shoved together and forced to work.

Take some pride in your work, make something clear, styled and be professional.

[editline]03:54PM[/editline]

Reading your code, you are overwriting unallocated memory. You have logic errors.

Your claiming it doesn’t crash. This is only so because you have been lucky.

Was OOSocks not multithreaded?
Yes, around 25% of this is copypasted from Microsoft help or linux man pages. Basically all socket modules (non-threaded of course) consist of the same - select, recv, send, etc.

Where exactly am I overwriting unallocated memory? Where do I have logic errors?
And it does not crash. Recv is being called each frame, Send is called quite often (TCP), no crashes. Absolutely. Crashes may occur if you try to connect udp socket, but they never happen if you are using sockets as they are supposed to be used.

So… it crashes if you use it wrong? Just like the useless, horrible OOSocks?

I can confirm that OOSocks was crashing on changelevel while active TCP connection, that module does not crash in same case.

I didn’t call OOSocks “useless” and “horrible”, but in my opinion socket module does not need all the features OOSocks has. And it crashes randomly, not if I use it incorrectly.

So instead of reporting bugs you reinvented the wheel. Gg.

Nice to know you’re trying, but to call it bugged without at least attempting to get it fixed is stupid.

Yes, I reinvented the wheel. Simple round wheel. Without any unnecessary gyroscopes, breaking parts and sharp corners. I’m trying to keeps sockets simple, I don’t need any threading and bugs randomly popping out of nowhere.

Fair enough that you wrote something that works for you, however if you had bugs you should have reported them. How would you feel if people discovered bugs in yours, and rather than reported them just went and made their own saying yours was shit? That’s effectively what you are saying, and your attitude is appalling.

Glad this works for you, but just because something is more complicated doesn’t mean it has to be buggy by its very definition as you seem to imply. Simple things have just as much opportunity to be buggy.

[editline]06:56PM[/editline]

You also say the OOSocks has useless functions. Useless for you, yes. Not for other people.

I reported bugs. I posted code and dumps that crashed server. This bug got fixed just now.

GM13 please?

This may be the least advanced socket module but definitely quickest/easiest to port.

EDIT: Thanks :slight_smile:

I’ve updated this module for Beta.
RecvTable functions are now gone, since Beta supports proper string handling, and Send functions don’t use length argument anymore. Also, I’ve removed GetHostByName since it didn’t work anyway, and there are better DNS modules out there.
Feel free to use. And report bugs, I haven’t done much testing for Beta, but I can tell for sure that TCP part works fine.

‘require(“litesocket”)’ alone seems to crash me, running latest Gmod Beta (Sept 21st, Beta Update 34). Tried on a fresh install, with gmsv_litesocket.dll in lua/bin/. Is there some new way to load modules?

Thanks for updating!

Apparently I’ve missed one of Garry’s interface updates, so it really crashed. I updated it, now works fine on my dedicated server. Here is the link (it’s the same, just redownload) https://dl.dropbox.com/u/3679614/gmsv_litesocket.dll

Awesome, thanks! Works great for my IRC integration plugin!

Not really a big deal, since its solveable in lua by hooking into Shutdown, but your module does not auto disconnect sockets. If it were possible to pickup the socket reference after a map change, it’d probably be useful for some people to have it not auto disconnect, but otherwise sockets should probably close with lua.

Beta V39 changed binary module headers again (probably as part of the luajit addition), so this isn’t loading again.

Thanks for maintaining this!

I’ve updated module for latest GMod Beta with LuaJIT.
As for sockets closing on shutdown, it’s broken at the moment. You should close them manually in Shutdown hook.

Could you make the sockets truly non blocking?



		int flags = fcntl(sc, F_GETFL, 0);
		fcntl(sc, F_SETFL, flags | O_NONBLOCK);


Otherwise I can’t use tcp :Accept() since it would block.

Also could we have the accepted ip/port returned also on the :Accept function?

hey there, could you explane me how to use the udp ?
somehow it wont work for me, even if i just want to receive one line of data,…

thats the testing snippet:


require('litesocket')

socket = Socket(IPPROTO_UDP)
ip = "localhost"
port = 7777
socket:Accept()
socket:SetTimeout(0)
socket:Bind(ip, port)

data, ip, port = socket:RecvFrom()

print(data)
print(socket)

prints:


nil
socket{udp,unbound}
R

now if i dont bind the port i need with socket:Bind("*", 0)
thats printed out:


nil
socket{udp,bound}


i really need a working udp lib, thanks in advance for answers!

numu