X-Git-Url: https://git.enpas.org/?a=blobdiff_plain;f=net%2Fserver.lua;h=375e7081f670bb760f46fe8df757215a34e9617d;hb=f50f4cb01c079cfa913a76313859e469abbda12e;hp=40f37345426ee08a58701d91403d95d794ae34e5;hpb=d89c152af0fc16985a6b9da1e5592875a7b9fa7a;p=prosody.git diff --git a/net/server.lua b/net/server.lua index 40f37345..375e7081 100644 --- a/net/server.lua +++ b/net/server.lua @@ -1,840 +1,84 @@ ---[[ - - server.lua by blastbeat of the luadch project - - re-used here under the MIT/X Consortium License - - - this script contains the server loop of the program - - other scripts can reg a server here - -]]-- - -----------------------------------// DECLARATION //-- - ---// constants //-- - -local STAT_UNIT = 1 / ( 1024 * 1024 ) -- mb - ---// lua functions //-- - -local function use( what ) return _G[ what ] end - -local type = use "type" -local pairs = use "pairs" -local ipairs = use "ipairs" -local tostring = use "tostring" -local collectgarbage = use "collectgarbage" - ---// lua libs //-- - -local table = use "table" -local coroutine = use "coroutine" - ---// lua lib methods //-- - -local table_concat = table.concat -local table_remove = table.remove -local string_sub = use'string'.sub -local coroutine_wrap = coroutine.wrap -local coroutine_yield = coroutine.yield -local print = print; -local out_put = function () end --print; -local out_error = print; - ---// extern libs //-- - -local luasec = select(2, pcall(require, "ssl")) -local luasocket = require "socket" - ---// extern lib methods //-- - -local ssl_wrap = ( luasec and luasec.wrap ) -local socket_bind = luasocket.bind -local socket_select = luasocket.select -local ssl_newcontext = ( luasec and luasec.newcontext ) - ---// functions //-- - -local loop -local stats -local addtimer -local closeall -local addserver -local firetimer -local closesocket -local removesocket -local wrapserver -local wraptcpclient -local wrapsslclient - ---// tables //-- - -local listener -local readlist -local writelist -local socketlist -local timelistener - ---// simple data types //-- - -local _ -local readlen = 0 -- length of readlist -local writelen = 0 -- lenght of writelist - -local sendstat= 0 -local receivestat = 0 - -----------------------------------// DEFINITION //-- - -listener = { } -- key = port, value = table -readlist = { } -- array with sockets to read from -writelist = { } -- arrary with sockets to write to -socketlist = { } -- key = socket, value = wrapped socket -timelistener = { } - -stats = function( ) - return receivestat, sendstat -end - -wrapserver = function( listener, socket, ip, serverport, mode, sslctx ) -- this function wraps a server - - local dispatch, disconnect = listener.listener, listener.disconnect -- dangerous - - local wrapclient, err - - if sslctx then - if not ssl_newcontext then - return nil, "luasec not found" - end - if type( sslctx ) ~= "table" then - out_error "server.lua: wrong server sslctx" - return nil, "wrong server sslctx" - end - sslctx, err = ssl_newcontext( sslctx ) - if not sslctx then - err = err or "wrong sslctx parameters" - out_error( "server.lua: ", err ) - return nil, err - end - wrapclient = wrapsslclient - wrapclient = wraptlsclient - else - wrapclient = wraptcpclient - end - - local accept = socket.accept - local close = socket.close - - --// public methods of the object //-- - - local handler = { } - - handler.shutdown = function( ) end - - --[[handler.listener = function( data, err ) - return ondata( handler, data, err ) - end]] - handler.ssl = function( ) - return sslctx and true or false - end - handler.close = function( closed ) - _ = not closed and close( socket ) - writelen = removesocket( writelist, socket, writelen ) - readlen = removesocket( readlist, socket, readlen ) - socketlist[ socket ] = nil - handler = nil - end - handler.ip = function( ) - return ip - end - handler.serverport = function( ) - return serverport - end - handler.socket = function( ) - return socket - end - handler.receivedata = function( ) - local client, err = accept( socket ) -- try to accept - if client then - local ip, clientport = client:getpeername( ) - client:settimeout( 0 ) - local handler, client, err = wrapclient( listener, client, ip, serverport, clientport, mode, sslctx ) -- wrap new client socket - if err then -- error while wrapping ssl socket - return false - end - out_put( "server.lua: accepted new client connection from ", ip, ":", clientport ) - return dispatch( handler ) - elseif err then -- maybe timeout or something else - out_put( "server.lua: error with new client connection: ", err ) - return false - end - end - return handler -end - -wrapsslclient = function( listener, socket, ip, serverport, clientport, mode, sslctx ) -- this function wraps a ssl cleint - - local dispatch, disconnect = listener.listener, listener.disconnect - - --// transform socket to ssl object //-- - - local err - socket, err = ssl_wrap( socket, sslctx ) -- wrap socket - if err then - out_put( "server.lua: ssl error: ", err ) - return nil, nil, err -- fatal error - end - socket:settimeout( 0 ) - - --// private closures of the object //-- - - local writequeue = { } -- buffer for messages to send - - local eol, fatal_send_error -- end of buffer - - local sstat, rstat = 0, 0 - - --// local import of socket methods //-- - - local send = socket.send - local receive = socket.receive - local close = socket.close - --local shutdown = socket.shutdown - - --// public methods of the object //-- - - local handler = { } - - handler.getstats = function( ) - return rstat, sstat - end - - handler.listener = function( data, err ) - return listener( handler, data, err ) - end - handler.ssl = function( ) - return true - end - handler.send = function( _, data, i, j ) - return send( socket, data, i, j ) - end - handler.receive = function( pattern, prefix ) - return receive( socket, pattern, prefix ) - end - handler.shutdown = function( pattern ) - --return shutdown( socket, pattern ) - end - handler.close = function( closed ) - if eol and not fatal_send_error then handler._dispatchdata(); end - close( socket ) - writelen = ( eol and removesocket( writelist, socket, writelen ) ) or writelen - readlen = removesocket( readlist, socket, readlen ) - socketlist[ socket ] = nil - out_put "server.lua: closed handler and removed socket from list" - end - handler.ip = function( ) - return ip - end - handler.serverport = function( ) - return serverport - end - handler.clientport = function( ) - return clientport - end - - handler.write = function( data ) - if not eol then - writelen = writelen + 1 - writelist[ writelen ] = socket - eol = 0 - end - eol = eol + 1 - writequeue[ eol ] = data - end - handler.writequeue = function( ) - return writequeue - end - handler.socket = function( ) - return socket - end - handler.mode = function( ) - return mode - end - handler._receivedata = function( ) - local data, err, part = receive( socket, mode ) -- receive data in "mode" - if not err or ( err == "timeout" or err == "wantread" ) then -- received something - local data = data or part or "" - local count = #data * STAT_UNIT - rstat = rstat + count - receivestat = receivestat + count - out_put( "server.lua: read data '", data, "', error: ", err ) - return dispatch( handler, data, err ) - else -- connections was closed or fatal error - out_put( "server.lua: client ", ip, ":", clientport, " error: ", err ) - handler.close( ) - disconnect( handler, err ) - writequeue = nil - handler = nil - return false - end - end - handler._dispatchdata = function( ) -- this function writes data to handlers - local buffer = table_concat( writequeue, "", 1, eol ) - local succ, err, byte = send( socket, buffer ) - local count = ( succ or 0 ) * STAT_UNIT - sstat = sstat + count - sendstat = sendstat + count - out_put( "server.lua: sended '", buffer, "', bytes: ", succ, ", error: ", err, ", part: ", byte, ", to: ", ip, ":", clientport ) - if succ then -- sending succesful - --writequeue = { } - eol = nil - writelen = removesocket( writelist, socket, writelen ) -- delete socket from writelist - return true - elseif byte and ( err == "timeout" or err == "wantwrite" ) then -- want write - buffer = string_sub( buffer, byte + 1, -1 ) -- new buffer - writequeue[ 1 ] = buffer -- insert new buffer in queue - eol = 1 - return true - else -- connection was closed during sending or fatal error - fatal_send_error = true; - out_put( "server.lua: client ", ip, ":", clientport, " error: ", err ) - handler.close( ) - disconnect( handler, err ) - writequeue = nil - handler = nil - return false - end - end - - -- // COMPAT // -- - - handler.getIp = handler.ip - handler.getPort = handler.clientport - - --// handshake //-- - - local wrote - - handler.handshake = coroutine_wrap( function( client ) - local err - for i = 1, 10 do -- 10 handshake attemps - _, err = client:dohandshake( ) - if not err then - out_put( "server.lua: ssl handshake done" ) - writelen = ( wrote and removesocket( writelist, socket, writelen ) ) or writelen - handler.receivedata = handler._receivedata -- when handshake is done, replace the handshake function with regular functions - handler.dispatchdata = handler._dispatchdata - return dispatch( handler ) - else - out_put( "server.lua: error during ssl handshake: ", err ) - if err == "wantwrite" then - if wrote == nil then - writelen = writelen + 1 - writelist[ writelen ] = client - wrote = true - end - end - coroutine_yield( handler, nil, err ) -- handshake not finished - end - end - _ = err ~= "closed" and close( socket ) - handler.close( ) - disconnect( handler, err ) - writequeue = nil - handler = nil - return false -- handshake failed - end - ) - handler.receivedata = handler.handshake - handler.dispatchdata = handler.handshake - - handler.handshake( socket ) -- do handshake - - socketlist[ socket ] = handler - readlen = readlen + 1 - readlist[ readlen ] = socket - - return handler, socket -end - -wraptlsclient = function( listener, socket, ip, serverport, clientport, mode, sslctx ) -- this function wraps a tls cleint - - local dispatch, disconnect = listener.listener, listener.disconnect - - --// transform socket to ssl object //-- - - local err - - socket:settimeout( 0 ) - out_put("setting linger on "..tostring(socket)) - socket:setoption("linger", { on = true, timeout = 10 }); - --// private closures of the object //-- - - local writequeue = { } -- buffer for messages to send - - local eol, fatal_send_error -- end of buffer - - local sstat, rstat = 0, 0 - - --// local import of socket methods //-- - - local send = socket.send - local receive = socket.receive - local close = socket.close - --local shutdown = socket.shutdown - - --// public methods of the object //-- - - local handler = { } - - handler.getstats = function( ) - return rstat, sstat - end - - handler.listener = function( data, err ) - return listener( handler, data, err ) - end - handler.ssl = function( ) - return false - end - handler.send = function( _, data, i, j ) - return send( socket, data, i, j ) - end - handler.receive = function( pattern, prefix ) - return receive( socket, pattern, prefix ) - end - handler.shutdown = function( pattern ) - --return shutdown( socket, pattern ) - end - handler.close = function( closed ) - if eol and not fatal_send_error then handler._dispatchdata(); end - close( socket ) - writelen = ( eol and removesocket( writelist, socket, writelen ) ) or writelen - readlen = removesocket( readlist, socket, readlen ) - socketlist[ socket ] = nil - out_put "server.lua: closed handler and removed socket from list" - end - handler.ip = function( ) - return ip - end - handler.serverport = function( ) - return serverport - end - handler.clientport = function( ) - return clientport - end - - handler.write = function( data ) - if not eol then - writelen = writelen + 1 - writelist[ writelen ] = socket - eol = 0 - end - eol = eol + 1 - writequeue[ eol ] = data - end - handler.writequeue = function( ) - return writequeue - end - handler.socket = function( ) - return socket - end - handler.mode = function( ) - return mode - end - handler._receivedata = function( ) - local data, err, part = receive( socket, mode ) -- receive data in "mode" - if not err or ( err == "timeout" or err == "wantread" ) then -- received something - local data = data or part or "" - local count = #data * STAT_UNIT - rstat = rstat + count - receivestat = receivestat + count - --out_put( "server.lua: read data '", data, "', error: ", err ) - return dispatch( handler, data, err ) - else -- connections was closed or fatal error - out_put( "server.lua: client ", ip, ":", clientport, " error: ", err ) - handler.close( ) - disconnect( handler, err ) - writequeue = nil - handler = nil - return false - end - end - handler._dispatchdata = function( ) -- this function writes data to handlers - local buffer = table_concat( writequeue, "", 1, eol ) - local succ, err, byte = send( socket, buffer ) - local count = ( succ or 0 ) * STAT_UNIT - sstat = sstat + count - sendstat = sendstat + count - out_put( "server.lua: sended '", buffer, "', bytes: ", succ, ", error: ", err, ", part: ", byte, ", to: ", ip, ":", clientport ) - if succ then -- sending succesful - --writequeue = { } - eol = nil - writelen = removesocket( writelist, socket, writelen ) -- delete socket from writelist - if handler.need_tls then - out_put("server.lua: connection is ready for tls handshake"); - handler.starttls(true); - if handler.need_tls then - out_put("server.lua: uh-oh... we still want tls, something must be wrong"); - end - end - return true - elseif byte and ( err == "timeout" or err == "wantwrite" ) then -- want write - buffer = string_sub( buffer, byte + 1, -1 ) -- new buffer - writequeue[ 1 ] = buffer -- insert new buffer in queue - eol = 1 - return true - else -- connection was closed during sending or fatal error - fatal_send_error = true; -- :( - out_put( "server.lua: client ", ip, ":", clientport, " error: ", err ) - handler.close( ) - disconnect( handler, err ) - writequeue = nil - handler = nil - return false - end - end - - handler.receivedata, handler.dispatchdata = handler._receivedata, handler._dispatchdata; - -- // COMPAT // -- - - handler.getIp = handler.ip - handler.getPort = handler.clientport - - --// handshake //-- - - local wrote, read - - handler.starttls = function (now) - if not now then out_put("server.lua: we need to do tls, but delaying until later"); handler.need_tls = true; return; end - out_put( "server.lua: attempting to start tls on "..tostring(socket) ) - socket, err = ssl_wrap( socket, sslctx ) -- wrap socket - out_put("sslwrapped socket is "..tostring(socket)); - if err then - out_put( "server.lua: ssl error: ", err ) - return nil, nil, err -- fatal error - end - socket:settimeout( 1 ) - send = socket.send - receive = socket.receive - close = socket.close - handler.ssl = function( ) - return true - end - handler.send = function( _, data, i, j ) - return send( socket, data, i, j ) - end - handler.receive = function( pattern, prefix ) - return receive( socket, pattern, prefix ) - end - - handler.starttls = nil; - - handler.handshake = coroutine_wrap( function( client ) - local err - for i = 1, 10 do -- 10 handshake attemps - _, err = client:dohandshake( ) - if not err then - out_put( "server.lua: ssl handshake done" ) - writelen = ( wrote and removesocket( writelist, socket, writelen ) ) or writelen - handler.receivedata = handler._receivedata -- when handshake is done, replace the handshake function with regular functions - handler.dispatchdata = handler._dispatchdata - handler.need_tls = nil - socketlist[ client ] = handler - readlen = readlen + 1 - readlist[ readlen ] = client - return true; - else - out_put( "server.lua: error during ssl handshake: ", err ) - if err == "wantwrite" then - if wrote == nil then - writelen = writelen + 1 - writelist[ writelen ] = client - wrote = true - end - end - coroutine_yield( handler, nil, err ) -- handshake not finished - end - end - _ = err ~= "closed" and close( socket ) - handler.close( ) - disconnect( handler, err ) - writequeue = nil - handler = nil - return false -- handshake failed - end - ) - handler.receivedata = handler.handshake - handler.dispatchdata = handler.handshake - - handler.handshake( socket ) -- do handshake - end - socketlist[ socket ] = handler - readlen = readlen + 1 - readlist[ readlen ] = socket - - return handler, socket -end - -wraptcpclient = function( listener, socket, ip, serverport, clientport, mode ) -- this function wraps a socket - - local dispatch, disconnect = listener.listener, listener.disconnect - - --// private closures of the object //-- - - local writequeue = { } -- list for messages to send - - local eol, fatal_send_error - - local rstat, sstat = 0, 0 - - --// local import of socket methods //-- - - local send = socket.send - local receive = socket.receive - local close = socket.close - local shutdown = socket.shutdown - - --// public methods of the object //-- - - local handler = { } - - handler.getstats = function( ) - return rstat, sstat - end - - handler.listener = function( data, err ) - return listener( handler, data, err ) - end - handler.ssl = function( ) - return false - end - handler.send = function( _, data, i, j ) - return send( socket, data, i, j ) - end - handler.receive = function( pattern, prefix ) - return receive( socket, pattern, prefix ) - end - handler.shutdown = function( pattern ) - return shutdown( socket, pattern ) - end - handler.close = function( closed ) - if eol and not fatal_send_error then handler.dispatchdata(); end - _ = not closed and shutdown( socket ) - _ = not closed and close( socket ) - writelen = ( eol and removesocket( writelist, socket, writelen ) ) or writelen - readlen = removesocket( readlist, socket, readlen ) - socketlist[ socket ] = nil - out_put "server.lua: closed handler and removed socket from list" - end - handler.ip = function( ) - return ip - end - handler.serverport = function( ) - return serverport - end - handler.clientport = function( ) - return clientport - end - handler.write = function( data ) - if not eol then - writelen = writelen + 1 - writelist[ writelen ] = socket - eol = 0 - end - eol = eol + 1 - writequeue[ eol ] = data - end - handler.writequeue = function( ) - return writequeue - end - handler.socket = function( ) - return socket - end - handler.mode = function( ) - return mode - end - - handler.receivedata = function( ) - local data, err, part = receive( socket, mode ) -- receive data in "mode" - if not err or ( err == "timeout" or err == "wantread" ) then -- received something - local data = data or part or "" - local count = #data * STAT_UNIT - rstat = rstat + count - receivestat = receivestat + count - out_put( "server.lua: read data '", data, "', error: ", err ) - return dispatch( handler, data, err ) - else -- connections was closed or fatal error - out_put( "server.lua: client ", ip, ":", clientport, " error: ", err ) - handler.close( ) - disconnect( handler, err ) - writequeue = nil - handler = nil - return false - end - end - - handler.dispatchdata = function( ) -- this function writes data to handlers - local buffer = table_concat( writequeue, "", 1, eol ) - local succ, err, byte = send( socket, buffer ) - local count = ( succ or 0 ) * STAT_UNIT - sstat = sstat + count - sendstat = sendstat + count - out_put( "server.lua: sended '", buffer, "', bytes: ", succ, ", error: ", err, ", part: ", byte, ", to: ", ip, ":", clientport ) - if succ then -- sending succesful - --writequeue = { } - eol = nil - writelen = removesocket( writelist, socket, writelen ) -- delete socket from writelist - return true - elseif byte and ( err == "timeout" or err == "wantwrite" ) then -- want write - buffer = string_sub( buffer, byte + 1, -1 ) -- new buffer - writequeue[ 1 ] = buffer -- insert new buffer in queue - eol = 1 - return true - else -- connection was closed during sending or fatal error - fatal_send_error = true; -- :'-( - out_put( "server.lua: client ", ip, ":", clientport, " error: ", err ) - handler.close( ) - disconnect( handler, err ) - writequeue = nil - handler = nil - return false - end - end - - -- // COMPAT // -- - - handler.getIp = handler.ip - handler.getPort = handler.clientport - - socketlist[ socket ] = handler - readlen = readlen + 1 - readlist[ readlen ] = socket - - return handler, socket -end - -addtimer = function( listener ) - timelistener[ #timelistener + 1 ] = listener -end - -firetimer = function( listener ) - for i, listener in ipairs( timelistener ) do - listener( ) - end -end - -addserver = function( listeners, port, addr, mode, sslctx ) -- this function provides a way for other scripts to reg a server - local err - if type( listeners ) ~= "table" then - err = "invalid listener table" - else - for name, func in pairs( listeners ) do - if type( func ) ~= "function" then - --err = "invalid listener function" - break - end - end - end - if not type( port ) == "number" or not ( port >= 0 and port <= 65535 ) then - err = "invalid port" - elseif listener[ port ] then - err= "listeners on port '" .. port .. "' already exist" - elseif sslctx and not luasec then - err = "luasec not found" - end - if err then - out_error( "server.lua: ", err ) - return nil, err - end - addr = addr or "*" - local server, err = socket_bind( addr, port ) - if err then - out_error( "server.lua: ", err ) - return nil, err - end - local handler, err = wrapserver( listeners, server, addr, port, mode, sslctx ) -- wrap new server socket - if not handler then - server:close( ) - return nil, err - end - server:settimeout( 0 ) - readlen = readlen + 1 - readlist[ readlen ] = server - listener[ port ] = listeners - socketlist[ server ] = handler - out_put( "server.lua: new server listener on ", addr, ":", port ) - return true -end - -removesocket = function( tbl, socket, len ) -- this function removes sockets from a list - for i, target in ipairs( tbl ) do - if target == socket then - len = len - 1 - table_remove( tbl, i ) - return len - end - end - return len -end - -closeall = function( ) - for sock, handler in pairs( socketlist ) do - handler.shutdown( ) - handler.close( ) - socketlist[ sock ] = nil - end - writelist, readlist, socketlist = { }, { }, { } -end - -closesocket = function( socket ) - writelen = removesocket( writelist, socket, writelen ) - readlen = removesocket( readlist, socket, readlen ) - socketlist[ socket ] = nil - socket:close( ) -end - -loop = function( ) -- this is the main loop of the program - --signal_set( "hub", "run" ) - repeat - --[[print(readlen, writelen) - for _, s in ipairs(readlist) do print("R:", tostring(s)) end - for _, s in ipairs(writelist) do print("W:", tostring(s)) end - out_put("select()"..os.time())]] - local read, write, err = socket_select( readlist, writelist, 1 ) -- 1 sec timeout, nice for timers - for i, socket in ipairs( write ) do -- send data waiting in writequeues - local handler = socketlist[ socket ] - if handler then - handler.dispatchdata( ) - else - closesocket( socket ) - out_put "server.lua: found no handler and closed socket (writelist)" -- this should not happen - end - end - for i, socket in ipairs( read ) do -- receive data - local handler = socketlist[ socket ] - if handler then - handler.receivedata( ) - else - closesocket( socket ) - out_put "server.lua: found no handler and closed socket (readlist)" -- this can happen - end - end - firetimer( ) - until false - return -end - -----------------------------------// BEGIN //-- - -----------------------------------// PUBLIC INTERFACE //-- - -return { - - add = addserver, - loop = loop, - stats = stats, - closeall = closeall, - addtimer = addtimer, - wraptlsclient = wraptlsclient, -} +-- Prosody IM +-- Copyright (C) 2008-2010 Matthew Wild +-- Copyright (C) 2008-2010 Waqas Hussain +-- +-- This project is MIT/X11 licensed. Please see the +-- COPYING file in the source package for more information. +-- + +local use_luaevent = prosody and require "core.configmanager".get("*", "use_libevent"); + +if use_luaevent then + use_luaevent = pcall(require, "luaevent.core"); + if not use_luaevent then + log("error", "libevent not found, falling back to select()"); + end +end + +local server; + +if use_luaevent then + server = require "net.server_event"; + + -- Overwrite signal.signal() because we need to ask libevent to + -- handle them instead + local ok, signal = pcall(require, "util.signal"); + if ok and signal then + local _signal_signal = signal.signal; + function signal.signal(signal_id, handler) + if type(signal_id) == "string" then + signal_id = signal[signal_id:upper()]; + end + if type(signal_id) ~= "number" then + return false, "invalid-signal"; + end + return server.hook_signal(signal_id, handler); + end + end +else + use_luaevent = false; + server = require "net.server_select"; +end + +if prosody then + local config_get = require "core.configmanager".get; + local defaults = {}; + for k,v in pairs(server.cfg or server.getsettings()) do + defaults[k] = v; + end + local function load_config() + local settings = config_get("*", "network_settings") or {}; + if use_luaevent then + local event_settings = { + ACCEPT_DELAY = settings.event_accept_retry_interval; + ACCEPT_QUEUE = settings.tcp_backlog; + CLEAR_DELAY = settings.event_clear_interval; + CONNECT_TIMEOUT = settings.connect_timeout; + DEBUG = settings.debug; + HANDSHAKE_TIMEOUT = settings.ssl_handshake_timeout; + MAX_CONNECTIONS = settings.max_connections; + MAX_HANDSHAKE_ATTEMPTS = settings.max_ssl_handshake_roundtrips; + MAX_READ_LENGTH = settings.max_receive_buffer_size; + MAX_SEND_LENGTH = settings.max_send_buffer_size; + READ_TIMEOUT = settings.read_timeout; + WRITE_TIMEOUT = settings.send_timeout; + }; + + for k,default in pairs(defaults) do + server.cfg[k] = event_settings[k] or default; + end + else + local select_settings = {}; + for k,default in pairs(defaults) do + select_settings[k] = settings[k] or default; + end + server.changesettings(select_settings); + end + end + load_config(); + prosody.events.add_handler("config-reloaded", load_config); +end + +-- require "net.server" shall now forever return this, +-- ie. server_select or server_event as chosen above. +return server;