-wrapsslclient = function( listener, socket, ip, serverport, clientport, mode, sslctx ) -- this function wraps a ssl cleint\r
-\r
- local dispatch, disconnect = listener.listener, listener.disconnect\r
-\r
- --// transform socket to ssl object //--\r
-\r
- local err\r
- socket, err = ssl_wrap( socket, sslctx ) -- wrap socket\r
- if err then\r
- out_put( "server.lua: ssl error: ", err )\r
- return nil, nil, err -- fatal error\r
- end\r
- socket:settimeout( 0 )\r
-\r
- --// private closures of the object //--\r
-\r
- local writequeue = { } -- buffer for messages to send\r
-\r
- local eol, fatal_send_error -- end of buffer\r
-\r
- local sstat, rstat = 0, 0\r
-\r
- --// local import of socket methods //--\r
-\r
- local send = socket.send\r
- local receive = socket.receive\r
- local close = socket.close\r
- --local shutdown = socket.shutdown\r
-\r
- --// public methods of the object //--\r
-\r
- local handler = { }\r
-\r
- handler.getstats = function( )\r
- return rstat, sstat\r
- end\r
-\r
- handler.listener = function( data, err )\r
- return listener( handler, data, err )\r
- end\r
- handler.ssl = function( )\r
- return true\r
- end\r
- handler.send = function( _, data, i, j )\r
- return send( socket, data, i, j )\r
- end\r
- handler.receive = function( pattern, prefix )\r
- return receive( socket, pattern, prefix )\r
- end\r
- handler.shutdown = function( pattern )\r
- --return shutdown( socket, pattern )\r
- end\r
- handler.close = function( closed )\r
- if eol and not fatal_send_error then handler._dispatchdata(); end\r
- close( socket )\r
- writelen = ( eol and removesocket( writelist, socket, writelen ) ) or writelen\r
- readlen = removesocket( readlist, socket, readlen )\r
- socketlist[ socket ] = nil\r
- out_put "server.lua: closed handler and removed socket from list"\r
- end\r
- handler.ip = function( )\r
- return ip\r
- end\r
- handler.serverport = function( )\r
- return serverport\r
- end\r
- handler.clientport = function( ) \r
- return clientport\r
- end\r
-\r
- handler.write = function( data )\r
- if not eol then\r
- writelen = writelen + 1\r
- writelist[ writelen ] = socket\r
- eol = 0\r
- end\r
- eol = eol + 1\r
- writequeue[ eol ] = data\r
- end\r
- handler.writequeue = function( )\r
- return writequeue\r
- end\r
- handler.socket = function( )\r
- return socket\r
- end\r
- handler.mode = function( )\r
- return mode\r
- end\r
- handler._receivedata = function( )\r
- local data, err, part = receive( socket, mode ) -- receive data in "mode"\r
- if not err or ( err == "timeout" or err == "wantread" ) then -- received something\r
- local data = data or part or ""\r
- local count = #data * STAT_UNIT\r
- rstat = rstat + count\r
- receivestat = receivestat + count\r
- out_put( "server.lua: read data '", data, "', error: ", err )\r
- return dispatch( handler, data, err )\r
- else -- connections was closed or fatal error\r
- out_put( "server.lua: client ", ip, ":", clientport, " error: ", err )\r
- handler.close( )\r
- disconnect( handler, err )\r
- writequeue = nil\r
- handler = nil\r
- return false\r
- end\r
- end\r
- handler._dispatchdata = function( ) -- this function writes data to handlers\r
- local buffer = table_concat( writequeue, "", 1, eol )\r
- local succ, err, byte = send( socket, buffer )\r
- local count = ( succ or 0 ) * STAT_UNIT\r
- sstat = sstat + count\r
- sendstat = sendstat + count\r
- out_put( "server.lua: sended '", buffer, "', bytes: ", succ, ", error: ", err, ", part: ", byte, ", to: ", ip, ":", clientport )\r
- if succ then -- sending succesful\r
- --writequeue = { }\r
- eol = nil\r
- writelen = removesocket( writelist, socket, writelen ) -- delete socket from writelist\r
- return true\r
- elseif byte and ( err == "timeout" or err == "wantwrite" ) then -- want write\r
- buffer = string_sub( buffer, byte + 1, -1 ) -- new buffer\r
- writequeue[ 1 ] = buffer -- insert new buffer in queue\r
- eol = 1\r
- return true\r
- else -- connection was closed during sending or fatal error\r
- fatal_send_error = true;\r
- out_put( "server.lua: client ", ip, ":", clientport, " error: ", err )\r
- handler.close( )\r
- disconnect( handler, err )\r
- writequeue = nil\r
- handler = nil\r
- return false\r
- end\r
- end\r
-\r
- -- // COMPAT // --\r
-\r
- handler.getIp = handler.ip\r
- handler.getPort = handler.clientport\r
-\r
- --// handshake //--\r
-\r
- local wrote\r
-\r
- handler.handshake = coroutine_wrap( function( client )\r
- local err\r
- for i = 1, 10 do -- 10 handshake attemps\r
- _, err = client:dohandshake( )\r
- if not err then\r
- out_put( "server.lua: ssl handshake done" )\r
- writelen = ( wrote and removesocket( writelist, socket, writelen ) ) or writelen\r
- handler.receivedata = handler._receivedata -- when handshake is done, replace the handshake function with regular functions\r
- handler.dispatchdata = handler._dispatchdata\r
- return dispatch( handler )\r
- else\r
- out_put( "server.lua: error during ssl handshake: ", err )\r
- if err == "wantwrite" then\r
- if wrote == nil then\r
- writelen = writelen + 1\r
- writelist[ writelen ] = client\r
- wrote = true\r
- end\r
- end\r
- coroutine_yield( handler, nil, err ) -- handshake not finished\r
- end\r
- end\r
- _ = err ~= "closed" and close( socket )\r
- handler.close( )\r
- disconnect( handler, err )\r
- writequeue = nil\r
- handler = nil\r
- return false -- handshake failed\r
- end\r
- )\r
- handler.receivedata = handler.handshake\r
- handler.dispatchdata = handler.handshake\r
-\r
- handler.handshake( socket ) -- do handshake\r
-\r
- socketlist[ socket ] = handler\r
- readlen = readlen + 1\r
- readlist[ readlen ] = socket\r
-\r
- return handler, socket\r
+wrapconnection = function( server, listeners, socket, ip, serverport, clientport, pattern, sslctx, startssl ) -- this function wraps a client to a handler object\r
+\r
+ socket:settimeout( 0 )\r
+\r
+ --// local import of socket methods //--\r
+\r
+ local send\r
+ local receive\r
+ local shutdown\r
+\r
+ --// private closures of the object //--\r
+\r
+ local ssl\r
+\r
+ local dispatch = listeners.incoming or listeners.listener\r
+ local disconnect = listeners.disconnect\r
+\r
+ local bufferqueue = { } -- buffer array\r
+ local bufferqueuelen = 0 -- end of buffer array\r
+\r
+ local toclose\r
+ local fatalerror\r
+ local needtls\r
+\r
+ local bufferlen = 0\r
+\r
+ local noread = false\r
+ local nosend = false\r
+\r
+ local sendtraffic, readtraffic = 0, 0\r
+\r
+ local maxsendlen = _maxsendlen\r
+ local maxreadlen = _maxreadlen\r
+\r
+ --// public methods of the object //--\r
+\r
+ local handler = bufferqueue -- saves a table ^_^\r
+\r
+ handler.dispatch = function( )\r
+ return dispatch\r
+ end\r
+ handler.disconnect = function( )\r
+ return disconnect\r
+ end\r
+ handler.setlistener = function( listeners )\r
+ dispatch = listeners.incoming\r
+ disconnect = listeners.disconnect\r
+ end\r
+ handler.getstats = function( )\r
+ return readtraffic, sendtraffic\r
+ end\r
+ handler.ssl = function( )\r
+ return ssl\r
+ end\r
+ handler.send = function( _, data, i, j )\r
+ return send( socket, data, i, j )\r
+ end\r
+ handler.receive = function( pattern, prefix )\r
+ return receive( socket, pattern, prefix )\r
+ end\r
+ handler.shutdown = function( pattern )\r
+ return shutdown( socket, pattern )\r
+ end\r
+ handler.close = function( forced )\r
+ if not handler then return true; end\r
+ _readlistlen = removesocket( _readlist, socket, _readlistlen )\r
+ _readtimes[ handler ] = nil\r
+ if bufferqueuelen ~= 0 then\r
+ if not ( forced or fatalerror ) then\r
+ handler.sendbuffer( )\r
+ if bufferqueuelen ~= 0 then -- try again...\r
+ if handler then\r
+ handler.write = nil -- ... but no further writing allowed\r
+ end\r
+ toclose = true\r
+ return false\r
+ end\r
+ else\r
+ send( socket, table_concat( bufferqueue, "", 1, bufferqueuelen ), 1, bufferlen ) -- forced send\r
+ end\r
+ end\r
+ _ = shutdown and shutdown( socket )\r
+ socket:close( )\r
+ _sendlistlen = removesocket( _sendlist, socket, _sendlistlen )\r
+ _socketlist[ socket ] = nil\r
+ if handler then\r
+ _writetimes[ handler ] = nil\r
+ _closelist[ handler ] = nil\r
+ handler = nil\r
+ end\r
+ socket = nil\r
+ --mem_free( )\r
+ if server then\r
+ server.remove( )\r
+ end\r
+ out_put "server.lua: closed client handler and removed socket from list"\r
+ return true\r
+ end\r
+ handler.ip = function( )\r
+ return ip\r
+ end\r
+ handler.serverport = function( )\r
+ return serverport\r
+ end\r
+ handler.clientport = function( )\r
+ return clientport\r
+ end\r
+ local write = function( data )\r
+ bufferlen = bufferlen + string_len( data )\r
+ if bufferlen > maxsendlen then\r
+ _closelist[ handler ] = "send buffer exceeded" -- cannot close the client at the moment, have to wait to the end of the cycle\r
+ handler.write = idfalse -- dont write anymore\r
+ return false\r
+ elseif socket and not _sendlist[ socket ] then\r
+ _sendlistlen = _sendlistlen + 1\r
+ _sendlist[ _sendlistlen ] = socket\r
+ _sendlist[ socket ] = _sendlistlen\r
+ end\r
+ bufferqueuelen = bufferqueuelen + 1\r
+ bufferqueue[ bufferqueuelen ] = data\r
+ if handler then\r
+ _writetimes[ handler ] = _writetimes[ handler ] or _currenttime\r
+ end\r
+ return true\r
+ end\r
+ handler.write = write\r
+ handler.bufferqueue = function( )\r
+ return bufferqueue\r
+ end\r
+ handler.socket = function( )\r
+ return socket\r
+ end\r
+ handler.pattern = function( new )\r
+ pattern = new or pattern\r
+ return pattern\r
+ end\r
+ handler.setsend = function ( newsend )\r
+ send = newsend or send\r
+ return send\r
+ end\r
+ handler.bufferlen = function( readlen, sendlen )\r
+ maxsendlen = sendlen or maxsendlen\r
+ maxreadlen = readlen or maxreadlen\r
+ return maxreadlen, maxsendlen\r
+ end\r
+ handler.lock = function( switch )\r
+ if switch == true then\r
+ handler.write = idfalse\r
+ local tmp = _sendlistlen\r
+ _sendlistlen = removesocket( _sendlist, socket, _sendlistlen )\r
+ _writetimes[ handler ] = nil\r
+ if _sendlistlen ~= tmp then\r
+ nosend = true\r
+ end\r
+ tmp = _readlistlen\r
+ _readlistlen = removesocket( _readlist, socket, _readlistlen )\r
+ _readtimes[ handler ] = nil\r
+ if _readlistlen ~= tmp then\r
+ noread = true\r
+ end\r
+ elseif switch == false then\r
+ handler.write = write\r
+ if noread then\r
+ noread = false\r
+ _readlistlen = _readlistlen + 1\r
+ _readlist[ socket ] = _readlistlen\r
+ _readlist[ _readlistlen ] = socket\r
+ _readtimes[ handler ] = _currenttime\r
+ end\r
+ if nosend then\r
+ nosend = false\r
+ write( "" )\r
+ end\r
+ end\r
+ return noread, nosend\r
+ end\r
+ local _readbuffer = function( ) -- this function reads data\r
+ local buffer, err, part = receive( socket, pattern ) -- receive buffer with "pattern"\r
+ if not err or ( err == "timeout" or err == "wantread" ) then -- received something\r
+ local buffer = buffer or part or ""\r
+ local len = string_len( buffer )\r
+ if len > maxreadlen then\r
+ disconnect( handler, "receive buffer exceeded" )\r
+ handler.close( true )\r
+ return false\r
+ end\r
+ local count = len * STAT_UNIT\r
+ readtraffic = readtraffic + count\r
+ _readtraffic = _readtraffic + count\r
+ _readtimes[ handler ] = _currenttime\r
+ --out_put( "server.lua: read data '", buffer, "', error: ", err )\r
+ return dispatch( handler, buffer, err )\r
+ else -- connections was closed or fatal error\r
+ out_put( "server.lua: client ", tostring(ip), ":", tostring(clientport), " error: ", tostring(err) )\r
+ fatalerror = true\r
+ disconnect( handler, err )\r
+ _ = handler and handler.close( )\r
+ return false\r
+ end\r
+ end\r
+ local _sendbuffer = function( ) -- this function sends data\r
+ local buffer = table_concat( bufferqueue, "", 1, bufferqueuelen )\r
+ local succ, err, byte = send( socket, buffer, 1, bufferlen )\r
+ local count = ( succ or byte or 0 ) * STAT_UNIT\r
+ sendtraffic = sendtraffic + count\r
+ _sendtraffic = _sendtraffic + count\r
+ _ = _cleanqueue and clean( bufferqueue )\r
+ --out_put( "server.lua: sended '", buffer, "', bytes: ", tostring(succ), ", error: ", tostring(err), ", part: ", tostring(byte), ", to: ", tostring(ip), ":", tostring(clientport) )\r
+ if succ then -- sending succesful\r
+ bufferqueuelen = 0\r
+ bufferlen = 0\r
+ _sendlistlen = removesocket( _sendlist, socket, _sendlistlen ) -- delete socket from writelist\r
+ _ = needtls and handler.starttls(true)\r
+ _writetimes[ handler ] = nil\r
+ _ = toclose and handler.close( )\r
+ return true\r
+ elseif byte and ( err == "timeout" or err == "wantwrite" ) then -- want write\r
+ buffer = string_sub( buffer, byte + 1, bufferlen ) -- new buffer\r
+ bufferqueue[ 1 ] = buffer -- insert new buffer in queue\r
+ bufferqueuelen = 1\r
+ bufferlen = bufferlen - byte\r
+ _writetimes[ handler ] = _currenttime\r
+ return true\r
+ else -- connection was closed during sending or fatal error\r
+ out_put( "server.lua: client ", tostring(ip), ":", tostring(clientport), " error: ", tostring(err) )\r
+ fatalerror = true\r
+ disconnect( handler, err )\r
+ _ = handler and handler.close( )\r
+ return false\r
+ end\r
+ end\r
+\r
+ if sslctx then -- ssl?\r
+ ssl = true\r
+ local wrote\r
+ local read\r
+ local handshake = coroutine_wrap( function( client ) -- create handshake coroutine\r
+ local err\r
+ for i = 1, 10 do -- 10 handshake attemps\r
+ _sendlistlen = ( wrote and removesocket( _sendlist, socket, _sendlistlen ) ) or _sendlistlen\r
+ _readlistlen = ( read and removesocket( _readlist, socket, _readlistlen ) ) or _readlistlen\r
+ read, wrote = nil, nil\r
+ _, err = client:dohandshake( )\r
+ if not err then\r
+ out_put( "server.lua: ssl handshake done" )\r
+ handler.readbuffer = _readbuffer -- when handshake is done, replace the handshake function with regular functions\r
+ handler.sendbuffer = _sendbuffer\r
+ -- return dispatch( handler )\r
+ return true\r
+ else\r
+ out_put( "server.lua: error during ssl handshake: ", tostring(err) )\r
+ if err == "wantwrite" and not wrote then\r
+ _sendlistlen = _sendlistlen + 1\r
+ _sendlist[ _sendlistlen ] = client\r
+ wrote = true\r
+ elseif err == "wantread" and not read then\r
+ _readlistlen = _readlistlen + 1\r
+ _readlist [ _readlistlen ] = client\r
+ read = true\r
+ else\r
+ break;\r
+ end\r
+ --coroutine_yield( handler, nil, err ) -- handshake not finished\r
+ coroutine_yield( )\r
+ end\r
+ end\r
+ disconnect( handler, "ssl handshake failed" )\r
+ _ = handler and handler.close( true ) -- forced disconnect\r
+ return false -- handshake failed\r
+ end\r
+ )\r
+ if startssl then -- ssl now?\r
+ --out_put("server.lua: ", "starting ssl handshake")\r
+ local err\r
+ socket, err = ssl_wrap( socket, sslctx ) -- wrap socket\r
+ if err then\r
+ out_put( "server.lua: ssl error: ", tostring(err) )\r
+ --mem_free( )\r
+ return nil, nil, err -- fatal error\r
+ end\r
+ socket:settimeout( 0 )\r
+ handler.readbuffer = handshake\r
+ handler.sendbuffer = handshake\r
+ handshake( socket ) -- do handshake\r
+ if not socket then\r
+ return nil, nil, "ssl handshake failed";\r
+ end\r
+ else\r
+ -- We're not automatically doing SSL, so we're not secure (yet)\r
+ ssl = false\r
+ handler.starttls = function( now )\r
+ if not now then\r
+ --out_put "server.lua: we need to do tls, but delaying until later"\r
+ needtls = true\r
+ return\r
+ end\r
+ --out_put( "server.lua: attempting to start tls on " .. tostring( socket ) )\r
+ local oldsocket, err = socket\r
+ socket, err = ssl_wrap( socket, sslctx ) -- wrap socket\r
+ --out_put( "server.lua: sslwrapped socket is " .. tostring( socket ) )\r
+ if err then\r
+ out_put( "server.lua: error while starting tls on client: ", tostring(err) )\r
+ return nil, err -- fatal error\r
+ end\r
+\r
+ socket:settimeout( 0 )\r
+\r
+ -- add the new socket to our system\r
+\r
+ send = socket.send\r
+ receive = socket.receive\r
+ shutdown = id\r
+\r
+ _socketlist[ socket ] = handler\r
+ _readlistlen = _readlistlen + 1\r
+ _readlist[ _readlistlen ] = socket\r
+ _readlist[ socket ] = _readlistlen\r
+\r
+ -- remove traces of the old socket\r
+\r
+ _readlistlen = removesocket( _readlist, oldsocket, _readlistlen )\r
+ _sendlistlen = removesocket( _sendlist, oldsocket, _sendlistlen )\r
+ _socketlist[ oldsocket ] = nil\r
+\r
+ handler.starttls = nil\r
+ needtls = nil\r
+ \r
+ -- Secure now\r
+ ssl = true\r
+\r
+ handler.readbuffer = handshake\r
+ handler.sendbuffer = handshake\r
+ handshake( socket ) -- do handshake\r
+ end\r
+ handler.readbuffer = _readbuffer\r
+ handler.sendbuffer = _sendbuffer\r
+ end\r
+ else -- normal connection\r
+ ssl = false\r
+ handler.readbuffer = _readbuffer\r
+ handler.sendbuffer = _sendbuffer\r
+ end\r
+\r
+ send = socket.send\r
+ receive = socket.receive\r
+ shutdown = ( ssl and id ) or socket.shutdown\r
+\r
+ _socketlist[ socket ] = handler\r
+ _readlistlen = _readlistlen + 1\r
+ _readlist[ _readlistlen ] = socket\r
+ _readlist[ socket ] = _readlistlen\r
+\r
+ return handler, socket\r