diff --git a/src/bin/tinn.exe b/src/bin/tinn.exe index 4e61c36..36e30e0 100644 Binary files a/src/bin/tinn.exe and b/src/bin/tinn.exe differ diff --git a/src/computicle/IOCPSocket.lua b/src/computicle/IOCPSocket.lua index cc0cb02..7a1b4ae 100644 --- a/src/computicle/IOCPSocket.lua +++ b/src/computicle/IOCPSocket.lua @@ -205,14 +205,14 @@ IOCPSocket.setKeepAlive = function(self, keepalive, timeout, interval) return success, err end - IOCPSocket.setNoDelay = function(self, nodelay) - local oneint = ffi.new("int[1]"); - if nodelay then - oneint[0] = 1 - end +IOCPSocket.setNoDelay = function(self, nodelay) + local oneint = ffi.new("int[1]"); + if nodelay then + oneint[0] = 1 + end - return WinSock.setsockopt(self:getNativeSocket(), IPPROTO_TCP, TCP_NODELAY, oneint, ffi.sizeof(oneint)) - end + return WinSock.setsockopt(self:getNativeSocket(), IPPROTO_TCP, TCP_NODELAY, oneint, ffi.sizeof(oneint)) +end IOCPSocket.setNonBlocking = function(self, nonblocking) local oneint = ffi.new("int[1]"); @@ -223,23 +223,23 @@ IOCPSocket.setNonBlocking = function(self, nonblocking) return WinSock.ioctlsocket(self:getNativeSocket(), FIONBIO, oneint); end - IOCPSocket.setReuseAddress = function(self, reuse) - local oneint = ffi.new("int[1]"); - if reuse then - oneint[0] = 1 - end +IOCPSocket.setReuseAddress = function(self, reuse) + local oneint = ffi.new("int[1]"); + if reuse then + oneint[0] = 1 + end - return WinSock.setsockopt(self:getNativeSocket(), SOL_SOCKET, SO_REUSEADDR, oneint, ffi.sizeof(oneint)) - end + return WinSock.setsockopt(self:getNativeSocket(), SOL_SOCKET, SO_REUSEADDR, oneint, ffi.sizeof(oneint)) +end - IOCPSocket.setExclusiveAddress = function(self, exclusive) - local oneint = ffi.new("int[1]"); - if exclusive then - oneint[0] = 1 - end +IOCPSocket.setExclusiveAddress = function(self, exclusive) + local oneint = ffi.new("int[1]"); + if exclusive then + oneint[0] = 1 + end - return WinSock.setsockopt(self:getNativeSocket(), SOL_SOCKET, SO_EXCLUSIVEADDRUSE, oneint, ffi.sizeof(oneint)) - end + return WinSock.setsockopt(self:getNativeSocket(), SOL_SOCKET, SO_EXCLUSIVEADDRUSE, oneint, ffi.sizeof(oneint)) +end --[[ Reading Socket Options @@ -474,6 +474,55 @@ IOCPSocket.send = function(self, buff, bufflen) return bytes; end +IOCPSocket.sendTo = function(self, lpTo, iTolen, buff, bufflen) + if lpTo == nil then + return false; + end + + + bufflen = bufflen or #buff + + local lpBuffers = ffi.new("WSABUF", bufflen, ffi.cast("char *",buff)); + local dwBufferCount = 1; + local lpNumberOfBytesSent = nil; + local dwFlags = 0; + local lpOverlapped = self:createOverlapped(ffi.cast("uint8_t *",buff), bufflen, SocketOps.WRITE); + local lpCompletionRoutine = nil; + + local status = ws2_32.WSASendTo(self:getNativeSocket(), + lpBuffers, + dwBufferCount, + lpNumberOfBytesSent, + dwFlags, + ffi.cast("const struct sockaddr *", lpTo), + iTolen, + ffi.cast("OVERLAPPED *",lpOverlapped), + lpCompletionRoutine); + + + -- Do the following if we want to handle + -- immediate success + if status == 0 then + --print("#### IOCPSocket, WSASend STATUS == 0 ####") + -- return the number of bytes transferred + --return lpNumberOfBytesSent[0]; + else + local err = ws2_32.WSAGetLastError(); + if err ~= WSA_IO_PENDING then + print(" IOCPSocket.send, ERROR: ", err); + return false, err; + end + end + + local key, bytes, ovl = IOProcessor:yieldForIo(self, SocketOps.WRITE, lpOverlapped.opcounter); + +--print("WSASEND: ", key, bytes, ovl); + + -- BUGBUG + return bytes; +end + + IOCPSocket.receive = function(self, buff, bufflen) @@ -524,6 +573,58 @@ IOCPSocket.receive = function(self, buff, bufflen) end +IOCPSocket.receiveFrom = function(self, lpFrom, fromLen, buff, bufflen) + + local lpBuffers = ffi.new("WSABUF", bufflen, buff); + local dwBufferCount = 1; +-- local lpNumberOfBytesRecvd = ffi.new("DWORD[1]"); + -- if we're going to use io completion ports, then + -- the numberOfBytesRecvd MUST be == nil + local lpNumberOfBytesRecvd = nil; + local lpFlags = ffi.new("DWORD[1]"); + local lpOverlapped = self:createOverlapped(buff, bufflen, SocketOps.READ); + local lpCompletionRoutine = nil; + local lpFromlen = ffi.new("DWORD[1]", fromLen); + + local status = ws2_32.WSARecvFrom(self:getNativeSocket(), + lpBuffers, + dwBufferCount, + lpNumberOfBytesRecvd, + lpFlags, + ffi.cast("struct sockaddr *", lpFrom), + lpFromlen, + ffi.cast("OVERLAPPED *",lpOverlapped), + lpCompletionRoutine); + + +--print("IOCPSocket.receive, WSARecv(), STATUS: ", status); + + -- if the return value is == 0, then the transfer + -- to the network stack has already completed, + -- but the completion notification has not necessarily + -- happened, so treat it the same as PENDING + if status == 0 then + --print("#### IOCPSocket.WSARecv, STATUS == 0 ####"); + + --return lpNumberOfBytesRecvd[0]; + else + -- didn't get bytes immediately, so see if it's a 'pending' + -- or some other error + local err = ws2_32.WSAGetLastError(); + + if err ~= WSA_IO_PENDING then + print("IOCPSocket.WSARecv, ERROR: ", err); + return false, err; + end + end + + local key, bytes, ovl = IOProcessor:yieldForIo(self, SocketOps.READ, lpOverlapped.opcounter); + +print("WSARecvFrom: ", key, bytes, ovl); + + return bytes; +end + return IOCPSocket; \ No newline at end of file diff --git a/src/net/SocketServer.lua b/src/net/SocketServer.lua index abb5d97..e2f36a3 100644 --- a/src/net/SocketServer.lua +++ b/src/net/SocketServer.lua @@ -49,7 +49,7 @@ end SocketServer.handleAccepted = function(self, sock) ---print("SocketServer.handleAccepted(): ", sock); +print("SocketServer.handleAccepted(): ", sock); if self.OnAccept then --print("CALLING self.OnAccept") diff --git a/src/win32/apiset/WinCon.lua b/src/win32/apiset/WinCon.lua index b97a03d..dd7d36e 100644 --- a/src/win32/apiset/WinCon.lua +++ b/src/win32/apiset/WinCon.lua @@ -2,9 +2,8 @@ local ffi = require("ffi"); local NOGDI = true; -ffi.cdef[[ -typedef int16_t SHORT; -]] +local basetsd = require("basetsd"); + ffi.cdef[[ typedef struct _COORD { @@ -245,7 +244,7 @@ static const int ENABLE_WRAP_AT_EOL_OUTPUT = 0x0002; -typedef BOOL ( *PHANDLER_ROUTINE)(DWORD CtrlType); +typedef BOOL (__stdcall *PHANDLER_ROUTINE)(DWORD CtrlType); typedef struct _CONSOLE_READCONSOLE_CONTROL { ULONG nLength; diff --git a/src/win32/apiset/core_console_l1_1_0.lua b/src/win32/apiset/core_console_l1_1_0.lua index 472a3d2..e0fb749 100644 --- a/src/win32/apiset/core_console_l1_1_0.lua +++ b/src/win32/apiset/core_console_l1_1_0.lua @@ -86,4 +86,20 @@ WriteConsoleW(HANDLE hConsoleOutput, LPVOID lpReserved); ]] -return k32Lib; +return { + AllocConsole = k32Lib.AllocConsole, + GetConsoleCP = k32Lib.GetConsoleCP, + GetConsoleMode = k32Lib.GetConsoleMode, + GetConsoleOutputCP = k32Lib.GetConsoleOutputCP, + GetNumberOfConsoleInputEvents = k32Lib.GetNumberOfConsoleInputEvents, + PeekConsoleInputA = k32Lib.PeekConsoleInputA, + ReadConsoleA = k32Lib.ReadConsoleA, + ReadConsoleInputA = k32Lib.ReadConsoleInputA, + ReadConsoleInputW = k32Lib.ReadConsoleInputW, + ReadConsoleW = k32Lib.ReadConsoleW, + SetConsoleCtrlHandler = k32Lib.SetConsoleCtrlHandler, + SetConsoleMode = k32Lib.SetConsoleMode, + WriteConsoleA = k32Lib.WriteConsoleA, + WriteConsoleW = k32Lib.WriteConsoleW, +} + diff --git a/src/win32/apiset/ws2_32.lua b/src/win32/apiset/ws2_32.lua index 4ad5694..6a8bfd6 100644 --- a/src/win32/apiset/ws2_32.lua +++ b/src/win32/apiset/ws2_32.lua @@ -429,7 +429,16 @@ typedef struct __WSABUF { char * buf; } WSABUF, *LPWSABUF; ]] +WSABUF = ffi.typeof("WSABUF"); +WSABUF_mt = { + __new = function(ct, buf, len) + return ffi.new(ct, len, ffi.cast("char *", buf)); + end, + + __index = { + }, +} -- -- MSTcpIP.h -- @@ -988,6 +997,18 @@ int WSARecv( LPWSAOVERLAPPED lpOverlapped, void* lpCompletionRoutine); +int +WSARecvFrom( + SOCKET s, + LPWSABUF lpBuffers, + DWORD dwBufferCount, + LPDWORD lpNumberOfBytesRecvd, + LPDWORD lpFlags, + struct sockaddr * lpFrom, + LPINT lpFromlen, + LPWSAOVERLAPPED lpOverlapped, + LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); + int WSASend(SOCKET s, LPWSABUF lpBuffers, @@ -1321,10 +1342,10 @@ WSApSetPostRoutine = Lib.WSApSetPostRoutine, --]] WSARecv = Lib.WSARecv, + WSARecvFrom = Lib.WSARecvFrom, --[[ WSARecvDisconnect = Lib.WSARecvDisconnect, -WSARecvFrom = Lib.WSARecvFrom, WSARemoveServiceClass = Lib.WSARemoveServiceClass, WSAResetEvent = Lib.WSAResetEvent, --]] @@ -1334,10 +1355,12 @@ WSAResetEvent = Lib.WSAResetEvent, --[[ WSASendDisconnect = Lib. WSASendMsg = Lib. -WSASendTo = Lib. -WSASetBlockingHook = Lib. --]] + WSASendTo = Lib.WSASendTo, + +-- deprecated: WSASetBlockingHook = Lib. + WSASetEvent = Lib.WSASetEvent, --[[ diff --git a/tests/LineServer.lua b/tests/LineServer.lua index 85b452b..b72e3a1 100644 --- a/tests/LineServer.lua +++ b/tests/LineServer.lua @@ -19,7 +19,18 @@ local OnAccept = function(param, sock) print("LINE: ", line); -- write the line back out to the socket - socket:send(line, #line); + local body = ""..line.."\r\n" + local content = [[ +HTTP/1.1 200 OK +Connection: close + +]]..body + +print("CONTENT"); +print(content); + + socket:send(content, #content); + socket:closeDown(); --socket:send(buff, bytesread); end diff --git a/tests/SToken.lua b/tests/SToken.lua index 03a8561..28e0fe0 100644 --- a/tests/SToken.lua +++ b/tests/SToken.lua @@ -34,17 +34,28 @@ local SToken_mt = { end, __eq = function(self, other) - print("SToken:__eq()"); - local maxbytes = math.min(self.Length, other.Length); + -- print("SToken:__eq(): ", type(self), type(other)); + + local otherData = ffi.cast("const uint8_t *", other); + local otherLength = #other; + local otherOffset = 0; + + if type(other) == "string" then + else + otherOffset = other.Offset; + end + + + local maxbytes = math.min(self.Length, otherLength); for i=0,maxbytes-1 do - if self.Data[self.Offset+i] > other.Data[other.Offset+i] then - print("RETURN 1.0"); + if self.Data[self.Offset+i] > otherData[otherOffset+i] then + --print("RETURN 1.0"); return false end - if self.Data[self.Offset+i] < other.Data[other.Offset+i] then - print("RETURN 2.0"); + if self.Data[self.Offset+i] < otherData[otherOffset+i] then + --print("RETURN 2.0"); return false end end diff --git a/tests/UdpEchoClient.lua b/tests/UdpEchoClient.lua new file mode 100644 index 0000000..27aad21 --- /dev/null +++ b/tests/UdpEchoClient.lua @@ -0,0 +1,91 @@ +local ffi = require "ffi" + +local IOProcessor = require("IOProcessor"); +local IOCPSocket = require("IOCPSocket"); +local ws2_32 = require("ws2_32"); +local SocketUtils = require("SocketUtils"); + +local StopWatch = require("StopWatch"); + +local hostname = "localhost" +local serviceport = 9090 + + +local argv = {...} +local argc = #argv + +local EchoRequest = function(socket, addr, addrlen) + -- fill the buffer with current time + local datestr = os.date("%c"); + + local bytessent, err = socket:sendTo(addr, addrlen, datestr, #datestr); + +print("bytessent: ", bytessent, err); + + if not bytessent then + print("sendTo ERROR: ", bytessent, err); + return false, err; + end + + local bufflen = 1500; + local buff = ffi.new("uint8_t[?]", bufflen); + + local fromAddr = sockaddr_in(); + local fromLen = ffi.sizeof(fromAddr); + + local bytesreceived, err = socket:receiveFrom(fromAddr, fromLen, buff, bufflen); + + if not bytesreceived then + return false, err; + end + + if bytesreceived > 0 then + print("RECEIVED: ", bytesreceived); + return ffi.string(buff, bytesreceived); + end + + return string.format("bytesreceived == %d", bytesreceived); +end + + + +loop = function() + local sw = StopWatch(); + + local iterations = tonumber(argv[1]) or 1; + --print("iterations: ", iterations); + + + -- create the client socket + local socket, err = IOCPSocket:create(AF_INET, SOCK_DGRAM, 0); + + if not socket then + print("Socket Creation Failed: ", err); + return nil, err; + end + + -- create the address to the server + local addr, err = SocketUtils.CreateSocketAddress(hostname, serviceport) + local addrlen = ffi.sizeof(addr); + + + + local transcount = 0; + + for i=1,iterations do + local dtc, err = EchoRequest(socket, addr, addrlen); + + if dtc then + transcount = transcount + 1; + print(transcount, dtc, transcount/sw:Seconds()); + else + print("Error: ", i, err); + end + collectgarbage(); + end + + print("Transactions: ", transcount, transcount/sw:Seconds()); +end + +run(loop); + diff --git a/tests/UdpEchoServer.lua b/tests/UdpEchoServer.lua new file mode 100644 index 0000000..571bbc0 --- /dev/null +++ b/tests/UdpEchoServer.lua @@ -0,0 +1,64 @@ +local ffi = require("ffi"); + +local IOProcessor = require("IOProcessor"); +local IOCPSocket = require("IOCPSocket"); +local ws2_32 = require("ws2_32"); + +--IOProcessor:setMessageQuanta(5); +local serverport = 9090; + + +local createServerSocket = function(port) + local port = port or serverport; + local socket, err = IOCPSocket:create(AF_INET, SOCK_DGRAM, 0); + + if not socket then + print("create socket ERROR: ", err); + return nil, err; + end + + local addr = sockaddr_in(port); + local addrlen = ffi.sizeof(addr); + + success, err = socket:bind(addr,addrlen) + + if not success then + return false, err; + end + + return socket; +end + +-- The primary application loop +local loop = function() + local bufflen = 1500; + local buff = ffi.new("uint8_t[?]", bufflen); + local from = sockaddr_in(); + local fromLen = ffi.sizeof(from); + + local socket, err = createServerSocket(serverport); + + if not socket then + print("createServerSocket Error: ", err); + return false, err; + end + + while true do + local bytesread, err = socket:receiveFrom(from, fromLen, buff, bufflen); + + if not bytesread then + print("receiveFrom ERROR: ", err) + return false, err; + end + + print("BYTESREAD: ", bytesread, from); + + print(ffi.string(buff, bytesread)); + + -- echo back to sender + local bytessent, err = socket:sendTo(from, fromLen, buff, bufflen); + --collectgarbage(); + end +end + +run(loop); diff --git a/tests/test_SToken.lua b/tests/test_SToken.lua index fb30dac..5b587bb 100644 --- a/tests/test_SToken.lua +++ b/tests/test_SToken.lua @@ -16,6 +16,7 @@ local beg2, end2 = testVector:find("words"); local len2 = end2-beg2+1 local tok3 = SToken(testVector, beg2-1, len2); +local function test_Token() print("Token: ", tok1); print("Token Length: ", #tok1); print("Tok1 == Tok2: ", tok1 == tok2); @@ -23,3 +24,15 @@ print("Tok1 == Tok2: ", tok1 == tok2); print("Token3: ", tok3); print("Token 3 Len: ", #tok3); print("tok1 == tok3: ", tok1 == tok3); +end + +local function test_StringCompare() + print("SToken string compare") + print("tok1 == 'this'", tok1 == "this"); + print("'this' == tok1", 'this' == tok1); + print("tok1 == 'flipper'", tok1 == "flipper") +end + + +--test_Token(); +test_StringCompare();