Convert the login server to a supervisor-compatible module.
This commit is contained in:
parent
982b821415
commit
b85826c06a
ebin
priv
src
@ -10,7 +10,7 @@
|
||||
egs_cron,
|
||||
egs_db,
|
||||
egs_game,
|
||||
egs_login,
|
||||
psu_login,
|
||||
psu_patch,
|
||||
egs_proto,
|
||||
psu_appearance,
|
||||
|
@ -51,7 +51,9 @@ init([]) ->
|
||||
%% Start egs_cron, egs_game, egs_login, egs_patch. To be replaced by configurable modules.
|
||||
Processes = [{egs_cron, {egs_cron, start, []}, permanent, 5000, worker, dynamic},
|
||||
{egs_game, {egs_game, start, []}, permanent, 5000, worker, dynamic},
|
||||
{egs_login, {egs_login, start, []}, permanent, 5000, worker, dynamic},
|
||||
{psu_login_jp1, {psu_login, start_link, [?LOGIN_PORT_JP_ONE, 10000001]}, permanent, 5000, worker, dynamic},
|
||||
{psu_login_jp2, {psu_login, start_link, [?LOGIN_PORT_JP_TWO, 20000001]}, permanent, 5000, worker, dynamic},
|
||||
{psu_login_us, {psu_login, start_link, [?LOGIN_PORT_US, 30000001]}, permanent, 5000, worker, dynamic},
|
||||
{psu_patch_jp, {psu_patch, start_link, [?PATCH_PORT_JP]}, permanent, 5000, worker, dynamic},
|
||||
{psu_patch_us, {psu_patch, start_link, [?PATCH_PORT_US]}, permanent, 5000, worker, dynamic}],
|
||||
{ok, {{one_for_one, 10, 10}, Processes}}.
|
||||
|
@ -1,77 +1,75 @@
|
||||
% EGS: Erlang Game Server
|
||||
% Copyright (C) 2010 Loic Hoguin
|
||||
%
|
||||
% This file is part of EGS.
|
||||
%
|
||||
% EGS is free software: you can redistribute it and/or modify
|
||||
% it under the terms of the GNU General Public License as published by
|
||||
% the Free Software Foundation, either version 3 of the License, or
|
||||
% (at your option) any later version.
|
||||
%
|
||||
% EGS is distributed in the hope that it will be useful,
|
||||
% but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
% GNU General Public License for more details.
|
||||
%
|
||||
% You should have received a copy of the GNU General Public License
|
||||
% along with EGS. If not, see <http://www.gnu.org/licenses/>.
|
||||
%% @author Loïc Hoguin <essen@dev-extend.eu>
|
||||
%% @copyright 2010 Loïc Hoguin.
|
||||
%% @doc Process login requests.
|
||||
%%
|
||||
%% This file is part of EGS.
|
||||
%%
|
||||
%% EGS is free software: you can redistribute it and/or modify
|
||||
%% it under the terms of the GNU General Public License as published by
|
||||
%% the Free Software Foundation, either version 3 of the License, or
|
||||
%% (at your option) any later version.
|
||||
%%
|
||||
%% EGS is distributed in the hope that it will be useful,
|
||||
%% but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
%% GNU General Public License for more details.
|
||||
%%
|
||||
%% You should have received a copy of the GNU General Public License
|
||||
%% along with EGS. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
-module(egs_login).
|
||||
-export([start/0]). % external
|
||||
-export([listen/2, accept/2, process/2, loop/2]). % internal
|
||||
-module(psu_login).
|
||||
-export([start_link/2]). %% External.
|
||||
-export([listen/2, accept/2, process/2, loop/2]). %% Internal.
|
||||
|
||||
-include("include/records.hrl").
|
||||
-include("include/network.hrl").
|
||||
|
||||
%% @doc Start the login server. Currently AOTI JP and US only.
|
||||
-define(OPTIONS, [binary, {active, false}, {certfile, "priv/ssl/servercert.pem"}, {keyfile, "priv/ssl/serverkey.pem"}, {password, "alpha"}]).
|
||||
|
||||
start() ->
|
||||
spawn_link(?MODULE, listen, [?LOGIN_PORT_JP_ONE, 10000001]),
|
||||
spawn_link(?MODULE, listen, [?LOGIN_PORT_JP_TWO, 20000001]),
|
||||
USPid = spawn_link(?MODULE, listen, [?LOGIN_PORT_US, 30000001]),
|
||||
{ok, USPid}.
|
||||
%% @spec start_link(Port) -> {ok,Pid::pid()}
|
||||
%% @doc Start the PSU login server for inclusion in a supervisor tree.
|
||||
start_link(Port, SessionID) ->
|
||||
Pid = spawn(?MODULE, listen, [Port, SessionID]),
|
||||
{ok, Pid}.
|
||||
|
||||
%% @spec listen(Port, SessionID) -> ok
|
||||
%% @doc Listen for connections.
|
||||
|
||||
listen(Port, SessionID) ->
|
||||
process_flag(trap_exit, true),
|
||||
{ok, LSocket} = ssl:listen(Port, ?LOGIN_LISTEN_OPTIONS),
|
||||
{ok, LSocket} = ssl:listen(Port, ?OPTIONS),
|
||||
?MODULE:accept(LSocket, SessionID).
|
||||
|
||||
%% @spec accept(LSocket, SessionID) -> ok
|
||||
%% @doc Accept connections.
|
||||
|
||||
accept(LSocket, SessionID) ->
|
||||
case ssl:transport_accept(LSocket, 5000) of
|
||||
{ok, CSocket} ->
|
||||
% in the future, modulo to avoid conflicts future with real GIDs
|
||||
%~ NextID = (SessionID + 1) rem 1000000,
|
||||
%% in the future, modulo to avoid conflicts future with real GIDs
|
||||
%% NextID = (SessionID + 1) rem 1000000,
|
||||
NextID = SessionID + 1,
|
||||
ssl:ssl_accept(CSocket),
|
||||
spawn_link(?MODULE, process, [CSocket, SessionID]);
|
||||
_ ->
|
||||
spawn(?MODULE, process, [CSocket, SessionID]);
|
||||
{error, _Reason} ->
|
||||
NextID = SessionID,
|
||||
reload
|
||||
end,
|
||||
?MODULE:accept(LSocket, NextID).
|
||||
|
||||
%% @spec process(CSocket, SessionID) -> ok
|
||||
%% @doc Process the new connections. Send an hello packet and start the loop.
|
||||
|
||||
process(CSocket, SessionID) ->
|
||||
log(SessionID, "hello"),
|
||||
egs_proto:packet_send(CSocket, << 16#02020300:32, 0:288, SessionID:32/little-unsigned-integer >>),
|
||||
?MODULE:loop(CSocket, SessionID).
|
||||
|
||||
%% @spec loop(CSocket, SessionID) -> ok
|
||||
%% @doc Main loop for the login server.
|
||||
|
||||
loop(CSocket, SessionID) ->
|
||||
case egs_proto:packet_recv(CSocket, 5000) of
|
||||
{ok, Orig} ->
|
||||
<< _:32, Command:16/unsigned-integer, _/bits >> = Orig,
|
||||
case handle(Command, CSocket, SessionID, Orig) of
|
||||
closed ->
|
||||
ignore;
|
||||
_ ->
|
||||
?MODULE:loop(CSocket, SessionID)
|
||||
closed -> ok;
|
||||
_ -> ?MODULE:loop(CSocket, SessionID)
|
||||
end;
|
||||
{error, timeout} ->
|
||||
reload,
|
||||
@ -81,8 +79,11 @@ loop(CSocket, SessionID) ->
|
||||
egs_db:users_delete(SessionID)
|
||||
end.
|
||||
|
||||
%% @doc Game server info request handler.
|
||||
%% @spec handle(Command, CSocket, SessionID, Orig) -> ok | closed
|
||||
%% @doc Login server client commands handler.
|
||||
|
||||
%% Game server info request handler.
|
||||
%% @todo Remove the dependency on network.hrl
|
||||
handle(16#0217, CSocket, SessionID, _) ->
|
||||
log(SessionID, "forward to game server"),
|
||||
IP = ?GAME_IP,
|
||||
@ -92,12 +93,11 @@ handle(16#0217, CSocket, SessionID, _) ->
|
||||
ssl:close(CSocket),
|
||||
closed;
|
||||
|
||||
%% @doc Authentication request handler. Currently always succeed.
|
||||
%% Use the temporary session ID as the GID for now.
|
||||
%% Use username and password as a folder name for saving character data.
|
||||
%% Authentication request handler. Currently always succeed.
|
||||
%% Use the temporary session ID as the GID for now.
|
||||
%% Use username and password as a folder name for saving character data.
|
||||
%% @todo Handle real GIDs whenever there's real authentication. GID is the second SessionID in the reply.
|
||||
%% @todo Apparently it's possible to ask a question in the reply here. Used for free course on JP.
|
||||
|
||||
handle(16#0219, CSocket, SessionID, Orig) ->
|
||||
<< _:352, UsernameBlob:192/bits, PasswordBlob:192/bits, _/bits >> = Orig,
|
||||
Username = re:replace(UsernameBlob, "\\0", "", [global, {return, binary}]),
|
||||
@ -110,35 +110,34 @@ handle(16#0219, CSocket, SessionID, Orig) ->
|
||||
Packet = << 16#02230300:32, 0:192, SessionID:32/little-unsigned-integer, 0:64, SessionID:32/little-unsigned-integer, Auth:32/bits >>,
|
||||
egs_proto:packet_send(CSocket, Packet);
|
||||
|
||||
%% @doc MOTD request handler. Handles both forms of MOTD requests, US and JP. Page number starts at 0.
|
||||
%% MOTD request handler. Handles both forms of MOTD requests, US and JP. Page number starts at 0.
|
||||
%% @todo Currently ignore the language and send the same MOTD file to everyone. Language is 8 bits next to Page.
|
||||
%% @todo Use a normal ASCII file rather than an UCS2 one?
|
||||
|
||||
handle(Command, CSocket, SessionID, Orig) when Command =:= 16#0226; Command =:= 16#023f ->
|
||||
<< _:352, Page:8/little-unsigned-integer, _/bits >> = Orig,
|
||||
log(SessionID, "send MOTD page ~.10b", [Page + 1]),
|
||||
{ok, File} = file:read_file("conf/motd.txt"),
|
||||
{ok, File} = file:read_file("priv/psu_login/motd.txt"),
|
||||
Tokens = re:split(File, "\n."),
|
||||
MOTD = << << Line/binary, "\n", 0 >> || Line <- lists:sublist(Tokens, 1 + Page * 15, 15) >>,
|
||||
NbPages = 1 + length(Tokens) div 15,
|
||||
Packet = << 16#0225:16, 0:304, NbPages:8, Page:8, 16#8200:16/unsigned-integer, MOTD/binary, 0:16 >>,
|
||||
egs_proto:packet_send(CSocket, Packet);
|
||||
|
||||
%% @doc Silently ignore packets 0227 and 080e.
|
||||
|
||||
%% Silently ignore packets 0227 and 080e.
|
||||
handle(Command, _, _, _) when Command =:= 16#0227; Command =:= 16#080e ->
|
||||
ignore;
|
||||
|
||||
%% @doc Unknown command handler. Print a log message about it.
|
||||
|
||||
%% Unknown command handler. Print a log message about it.
|
||||
handle(Command, _, SessionID, _) ->
|
||||
log(SessionID, "dismissed packet ~4.16.0b", [Command]).
|
||||
|
||||
%% @spec log(SessionID, Message) -> ok
|
||||
%% @doc Log message to the console.
|
||||
|
||||
log(SessionID, Message) ->
|
||||
io:format("login (~.10b): ~s~n", [SessionID, Message]).
|
||||
|
||||
%% @spec log(SessionID, Message, Format) -> ok
|
||||
%% @doc Format a message and log it to the console.
|
||||
log(SessionID, Message, Format) ->
|
||||
RealMessage = io_lib:format(Message, Format),
|
||||
log(SessionID, RealMessage).
|
@ -24,7 +24,7 @@
|
||||
-define(OPTIONS, [binary, {send_timeout, 5000}, {packet, 0}, {active, false}, {reuseaddr, true}]).
|
||||
|
||||
%% @spec start_link(Port) -> {ok,Pid::pid()}
|
||||
%% @doc Starts the patch server for inclusion in a supervisor tree.
|
||||
%% @doc Start the PSU patch server for inclusion in a supervisor tree.
|
||||
start_link(Port) ->
|
||||
Pid = spawn(?MODULE, listen, [Port]),
|
||||
{ok, Pid}.
|
||||
|
Loading…
Reference in New Issue
Block a user