-- LuaSocket-API like and BNet-API like source code -- Author: Matías "Starkkz" Hermosilla -- License: MIT local ffi = require("ffi") local bit = require("bit") local sock, errno = unpack(require("bnet_h")) local C = ffi.C local SOMAXCONN = 128 local INVALID_SOCKET = -1 local INADDR_ANY = 0 local INADDR_NONE = 0XFFFFFFFF local AF_INET = 2 local SOCK_STREAM = 1 local SOCK_DGRAM = 2 local SOCKET_ERROR = -1 local SD_RECEIVE = 0 local SD_SEND = 1 local SD_BOTH = 2 local TCP_TIMEOUT = 255 + 256 ^ 2 + 256 ^ 3 + 256 ^ 4 local UDP_TIMEOUT = 255 + 256 ^ 2 + 256 ^ 3 + 256 ^ 4 local socket = { _VERSION = "LuaSocket 2.0.2", _BNETVERSION = "0.0.3", _DEBUG = false } local FIONREAD local ioctl_, fd_lib if ffi.os == "Windows" then FIONREAD = 0x4004667F local WSADATA = ffi.new("WSADATA") sock.WSAStartup(0x101, WSADATA) ffi.C.atexit(sock.WSACleanup) fd_lib = { FD_CLR = function (fd, set) for i = 0, set.fd_count do if set.fd_array[i] == fd then while i < set.fd_count-1 do set.fd_array[i] = set.fd_array[i + 1] i = i + 1 end set.fd_count = set.fd_count - 1 break end end end, FD_SET = function (fd, set) local Index = 0 for i = 0, set.fd_count do if set.fd_array[i] == fd then Index = i break end end if Index == set.fd_count then if set.fd_count < 64 then set.fd_array[Index] = fd set.fd_count = set.fd_count + 1 end end end, FD_ZERO = function (set) set.fd_count = 0 end, FD_ISSET = sock.__WSAFDIsSet, } function ioctl_(s, cmd, argp) return sock.ioctlsocket(s, cmd, argp) end else sock = ffi.C fd_lib = { FD_CLR = function (fd, set) for i = 0, set.fd_count do if set.fd_array[i] == fd then while i < set.fd_count-1 do set.fd_array[i] = set.fd_array[i + 1] i = i + 1 end set.fd_count = set.fd_count - 1 break end end end, FD_SET = function (fd, set) local Index = 0 for i = 0, set.fd_count do if set.fd_array[i] == fd then Index = i break end end if Index == set.fd_count then if set.fd_count < 64 then set.fd_array[Index] = fd set.fd_count = set.fd_count + 1 end end end, FD_ZERO = function (set) set.fd_count = 0 end, FD_ISSET = function (fd, set) for i = 0, set.fd_count do if set.fd_array[i] == fd then return true end end return false end, } function ioctl_(s, cmd, argp) return sock.ioctl(s, cmd, argp) end if ffi.os == "MacOS" then FIONREAD = 0x4004667F else --if ffi.os == "Linux" then FIONREAD = 0x0000541B end end local NULL = ffi.new("void *") local closesocket_ if ffi.os == "Windows" then function closesocket_(s) return sock.closesocket(s) end else function closesocket_(s) return sock.close(s) end end local function bind_(socket, addr_type, port) local sa = ffi.new("struct sockaddr_in") if addr_type ~= AF_INET then return -1 end ffi.fill(sa, 0, ffi.sizeof(sa)) sa.sin_family = addr_type sa.sin_addr.s_addr = sock.htonl(INADDR_ANY) sa.sin_port = sock.htons(port) local _sa = ffi.cast("struct sockaddr *", sa) return sock.bind(socket, _sa, ffi.sizeof(sa)) end local function gethostbyaddr_(addr, addr_len, addr_type) local e = sock.gethostbyaddr(addr, addr_len, addr_type) if e == NULL then return nil end return e.h_name end local function gethostbyname_(name) local e = sock.gethostbyname(name) if e == NULL then return nil end return e.h_addr_list, e.h_addrtype, e.h_length end local function connect_(socket, addr, addr_type, addr_len, port) local sa = ffi.new("struct sockaddr_in") if addr_type == AF_INET then ffi.fill(sa, 0, ffi.sizeof(sa)) sa.sin_family = addr_type sa.sin_port = sock.htons(port) ffi.copy(sa.sin_addr, addr, addr_len) local Addr = ffi.cast("struct sockaddr *", sa) return sock.connect(socket, Addr, ffi.sizeof(sa)) end return SOCKET_ERROR end local function select_(n_read, r_socks, n_write, w_socks, n_except, e_socks, timeout) local r_set = ffi.new("fd_set") local w_set = ffi.new("fd_set") local e_set = ffi.new("fd_set") r_socks = r_socks or {} w_socks = w_socks or {} e_socks = e_socks or {} local n = -1 fd_lib.FD_ZERO(r_set) for i = 0, n_read do if r_socks[i] then fd_lib.FD_SET(r_socks[i], r_set) if r_socks[i] > n then n = r_socks[i] end end end fd_lib.FD_ZERO(w_set) for i = 0, n_write do if w_socks[i] then fd_lib.FD_SET(w_socks[i], w_set) if w_socks[i] > n then n = w_socks[i] end end end fd_lib.FD_ZERO(e_set) for i = 0, n_except do if e_socks[i] then fd_lib.FD_SET(e_socks[i], e_set) if e_socks[i] > n then n = e_socks[i] end end end local TimevalPtr if timeout < 0 then TimevalPtr = ffi.new("struct timeval[0]") else local Timeval = ffi.new("struct timeval", {tv_sec = timeout / 1000, tv_usec = (timeout % 1000) / 1000}) TimevalPtr = ffi.new("struct timeval [1]", Timeval) end local r = sock.select(n + 1, r_set, w_set, e_set, TimevalPtr) if r < 0 then return r end for i = 0, n_read do if r_socks[i] and not fd_lib.FD_ISSET(r_socks[i], r_set) then r_socks[i] = nil end end for i = 0, n_write do if w_socks[i] and not fd_lib.FD_ISSET(w_socks[i], w_set) then w_rocks[i] = nil end end for i = 0, n_except do if e_socks[i] and not fd_lib.FD_ISSET(e_socks[i], e_set) then e_socks[i] = nil end end return r end local function sendto_(socket, buf, size, flags, dest_ip, dest_port) local sa = ffi.new("struct sockaddr_in") ffi.fill(sa, 0, ffi.sizeof(sa)) sa.sin_family = AF_INET sa.sin_addr.s_addr = sock.inet_addr(dest_ip) sa.sin_port = sock.htons(dest_port) return sock.sendto(socket, buf, size, flags, ffi.cast("struct sockaddr *", sa), ffi.sizeof(sa)) end local function recvfrom_(socket, buf, size, flags) local sa = ffi.new("struct sockaddr_in") ffi.fill(sa, 0, ffi.sizeof(sa)) local sasize = ffi.new("int[1]", ffi.sizeof(sa)) local count = sock.recvfrom(socket, buf, size, flags, ffi.cast("struct sockaddr *", sa), sasize) return count, sock.inet_ntoa(sa.sin_addr), sock.ntohs(sa.sin_port) end local IO_DONE = 0 local IO_TIMEOUT = -1 local IO_CLOSED = -2 local function io_strerror(err) if err == IO_DONE then return "closed" elseif err == IO_CLOSED then return "closed" elseif err == IO_TIMEOUT then return "timeout" end return "unknown error" end local socket_strerror if ffi.os == "Windows" then local WSAEINTR = 10004 local WSAEACCES = 10013 local WSAEFAULT = 10014 local WSAEINVAL = 10022 local WSAEMFILE = 10024 local WSAEWOULDBLOCK = 10035 local WSAEINPROGRESS = 10036 local WSAEALREADY = 10037 local WSAENOTSOCK = 10038 local WSAEDESTADDRREQ = 10039 local WSAEMSGSIZE = 10040 local WSAEPROTOTYPE = 10041 local WSAENOPROTOOPT = 10042 local WSAEPROTONOSUPPORT = 10043 local WSAESOCKTNOSUPPORT = 10044 local WSAEOPNOTSUPP = 10045 local WSAEPFNOSUPPORT = 10046 local WSAEAFNOSUPPORT = 10047 local WSAEADDRINUSE = 10048 local WSAEADDRNOTAVAIL = 10049 local WSAENETDOWN = 10050 local WSAENETUNREACH = 10051 local WSAENETRESET = 10052 local WSAECONNABORTED = 10053 local WSAECONNRESET = 10054 local WSAENOBUFS = 10055 local WSAEISCONN = 10056 local WSAENOTCONN = 10057 local WSAESHUTDOWN = 10058 local WSAETIMEDOUT = 10060 local WSAECONNREFUSED = 10061 local WSAEHOSTDOWN = 10064 local WSAEHOSTUNREACH = 10065 local WSAEPROCLIM = 10067 local WSASYSNOTREADY = 10091 local WSAVERNOTSUPPORTED = 10092 local WSANOTINITIALISED = 10093 local WSAEDISCON = 10101 local WSAHOST_NOT_FOUND = 11001 local WSATRY_AGAIN = 11002 local WSANO_RECOVERY = 11003 local WSANO_DATA = 11004 local function wstrerror(err) if err == WSAEINTR then return "Interrupted function call" elseif err == WSAEACCES then return "Permission denied" elseif err == WSAEFAULT then return "Bad address" elseif err == WSAEINVAL then return "Invalid argument" elseif err == WSAEMFILE then return "Too many open files" elseif err == WSAEWOULDBLOCK then return "Resource temporarily unavailable" elseif err == WSAEINPROGRESS then return "Operation now in progress" elseif err == WSAEALREADY then return "Operation already in progress" elseif err == WSAENOTSOCK then return "Socket operation on nonsocket" elseif err == WSAEDESTADDRREQ then return "Destination address required" elseif err == WSAEMSGSIZE then return "Message too long" elseif err == WSAEPROTOTYPE then return "Protocol wrong type for socket" elseif err == WSAENOPROTOOPT then return "Bad protocol option" elseif err == WSAEPROTONOSUPPORT then return "Protocol not supported" elseif err == WSAESOCKTNOSUPPORT then return "Socket type not supported" elseif err == WSAEOPNOTSUPP then return "Operation not supported" elseif err == WSAEPFNOSUPPORT then return "Protocol family not supported" elseif err == WSAEAFNOSUPPORT then return "Address family not supported by protocol family" elseif err == WSAEADDRINUSE then return "Address already in use" elseif err == WSAEADDRNOTAVAIL then return "Cannot assign requested address" elseif err == WSAENETDOWN then return "Network is down" elseif err == WSAENETUNREACH then return "Network is unreachable" elseif err == WSAENETRESET then return "Network dropped connection on reset" elseif err == WSAECONNABORTED then return "Software caused connection abort" elseif err == WSAECONNRESET then return "Connection reset by peer" elseif err == WSAENOBUFS then return "No buffer space available" elseif err == WSAEISCONN then return "Socket is already connected" elseif err == WSAENOTCONN then return "Socket is not connected" elseif err == WSAESHUTDOWN then return "Cannot send after socket shutdown" elseif err == WSAETIMEDOUT then return "Connection timed out" elseif err == WSAECONNREFUSED then return "Connection refused" elseif err == WSAEHOSTDOWN then return "Host is down" elseif err == WSAEHOSTUNREACH then return "No route to host" elseif err == WSAEPROCLIM then return "Too many processes" elseif err == WSASYSNOTREADY then return "Network subsystem is unavailable" elseif err == WSAVERNOTSUPPORTED then return "Winsock.dll version out of range" elseif err == WSANOTINITIALISED then return "Successful WSAStartup not yet performed" elseif err == WSAEDISCON then return "Graceful shutdown in progress" elseif err == WSAHOST_NOT_FOUND then return "Host not found" elseif err == WSATRY_AGAIN then return "Nonauthoritative host not found" elseif err == WSANO_RECOVERY then return "Nonrecoverable name lookup error" elseif err == WSANO_DATA then return "Valid name, no data record of requested type" end return "Unknown error" end local WSAEADDRINUSE = 10048 local WSAECONNREFUSED = 10061 local WSAEISCONN = 10056 local WSAECONNABORTED = 10053 local WSAECONNRESET = 10054 local WSAETIMEDOUT = 10060 function socket_strerror(err) if err <= 0 then return io_strerror(err) elseif err == WSAEADDRINUSE then return "address already in use" elseif err == WSAECONNREFUSED then return "connection refused" elseif err == WSAEISCONN then return "already connected" elseif err == WSAEACCES then return "permission denied" elseif err == WSAECONNABORTED then return "closed" elseif err == WSAECONNRESET then return "closed" elseif err == WSAETIMEDOUT then return "timeout" end return wstrerror(err) end else function socket_strerror(err) if err <= 0 then return io_strerror(err) elseif err == EADDRINUSE then return "address already in use" elseif err == EISCONN then return "already connected" elseif err == EACCES then return "permission denied" elseif err == ECONNREFUSED then return "connection refused" elseif err == ECONNABORTED then return "closed" elseif err == ECONNRESET then return "closed" elseif err == ETIMEDOUT then return "timeout" end return ffi.string(C.strerror(err)) end end function socket.CountHostIPs(Host) assert(Host) local Addresses, AdressType, AddressLength = gethostbyname_(Host) if Addresses == NULL or AddressType ~= AF_INET or AddressLength ~= 4 then return 0 end local Count = 0 repeat Count = Count + 1 until Address[Count] == NULL return Count end function socket.IntIP(IP) local ServerIP = sock.inet_addr(IP) if ServerIP == INADDR_NONE then local Addresses, AddressType, AddressLength = gethostbyname_(IP) if Addresses == NULL or AddressType ~= AF_INET or AddressLength ~= 4 then return 0 end local PAddress = Addresses[0] if PAddress == NULL then return 0 end return sock.htonl(bit.bor(bit.lshift(PAddress[3], 24), bit.lshift(PAddress[2], 16), bit.lshift(PAddress[1], 8), PAddress[0])) end return 0 end function socket.StringIP(IP) assert(IP) local HTONL = sock.htonl(IP) local Addr = ffi.new("struct in_addr") Addr.s_addr = HTONL local NTOA = sock.inet_ntoa(Addr) return ffi.string(NTOA) end local TUDPStream = {} local UDP = {__index = TUDPStream} ffi.metatype("struct TUDPStream", UDP) function UDP:__gc() self:Close() end function TUDPStream:ReadByte() local n = ffi.new("byte [1]"); self:Read(n, 1) return n[0] end function TUDPStream:ReadShort() local n = ffi.new("byte [2]"); self:Read(n, 2) return n[0] + n[1] * 256 end function TUDPStream:ReadInt() local n = ffi.new("byte [4]"); self:Read(n, 4) return n[0] + n[1] * 256 + n[2] * 65536 + n[3] * 16777216 end function TUDPStream:ReadLong() local n = ffi.new("byte [8]"); self:Read(n, 8) local Value = ffi.new("unsigned long") local LongByte = ffi.new("unsigned long", 256) for i = 0, 7 do Value = Value + ffi.new("unsigned long", n[i]) * LongByte ^ i end return Value end function TUDPStream:ReadLine() local Buffer = "" local Size = 0 while self:Size() > 0 do local Char = self:ReadByte() if Char == 10 or Char == 0 then break end if Char ~= 13 then Buffer = Buffer .. char(Char) end end return Buffer end function TUDPStream:ReadString(Length) if Length > 0 then local Buffer = ffi.new("byte [?]", Length); self:Read(Buffer, Length) return ffi.string(Buffer, Length) end return "" end function TUDPStream:WriteByte(n) local q = ffi.new("byte [1]") q[0] = bit.band(n, 0xff) return self:Write(q, 1) end function TUDPStream:WriteShort(n) local q = ffi.new("byte [2]") q[0] = bit.band(n, 0xff); n = bit.rshift(n - q[0], 8) q[1] = bit.band(n, 0xff) return self:Write(q, 2) end function TUDPStream:WriteInt(n) local q = ffi.new("byte [4]") q[0] = bit.band(n, 0xff); n = bit.rshift(n - q[0], 8) q[1] = bit.band(n, 0xff); n = bit.rshift(n - q[1], 8) q[2] = bit.band(n, 0xff); n = bit.rshift(n - q[2], 8) q[3] = bit.band(n, 0xff) return self:WriteBytes(q, 4) end function TUDPStream:WriteLong(n) local q = ffi.new("byte [8]") q[0] = bit.band(n, 0xff); n = bit.rshift(n - q[0], 8) q[1] = bit.band(n, 0xff); n = bit.rshift(n - q[1], 8) q[2] = bit.band(n, 0xff); n = bit.rshift(n - q[2], 8) q[3] = bit.band(n, 0xff); n = bit.rshift(n - q[3], 8) q[4] = bit.band(n, 0xff); n = bit.rshift(n - q[4], 8) q[5] = bit.band(n, 0xff); n = bit.rshift(n - q[5], 8) q[6] = bit.band(n, 0xff); n = bit.rshift(n - q[6], 8) q[7] = bit.band(n, 0xff) return self:WriteBytes(q, 8) end function TUDPStream:WriteLine(String) local Line = String .. "\n" return self:Write(Line, #Line) end function TUDPStream:WriteString(String) return self:Write(String, #String) end function TUDPStream:Read(Buffer, Size) local Size = math.min(Size, self.RecvSize) if Size > 0 then ffi.copy(Buffer, self.RecvBuffer, Size) if Size < self.RecvSize then self.RecvBuffer = self.RecvBuffer + Size self.RecvSize = self.RecvSize - Size else self.RecvBuffer = ffi.new("byte [0]") self.RecvSize = 0 end end return Size end function TUDPStream:Write(Buffer, Size) local NewBuffer = ffi.new("byte [?]", self.SendSize + Size) if self.SendSize > 0 then ffi.copy(NewBuffer, self.SendBuffer, self.SendSize) ffi.copy(NewBuffer + self.SendSize, Buffer, Size) self.SendBuffer = NewBuffer self.SendSize = self.SendSize + Size else ffi.copy(NewBuffer, Buffer, Size) self.SendBuffer = NewBuffer self.SendSize = Size end return Size end function TUDPStream:Size() return self.RecvSize end function TUDPStream:Eof() if self.Socket == INVALID_SOCKET then return true end return self.RecvSize == 0 end function TUDPStream:Close() if self.Socket ~= INVALID_SOCKET then local Error = sock.shutdown(self.Socket, SD_BOTH) if Error ~= 0 then return false, socket_strerror(Error) end local Error = closesocket_(self.Socket) if Error ~= 0 then return false, socket_strerror(Error) end self.Socket = INVALID_SOCKET end end function TUDPStream:Timeout(Recv) assert(Recv) if Recv >= 0 then self.Timeout = ffi.new("unsigned int", Recv or 0) end end function TUDPStream:SendTo(IP, Port) if self.Socket == INVALID_SOCKET or self.SendSize == 0 then return false end if select_(0, nil, 1, {self.Socket}, 0, nil, 0) ~= 1 then return false end if not Port or Port == 0 then Port = self.MessagePort end if not IP then IP = ffi.string(self.MessageIP) end local Result = sendto_(self.Socket, ffi.string(self.SendBuffer, self.SendSize), self.SendSize, 0, IP, Port) if Result == SOCKET_ERROR or Result == 0 then return false end if Result == self.SendSize then self.SendBuffer = ffi.new("byte [0]") self.SendSize = 0 return true end local NewBuffer = ffi.new("byte [?]", self.SendSize - Result) ffi.copy(NewBuffer, self.SendBuffer + Result, self.SendSize - Result) self.SendBuffer = NewBuffer self.SendSize = self.SendSize - Result return true end function TUDPStream:RecvFrom() if self.Socket == INVALID_SOCKET then return false end if select_(1, {self.Socket}, 0, nil, 0, nil, self.Timeout) ~= 1 then return false end local Size = ffi.new("int [1]") if ioctl_(self.Socket, FIONREAD, Size) == SOCKET_ERROR then return false end Size = Size[0] if Size <= 0 then return false end if self.RecvSize > 0 then local NewBuffer = ffi.new("byte [?]", self.RecvSize + Size) ffi.copy(NewBuffer, self.RecvBuffer, self.RecvSize) self.RecvBuffer = NewBuffer else self.RecvBuffer = ffi.new("byte [?]", Size) end local Result, MessageIP, MessagePort = recvfrom_(self.Socket, self.RecvBuffer + self.RecvSize, Size, 0) if Result == SOCKET_ERROR or Result == 0 then return false end self.MessageIP = MessageIP self.MessagePort = MessagePort self.RecvSize = self.RecvSize + Result return MessageIP, MessagePort end function TUDPStream:MsgIP() return ffi.string(self.MessageIP) end function TUDPStream:MsgPort() return tonumber(self.messagePort) end function TUDPStream:GetIP() return ffi.string(self.LocalIP) end function TUDPStream:GetPort() return tonumber(self.LocalPort) end function socket.CreateUDPStream(Port) local Port = Port or 0 local Socket = sock.socket(AF_INET, SOCK_DGRAM, 0) if Socket == INVALID_SOCKET then return nil end if bind_(Socket, AF_INET, Port) == SOCKET_ERROR then local BindError = errno() local Error = sock.shutdown(Socket, SD_BOTH) if Error ~= 0 then return nil, socket_strerror(Error) end local Error = closesocket_(Socket) if Error ~= 0 then return nil, socket_strerror(Error) end return nil, socket_strerror(BindError) end local Address = ffi.new("struct sockaddr_in") local Addr = ffi.cast("struct sockaddr *", Address) local SizePtr = ffi.new("int [1]") SizePtr[0] = ffi.sizeof(Address) if sock.getsockname(Socket, Addr, SizePtr) == SOCKET_ERROR then local GetSockNameError = errno() local Error = sock.shutdown(Socket, SD_BOTH) if Error ~= 0 then return nil, socket_strerror(Error) end local Error = closesocket_(Socket) if Error ~= 0 then return nil, socket_strerror(Error) end return nil, socket_strerror(GetSockNameError) end local LocalIP = ffi.string(sock.inet_ntoa(Address.sin_addr)) local LocalPort = tonumber(sock.ntohs(Address.sin_port)) local Stream = ffi.new("struct TUDPStream") Stream.Socket = Socket Stream.LocalIP = ffi.new("char [?]", #LocalIP, LocalIP) Stream.LocalPort = ffi.new("unsigned short", LocalPort) Stream.Timeout = ffi.new("unsigned int", UDP_TIMEOUT or 0) Stream.UDP = true Stream.SendBuffer = ffi.new("byte [0]") Stream.RecvBuffer = ffi.new("byte [0]") return Stream end local TTCPStream = {} local TCP = {__index = TTCPStream} ffi.metatype("struct TTCPStream", TCP) function TCP:__gc() self:Close() end function TTCPStream:ReadByte() local n = ffi.new("byte [1]"); self:Read(n, 1) return n[0] end function TTCPStream:ReadShort() local n = ffi.new("byte [2]"); self:Read(n, 2) return n[0] + n[1] * 256 end function TTCPStream:ReadInt() local n = ffi.new("byte [4]"); self:Read(n, 4) return n[0] + n[1] * 256 + n[2] * 65536 + n[3] * 16777216 end function TTCPStream:ReadLong() local n = ffi.new("byte [8]"); self:Read(n, 8) local Value = ffi.new("unsigned long") local LongByte = ffi.new("unsigned long", 256) for i = 0, 7 do Value = Value + ffi.new("unsigned long", n[i]) * LongByte ^ i end return Value end function TTCPStream:ReadLine() local Buffer = "" local Size = 0 while self:Size() > 0 do local Char = self:ReadByte() if Char == 10 or Char == 0 then break end if Char ~= 13 then Buffer = Buffer .. char(Char) end end return Buffer end function TTCPStream:ReadString(Length) if Length > 0 then local Buffer = ffi.new("byte [?]", Length); self:Read(Buffer, Length) return ffi.string(Buffer, Length) end return "" end function TTCPStream:WriteByte(n) local q = ffi.new("byte [1]", bit.band(n, 0xff)) return self:Write(q, 1) end function TTCPStream:WriteShort(n) local q = ffi.new("byte [2]") q[0] = bit.band(n, 0xff); n = bit.rshift(n - q[0], 8) q[1] = bit.band(n, 0xff) return self:Write(q, 2) end function TTCPStream:WriteInt(n) local q = ffi.new("byte [4]") q[0] = bit.band(n, 0xff); n = bit.rshift(n - q[0], 8) q[1] = bit.band(n, 0xff); n = bit.rshift(n - q[1], 8) q[2] = bit.band(n, 0xff); n = bit.rshift(n - q[2], 8) q[3] = bit.band(n, 0xff) return self:WriteBytes(q, 4) end function TTCPStream:WriteLong(n) local q = ffi.new("byte [8]") q[0] = bit.band(n, 0xff); n = bit.rshift(n - q[0], 8) q[1] = bit.band(n, 0xff); n = bit.rshift(n - q[1], 8) q[2] = bit.band(n, 0xff); n = bit.rshift(n - q[2], 8) q[3] = bit.band(n, 0xff); n = bit.rshift(n - q[3], 8) q[4] = bit.band(n, 0xff); n = bit.rshift(n - q[4], 8) q[5] = bit.band(n, 0xff); n = bit.rshift(n - q[5], 8) q[6] = bit.band(n, 0xff); n = bit.rshift(n - q[6], 8) q[7] = bit.band(n, 0xff) return self:WriteBytes(q, 8) end function TTCPStream:WriteLine(String) local Line = String.."\n" return self:Write(Line, #Line) end function TTCPStream:WriteString(String) return self:Write(String, #String) end function TTCPStream:SetTimeout(Read, Accept) assert(Read) assert(Accept) if Read < 0 then Read = 0 end if Accept < 0 then Accept = 0 end self.Timeouts = ffi.new("unsigned int [2]", Read, Accept) end function TTCPStream:Read(Buffer, Size) if self.Socket == INVALID_SOCKET then return 0 end if select_(1, {self.Socket}, 0, nil, 0, nil, self.Timeouts[0]) ~= 1 then return 0 end local Result = sock.recv(self.Socket, Buffer, Size, 0) if Result == SOCKET_ERROR then return 0 end self.Received = self.Received + Result return Result end function TTCPStream:Write(Buffer, Size) if self.Socket == INVALID_SOCKET then return 0 end if select_(1, nil, 1, {self.Socket}, 0, nil, 0) ~= 1 then return 0 end local Result = sock.send(self.Socket, Buffer, Size, 0) if Result == SOCKET_ERROR then return 0 end self.Sent = self.Sent + Result return Result end function TTCPStream:Size() local Size = ffi.new("int [1]") if ioctl_(self.Socket, FIONREAD, Size) == SOCKET_ERROR then return nil, socket_strerror(errno()) end return Size[0] end function TTCPStream:Connected() if self.Socket == INVALID_SOCKET then return false end return select_(1, {self.Socket}, 0, nil, 0, nil, 0) == 0 end function TTCPStream:Eof() return self:Size() == 0 end function TTCPStream:Close() local Error = sock.shutdown(self.Socket, SD_BOTH) if Error ~= 0 then return nil, socket_strerror(Error) end local Error = closesocket_(self.Socket) if Error ~= 0 then return nil, socket_strerror(Error) end self.Socket = INVALID_SOCKET return true end function TTCPStream:GetIP() return ffi.string(self.LocalIP) end function TTCPStream:GetPort() return tonumber(self.LocalPort) end function socket.OpenTCPStream(Server, ServerPort, LocalPort) assert(Server) assert(ServerPort) local LocalPort = LocalPort or 0 local ServerIP = sock.inet_addr(Server) if ServerIP == INADDR_NONE then local Addresses, AddressType, AddressLength = gethostbyname_(Server) local Errno = errno() if Addresses == NULL or AddressType ~= AF_INET or AddressLength ~= 4 then return nil, socket_strerror(Errno) end local PAddress = Addresses[0] if PAddress == NULL then return nil, socket_strerror(Errno) end ServerIP = bit.bor(bit.lshift(PAddress[3], 24), bit.lshift(PAddress[2], 16), bit.lshift(PAddress[1], 8), PAddress[0]) end local Socket = sock.socket(AF_INET, SOCK_STREAM, 0) if Socket == INVALID_SOCKET then return nil, socket_strerror(errno()) end if bind_(Socket, AF_INET, LocalPort) == SOCKET_ERROR then local BindError = errno() local Error = sock.shutdown(Socket, SD_BOTH) if Error ~= 0 then return nil, socket_strerror(Error) end local Error = closesocket_(Socket) if Error ~= 0 then return nil, socket_strerror(Error) end return nil, socket_strerror(BindError) end local SAddress = ffi.new("struct sockaddr_in") local Addr = ffi.cast("struct sockaddr *", SAddress) local SizePtr = ffi.new("int [1]") SizePtr[0] = ffi.sizeof(SAddress) if sock.getsockname(Socket, Addr, SizePtr) == SOCKET_ERROR then local GetSockNameError = errno() local Error = sock.shutdown(Socket, SD_BOTH) if Error ~= 0 then return nil, socket_strerror(Error) end local Error = closesocket_(Socket) if Error ~= 0 then return nil, socket_strerror(Error) end return nil, socket_strerror(GetSockNameError) end local LocalIP = ffi.string(sock.inet_ntoa(SAddress.sin_addr)) local LocalPort = tonumber(sock.ntohs(SAddress.sin_port)) local Stream = ffi.new("struct TTCPStream") Stream.Socket = Socket Stream.LocalIP = ffi.new("char [?]", #LocalIP, LocalIP) Stream.LocalPort = ffi.new("unsigned short", LocalPort) local ServerPtr = ffi.new("int[1]", ServerIP) if connect_(Socket, ServerPtr, AF_INET, 4, ServerPort) == SOCKET_ERROR then local ConnectError = errno() local Error = sock.shutdown(Socket, SD_BOTH) if Error ~= 0 then return nil, socket_strerror(Error) end local Error = closesocket_(Socket) if Error ~= 0 then return nil, socket_strerror(Error) end return nil, socket_strerror(ConnectError) end local RemoteAddress = ffi.new("struct sockaddr_in") local Addr = ffi.cast("struct sockaddr *", RemoteAddress) local SizePtr = ffi.new("int [1]", ffi.sizeof(RemoteAddress)) if sock.getpeername(Socket, Addr, SizePtr) == SOCKET_ERROR then local GetPeerNameError = errno() local Error = sock.shutdown(Socket, SD_BOTH) if Error ~= 0 then return nil, socket_strerror(Error) end local Error = closesocket_(Socket) if Error ~= 0 then return nil, socket_strerror(Error) end return nil, socket_strerror(GetPeerNameError) end local RemoteIP = ffi.string(sock.inet_ntoa(RemoteAddress.sin_addr)) local RemotePort = tonumber(sock.ntohs(RemoteAddress.sin_port)) Stream.RemoteIP = ffi.new("char [?]", #RemoteIP, RemoteIP) Stream.RemotePort = ffi.new("unsigned short", RemotePort) Stream.Age = socket.gettime() Stream.Timeouts = ffi.new("unsigned int[2]") Stream.TCP = true return Stream end function socket.CreateTCPServer(Port, Backlog) local Port = Port or 0 local Socket = sock.socket(AF_INET, SOCK_STREAM, 0) if Socket == INVALID_SOCKET then return nil, socket_strerror(errno()) end if bind_(Socket, AF_INET, Port) == SOCKET_ERROR then local BindError = errno() local Error = sock.shutdown(Socket, SD_BOTH) if Error ~= 0 then return nil, socket_strerror(Error) end local Error = closesocket_(Socket) if Error ~= 0 then return nil, socket_strerror(Error) end return nil, socket_strerror(BindError) end local SAddress = ffi.new("struct sockaddr_in") local Addr = ffi.cast("struct sockaddr *", SAddress) local SizePtr = ffi.new("int [1]") SizePtr[0] = ffi.sizeof(SAddress) if sock.getsockname(Socket, Addr, SizePtr) == SOCKET_ERROR then local GetSockNameError = errno() local Error = sock.shutdown(Socket, SD_BOTH) if Error ~= 0 then return nil, socket_strerror(Error) end local Error = closesocket_(Socket) if Error ~= 0 then return nil, socket_strerror(Error) end return nil, socket_strerror(GetSockNameError) end local LocalIP = ffi.string(sock.inet_ntoa(SAddress.sin_addr)) local LocalPort = tonumber(sock.ntohs(SAddress.sin_port)) local Stream = ffi.new("struct TTCPStream") Stream.Socket = Socket Stream.LocalIP = ffi.new("char [?]", #LocalIP, LocalIP) Stream.LocalPort = ffi.new("unsigned short", LocalPort) if sock.listen(Socket, Backlog or SOMAXCONN) == SOCKET_ERROR then local ListenError = errno() local Error = sock.shutdown(Socket, SD_BOTH) if Error ~= 0 then return nil, socket_strerror(Error) end local Error = closesocket_(Socket) if Error ~= 0 then return nil, socket_strerror(Error) end return nil, socket_strerror(ListenError) end Stream.Age = socket.gettime() Stream.Timeouts = ffi.new("unsigned int[2]") Stream.TCP = true return Stream end function TTCPStream:Accept() if self.Socket == INVALID_SOCKET then return nil end local Select = select_(1, {self.Socket}, 0, nil, 0, nil, self.Timeouts[1]) if Select ~= 1 then if Select == SOCKET_ERROR then return nil, socket_strerror(errno()) end return nil, "timeout" end local Address = ffi.new("struct sockaddr_in") local Addr = ffi.cast("struct sockaddr *", Address) local SizePtr = ffi.new("int [1]", ffi.sizeof(Address)) local Socket = sock.accept(self.Socket, Addr, SizePtr) if Socket == SOCKET_ERROR then return nil, socket_strerror(errno()) end local Stream = ffi.new("struct TTCPStream") Stream.Socket = Socket local LocalIP = ffi.string(sock.inet_ntoa(Address.sin_addr)) local LocalPort = tonumber(sock.ntohs(Address.sin_port)) local RemoteIP = ffi.string(sock.inet_ntoa(Address.sin_addr)) local RemotePort = tonumber(sock.ntohs(Address.sin_port)) Stream.LocalIP = ffi.new("char [?]", #LocalIP, LocalIP) Stream.LocalPort = ffi.new("unsigned short", LocalPort) Stream.RemoteIP = ffi.new("char [?]", #RemoteIP, RemoteIP) Stream.RemotePort = ffi.new("unsigned short", RemotePort) Stream.Timeouts = ffi.new("unsigned int [2]", TCP_TIMEOUT, TCP_TIMEOUT) Stream.TCP = true return Stream end ---------- LuaSocket-like api -- TCP streams function TTCPStream:accept() if self.Socket == INVALID_SOCKET then return nil end local Select = select_(1, {self.Socket}, 0, nil, 0, nil, self.Timeouts[1]) if Select ~= 1 then if Select == SOCKET_ERROR then return nil, socket_strerror(errno()) end return nil, "timeout" end local Address = ffi.new("struct sockaddr_in") local Addr = ffi.cast("struct sockaddr *", Address) local SizePtr = ffi.new("int [1]", ffi.sizeof(Address)) local Socket = sock.accept(self.Socket, Addr, SizePtr) if Socket == SOCKET_ERROR then return nil, socket_strerror(errno()) end local Stream = ffi.new("struct TTCPStream") Stream.Socket = Socket local LocalIP = ffi.string(sock.inet_ntoa(Address.sin_addr)) local LocalPort = tonumber(sock.ntohs(Address.sin_port)) local RemoteIP = ffi.string(sock.inet_ntoa(Address.sin_addr)) local RemotePort = tonumber(sock.ntohs(Address.sin_port)) Stream.LocalIP = ffi.new("char [?]", #LocalIP, LocalIP) Stream.LocalPort = ffi.new("unsigned short", LocalPort) Stream.RemoteIP = ffi.new("char [?]", #RemoteIP, RemoteIP) Stream.RemotePort = ffi.new("unsigned short", RemotePort) Stream.Timeouts = ffi.new("unsigned int [2]", TCP_TIMEOUT, TCP_TIMEOUT) Stream.TCP = true return Stream end function TTCPStream:bind(Address, Port) local Address = tostring(Address) or "" local Port = tonumber(Port) or 0 if Address == "*" or Address == "localhost" then if bind_(self.Socket, AF_INET, Port or 0) == SOCKET_ERROR then local BindError = errno() local Error = sock.shutdown(self.Socket, SD_BOTH) if Error ~= 0 then return nil, socket_strerror(Error) end local Error = closesocket_(self.Socket) if Error ~= 0 then return nil, socket_strerror(Error) end return nil, socket_strerror(BindError) end local SockAddress = ffi.new("struct sockaddr_in") local Addr = ffi.cast("struct sockaddr * ", SockAddress) local SizePtr = ffi.new("int [1]", ffi.sizeof(SockAddress)) if sock.getsockname(self.Socket, Addr, SizePtr) == SOCKET_ERROR then local GetSockNameError = errno() local Error = sock.shutdown(self.Socket, SD_BOTH) if Error ~= 0 then return nil, socket_strerror(Error) end local Error = closesocket_(self.Socket) if Error ~= 0 then return nil, socket_strerror(Error) end return nil, socket_strerror(GetSockNameError) end local LocalIP = ffi.string(sock.inet_ntoa(SockAddress.sin_addr)) local LocalPort = tonumber(sock.ntohs(SockAddress.sin_port)) self.LocalIP = ffi.new("char [?]", #LocalIP, LocalIP) self.LocalPort = ffi.new("unsigned short", LocalPort) self.Timeouts = ffi.new("unsigned int [2]", TCP_TIMEOUT, TCP_TIMEOUT) return true end end function TTCPStream:connect(address, port) if self.LocalPort == 0 then local Success, Error = self:bind("*", Port) if not Success then return nil, Error end end local ServerIP = sock.inet_addr(address) if ServerIP == INADDR_NONE then local Addresses, AddressType, AddressLength = gethostbyname_(address) local Errno = errno() if Addresses == nil or AddressType ~= AF_INET or AddressLength ~= 4 then return nil, socket_strerror(Errno) end local PAddress = Addresses[0] if PAddress == nil then return nil, socket_strerror(Errno) end ServerIP = bit.bor(bit.lshift(PAddress[3], 24), bit.lshift(PAddress[2], 16), bit.lshift(PAddress[1], 8), PAddress[0]) end local ServerPtr = ffi.new("int [1]", ServerIP) if connect_(self.Socket, ServerPtr, AF_INET, 4, port) == SOCKET_ERROR then local ConnectError = errno() local Error = sock.shutdown(self.Socket, SD_BOTH) if Error ~= 0 then return nil, socket_strerror(Error) end local Error = closesocket_(self.Socket) if Error ~= 0 then return nil, socket_strerror(Error) end return nil, socket_strerror(ConnectError) end local PeerAddress = ffi.new("struct sockaddr_in") local Addr = ffi.cast("struct sockaddr *", PeerAddress) local SizePtr = ffi.new("int [1]", ffi.sizeof(PeerAddress)) if sock.getpeername(self.Socket, Addr, SizePtr) == SOCKET_ERROR then local GetPeerNameError = errno() local Error = sock.shutdown(self.Socket, SD_BOTH) if Error ~= 0 then return nil, socket_strerror(Error) end local Error = closesocket_(self.Socket) if Error ~= 0 then return nil, socket_strerror(Error) end return nil, socket_strerror(GetPeerNameError) end local RemoteIP = ffi.string(sock.inet_ntoa(PeerAddress.sin_addr)) local RemotePort = tonumber(sock.ntohs(PeerAddress.sin_port)) self.RemoteIP = ffi.new("char [?]", #RemoteIP, RemoteIP) self.RemotePort = ffi.new("unsigned short", RemotePort) return true end function TTCPStream:getpeername() return ffi.string(self.RemoteIP), tonumber(self.RemotePort) end function TTCPStream:getsockname() return ffi.string(self.LocalIP), tonumber(self.LocalPort) end function TTCPStream:getstats() local Age = socket.gettime() - tonumber(self.Age) return tonumber(self.Received), tonumber(self.Sent), Age end function TTCPStream:close() local Error = sock.shutdown(self.Socket, SD_BOTH) if Error ~= 0 then return nil, socket_strerror(Error) end local Error = closesocket_(self.Socket) if Error ~= 0 then return nil, socket_strerror(Error) end self.Socket = INVALID_SOCKET return true end function TTCPStream:listen(backlog) if sock.listen(self.Socket, backlog or SOMAXCONN) == SOCKET_ERROR then local ListenError = errno() local Error = sock.shutdown(self.Socket, SD_BOTH) if Error ~= 0 then return nil, socket_strerror(Error) end local Error = closesocket_(self.Socket) if Error ~= 0 then return nil, socket_strerror(Error) end return nil, socket_strerror(ListenError) end return true end function TTCPStream:receive(pattern, prefix) local prefix = prefix or "" if pattern == "*a" then local Buffer = ffi.new("byte [4096]") local Result = sock.recv(self.Socket, Buffer, 4096, 0) if Result == SOCKET_ERROR then return nil, socket_strerror(errno()) end self.Received = self.Received + ffi.sizeof(Buffer) return prefix .. ffi.string(Buffer) elseif pattern == nil or pattern == "*l" then local Line = "" repeat local Buffer = ffi.new("byte [1]") local Result = sock.recv(self.Socket, Buffer, 1, 0) if Result == SOCKET_ERROR then return nil, socket_strerror(errno()) end self.Received = self.Received + 1 local Byte = Buffer[0] if Byte == 13 then break elseif Byte ~= 10 then Line = Line .. string.char(Byte) end until self:Eof() return prefix .. Line elseif type(pattern) == "number" then local Size = tonumber(pattern) if Size > 0 then local Buffer = ffi.new("byte [?]", Size) local Result = sock.recv(self.Socket, Buffer, Size, 0) if Result == SOCKET_ERROR then return nil, socket_strerror(errno()) end self.Received = self.Received + ffi.sizeof(Buffer) return prefix .. ffi.string(Buffer) end return prefix end if not self:Connected() then return nil, "closed" end return nil, "timeout" end function TTCPStream:send(data, i, j) if self.Socket == INVALID_SOCKET then return nil, "closed" end if i and j then data = data:sub(i, j) elseif i then data = data:sub(i) end local Select = select_(1, nil, 1, {self.Socket}, 0, nil, 0) if Select == SOCKET_ERROR then return nil, socket_strerror(errno()) end local Result = sock.send(self.Socket, data, #data, 0) if Result == SOCKET_ERROR then return nil, socket_strerror(errno()) end self.Sent = self.Sent + #data return Result end function TTCPStream:setstats(received, sent, age) self.Received = received self.Sent = sent self.Age = socket.gettime() - (tonumber(age) or 0) end function TTCPStream:settimeout(value, mode) if mode == nil or mode == "t" then self.Timeouts = ffi.new("unsigned int [2]", value, value) elseif mode == "b" then self.Timeouts = ffi.new("unsigned int [2]", value, self.Timeouts[1]) end return true end function TTCPStream:shutdown(mode) if mode == "both" then sock.shutdown(self.Socket, SD_BOTH) elseif mode == "send" then sock.shutdown(self.Socket, SD_SEND) elseif mode == "receive" then sock.shutdown(self.Socket, SD_RECEIVE) end return 1 end -- UDP streams function TUDPStream:close() local Error = sock.shutdown(self.Socket, SD_BOTH) if Error ~= 0 then return false, socket_strerror(Error) end local Error = closesocket_(self.Socket) if Error ~= 0 then return false, socket_strerror(Error) end self.Socket = INVALID_SOCKET return true end function TUDPStream:getpeername() return ffi.string(self.RemoteIP), tonumber(self.RemotePort) end function TUDPStream:getsockname() return ffi.string(self.LocalIP), tonumber(self.LocalPort) end function TUDPStream:receive(size) local size = size or 4096 if select_(1, {self.Socket}, 0, nil, 0, nil, self.Timeout) == SOCKET_ERROR then return nil, socket_strerror(errno()) end local Size = ffi.new("int [1]") if ioctl_(self.Socket, FIONREAD, Size) == SOCKET_ERROR then return nil, socket_strerror(errno()) end Size = Size[0] if Size <= 0 then return nil, "timeout" end local Buffer = ffi.new("char [?]", Size) local Result, MessageIP, MessagePort = recvfrom_(self.Socket, Buffer, Size, 0) if Result == SOCKET_ERROR then return nil, socket_strerror(errno()) end self.MessageIP = MessageIP self.MessagePort = MessagePort self.RecvSize = self.RecvSize + Result if self.RemoteIP == nil or self.RemotePort == nil then return ffi.string(Buffer) elseif MessageIP ~= ffi.string(self.RemoteIP) or MessagePort ~= tonumber(self.RemotePort) then return nil, "timeout" end return ffi.string(Buffer) end function TUDPStream:receivefrom(size) local size = size or 4096 if select_(1, {self.Socket}, 0, nil, 0, nil, self.Timeout) == SOCKET_ERROR then return nil, socket_strerror(errno()) end local Size = ffi.new("int [1]") if ioctl_(self.Socket, FIONREAD, Size) == SOCKET_ERROR then return nil, socket_strerror(errno()) end Size = Size[0] if Size <= 0 then return nil, "timeout" end local Buffer = ffi.new("char [?]", Size) local Result, MessageIP, MessagePort = recvfrom_(self.Socket, Buffer, Size, 0) if Result == SOCKET_ERROR then return nil, socket_strerror(errno()) end self.MessageIP = MessageIP self.MessagePort = MessagePort self.RecvSize = self.RecvSize + Result return ffi.string(Buffer), ffi.string(MessageIP), tonumber(MessagePort) end function TUDPStream:send(datagram) if select_(0, nil, 1, {self.Socket}, 0, nil, 0) ~= 1 then return nil, socket_strerror(errno()) end local IP = ffi.string(self.RemoteIP) or "" local Port = self.RemotePort or 0 local Result = sendto_(self.Socket, datagram, #datagram, 0, IP, Port) if Result == SOCKET_ERROR then return nil, socket_strerror(errno()) end return Result end function TUDPStream:sendto(datagram, ip, port) if select_(0, nil, 1, {self.Socket}, 0, nil, 0) ~= 1 then return nil, socket_strerror(errno()) end local Result = sendto_(self.Socket, datagram, #datagram, 0, ip, port) if Result == SOCKET_ERROR then return nil, socket_strerror(errno()) end return true end function TUDPStream:setpeername(address, port) if address == nil or port == nil then self.RemoteIP = nil self.RemotePort = nil end if self.LocalPort == 0 then local Bind, Error = self:setsockname("*", 0) if Bind == nil then return nil, Error end end self.RemoteIP = ffi.new("char [?]", #address, tostring(address)) self.RemotePort = tonumber(port) or 0 return true end function TUDPStream:setsockname(address, port) if address == "*" or address == "localhost" then if bind_(self.Socket, AF_INET, port or 0) == SOCKET_ERROR then local BindError = errno() local Error = sock.shutdown(self.Socket, SD_BOTH) if Error ~= 0 then return nil, socket_strerror(Error) end local Error = closesocket_(self.Socket) if Error ~= 0 then return nil, socket_strerror(Error) end return nil, socket_strerror(BindError) end local Address = ffi.new("struct sockaddr_in") local Addr = ffi.cast("struct sockaddr *", Address) local SizePtr = ffi.new("int[1]", ffi.sizeof(Address)) if sock.getsockname(self.Socket, Addr, SizePtr) == SOCKET_ERROR then local GetSockNameError = errno() local Error = sock.shutdown(Socket, SD_BOTH) if Error ~= 0 then return nil, socket_strerror(Error) end local Error = closesocket_(Socket) if Error ~= 0 then return nil, socket_strerror(Error) end return nil, socket_strerror(GetSockNameError) end local LocalIP = ffi.string(sock.inet_ntoa(Address.sin_addr)) local LocalPort = tonumber(sock.ntohs(Address.sin_port)) self.LocalIP = ffi.new("char [?]", #LocalIP, LocalIP) self.LocalPort = ffi.new("unsigned short", LocalPort) return true end end function TUDPStream:settimeout(value) self.Timeout = ffi.new("unsigned int", value or 0) return true end function socket.tcp() local Socket = sock.socket(AF_INET, SOCK_STREAM, 0) if Socket == INVALID_SOCKET then return nil, socket_strerror(errno()) end local Stream = ffi.new("struct TTCPStream") Stream.Socket = Socket Stream.TCP = true return Stream end function socket.udp() local Socket = sock.socket(AF_INET, SOCK_DGRAM, 0) if Socket == INVALID_SOCKET then return nil, socket_strerror(errno()) end local Stream = ffi.new("struct TUDPStream") Stream.Socket = Socket Stream.Timeout = ffi.new("unsigned int", UDP_TIMEOUT or 0) Stream.UDP = true Stream.SendBuffer = ffi.new("char [0]") Stream.RecvBuffer = ffi.new("char [0]") return Stream end function socket.protect(func) local function pass(ok, ...) if ok then return ... end return nil, ... end return function(...) return pass(pcall(func, ...)) end end function socket.select(recvt, sendt, timeout) if type(recvt) == "table" then local ReceiveTable = {} for _, Stream in pairs(recvt) do table.insert(ReceiveTable, Stream.Socket) end local SendTable = {} for _, Stream in pairs(SendTable) do table.insert(SendTable, Stream.Socket) end local Select = select_(#ReceiveTable, ReceiveTable, #SendTable, SendTable, 0, nil, timeout or 0) if Select == SOCKET_ERROR then return nil, nil, socket_strerror(errno()) end table.sort(ReceiveTable) table.sort(SendTable) return ReceiveTable, SendTable end end function socket.skip(d, ...) local skip = {} for Key, Value in pairs({...}) do if Key >= d then skip[Key - d + 1] = value end end return unpack(skip) end function socket.bind(address, port, backlog) local address = address and tostring(address) or "*" local port = tonumber(port) or 0 local Stream, Error = socket.tcp() if Stream == nil then return nil, Error end local Bind, Error = Stream:bind(address, port) if Bind == nil then return nil, Error end local Listen, Error = Stream:listen(backlog) if Listen == nil then return nil, Error end return Stream end function socket.connect(address, port, locaddr, locport) local port = tonumber(port) or 0 local locport = tonumber(locport) or 0 local Stream, Error = socket.tcp() if Stream == nil then return nil, Error end local Bind, Error = Stream:bind(locaddr or "*", locport) if Bind == nil then return nil, Error end local Connected, Error = Stream:connect(address, port) if Connected == nil then return nil, Error end return Stream end if ffi.os == "Windows" then function socket.sleep(t) C.Sleep(t * 1000) end else function socket.sleep(t) C.poll(nil, 0, s * 1000) end end if ffi.os == "Windows" then local Start = ffi.new("SYSTEMTIME"); C.GetSystemTime(Start) local StartTime = Start.wSecond + Start.wMilliseconds/1000 function socket.gettime() local Time = ffi.new("SYSTEMTIME"); C.GetSystemTime(Time) return (Time.wSecond + Time.wMilliseconds/1000) - StartTime end else local Start = ffi.new("struct timeval"); C.gettimeofday(Start, nil) local StartTime = Start.tv_sec + Start.tv_usec/1.0e6 function socket.gettime() local Time = ffi.new("struct timeval"); C.gettimeofday(Time, nil) return (Time.tv_sec + Time.tv_usec/1.0e6) - StartTime end end -- socket.dns.* api socket.dns = {} function socket.dns.gethostname() local Name = ffi.new("char [256]") if sock.gethostname(Name, 256) == SOCKET_ERROR then return nil, socket_strerror(errno()) end return ffi.string(Name) end function socket.dns.tohostname(address) end function socket.dns.toip(address) local address = address or "" local AddrIP = sock.inet_addr(address) if AddrIP == INADDR_NONE then local Addresses, AddressType, AddressLength = gethostbyname_(address) if Addresses == nil or AddressType ~= AF_INET or AddressLength ~= 4 then return nil, socket_strerror(errno()) end local PrimaryAddress = Addresses[0] if PrimaryAddress == nil then return nil, socket_strerror(errno()) end local Information = { ip = {}, name = address, alias = {} } local Count = 0 while Addresses[Count] ~= nil do local Address = Addresses[Count] local IntAddr = bit.bor(bit.lshift(Address[3], 24), bit.lshift(Address[2], 16), bit.lshift(Address[1], 8), Address[0]) local in_addr = ffi.new("struct in_addr", {s_addr = IntAddr}) local NTOA = sock.inet_ntoa(in_addr) Information.ip[Count + 1] = ffi.string(NTOA) Count = Count + 1 end return Information.ip[1], Information end return nil, socket_strerror(errno()) end return socket