From e1f01f0c8ac41c1604c19512b92ce1f19c416059 Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Fri, 24 Mar 2017 11:03:23 +0300 Subject: [PATCH] Avoid PID collisions Fixes #1470 --- src/ejabberd_sm_sql.erl | 70 +++++++++++++++++++++++++++++++++-------- 1 file changed, 57 insertions(+), 13 deletions(-) diff --git a/src/ejabberd_sm_sql.erl b/src/ejabberd_sm_sql.erl index d59c3670a..9fc027588 100644 --- a/src/ejabberd_sm_sql.erl +++ b/src/ejabberd_sm_sql.erl @@ -47,7 +47,7 @@ %%%=================================================================== -spec init() -> ok | {error, any()}. init() -> - Node = jlib:atom_to_binary(node()), + Node = erlang:atom_to_binary(node(), latin1), ?INFO_MSG("Cleaning SQL SM table...", []), lists:foldl( fun(Host, ok) -> @@ -68,8 +68,8 @@ set_session(#session{sid = {Now, Pid}, usr = {U, LServer, R}, InfoS = jlib:term_to_expr(Info), PrioS = enc_priority(Priority), TS = now_to_timestamp(Now), - PidS = list_to_binary(erlang:pid_to_list(Pid)), - Node = jlib:atom_to_binary(node(Pid)), + PidS = enc_pid(Pid), + Node = erlang:atom_to_binary(node(Pid), latin1), case ?SQL_UPSERT(LServer, "sm", ["!usec=%(TS)d", "!pid=%(PidS)s", @@ -89,7 +89,7 @@ delete_session(_LUser, LServer, _LResource, {Now, Pid}) -> PidS = list_to_binary(erlang:pid_to_list(Pid)), case ejabberd_sql:sql_query( LServer, - ?SQL("select @(usec)d, @(pid)s, @(username)s," + ?SQL("select @(usec)d, @(pid)s, @(node)s, @(username)s," " @(resource)s, @(priority)s, @(info)s " "from sm where usec=%(TS)d and pid=%(PidS)s")) of {selected, [Row]} -> @@ -97,7 +97,9 @@ delete_session(_LUser, LServer, _LResource, {Now, Pid}) -> LServer, ?SQL("delete from sm" " where usec=%(TS)d and pid=%(PidS)s")), - {ok, row_to_session(LServer, Row)}; + try {ok, row_to_session(LServer, Row)} + catch _:{node_down, _} -> {error, notfound} + end; {selected, []} -> {error, notfound}; Err -> @@ -114,10 +116,15 @@ get_sessions() -> get_sessions(LServer) -> case ejabberd_sql:sql_query( LServer, - ?SQL("select @(usec)d, @(pid)s, @(username)s," + ?SQL("select @(usec)d, @(pid)s, @(node)s, @(username)s," " @(resource)s, @(priority)s, @(info)s from sm")) of {selected, Rows} -> - [row_to_session(LServer, Row) || Row <- Rows]; + lists:flatmap( + fun(Row) -> + try [row_to_session(LServer, Row)] + catch _:{node_down, _} -> [] + end + end, Rows); Err -> ?ERROR_MSG("failed to select from 'sm' table: ~p", [Err]), [] @@ -126,11 +133,16 @@ get_sessions(LServer) -> get_sessions(LUser, LServer) -> case ejabberd_sql:sql_query( LServer, - ?SQL("select @(usec)d, @(pid)s, @(username)s," + ?SQL("select @(usec)d, @(pid)s, @(node)s, @(username)s," " @(resource)s, @(priority)s, @(info)s from sm" " where username=%(LUser)s")) of {selected, Rows} -> - [row_to_session(LServer, Row) || Row <- Rows]; + lists:flatmap( + fun(Row) -> + try [row_to_session(LServer, Row)] + catch _:{node_down, _} -> [] + end + end, Rows); Err -> ?ERROR_MSG("failed to select from 'sm' table: ~p", [Err]), [] @@ -139,11 +151,16 @@ get_sessions(LUser, LServer) -> get_sessions(LUser, LServer, LResource) -> case ejabberd_sql:sql_query( LServer, - ?SQL("select @(usec)d, @(pid)s, @(username)s," + ?SQL("select @(usec)d, @(pid)s, @(node)s, @(username)s," " @(resource)s, @(priority)s, @(info)s from sm" " where username=%(LUser)s and resource=%(LResource)s")) of {selected, Rows} -> - [row_to_session(LServer, Row) || Row <- Rows]; + lists:flatmap( + fun(Row) -> + try [row_to_session(LServer, Row)] + catch _:{node_down, _} -> [] + end + end, Rows); Err -> ?ERROR_MSG("failed to select from 'sm' table: ~p", [Err]), [] @@ -175,12 +192,39 @@ enc_priority(undefined) -> enc_priority(Int) when is_integer(Int) -> integer_to_binary(Int). -row_to_session(LServer, {USec, PidS, User, Resource, PrioS, InfoS}) -> +row_to_session(LServer, {USec, PidS, NodeS, User, Resource, PrioS, InfoS}) -> Now = timestamp_to_now(USec), - Pid = erlang:list_to_pid(binary_to_list(PidS)), + Pid = dec_pid(PidS, NodeS), Priority = dec_priority(PrioS), Info = ejabberd_sql:decode_term(InfoS), #session{sid = {Now, Pid}, us = {User, LServer}, usr = {User, LServer, Resource}, priority = Priority, info = Info}. + +-spec enc_pid(pid()) -> binary(). +enc_pid(Pid) -> + list_to_binary(erlang:pid_to_list(Pid)). + +-spec dec_pid(binary(), binary()) -> pid(). +dec_pid(PidBin, NodeBin) -> + PidStr = binary_to_list(PidBin), + Pid = erlang:list_to_pid(PidStr), + case erlang:binary_to_atom(NodeBin, latin1) of + Node when Node == node() -> + Pid; + Node -> + try set_node_id(PidStr, NodeBin) + catch _:badarg -> + erlang:error({node_down, Node}) + end + end. + +-spec set_node_id(string(), binary()) -> pid(). +set_node_id(PidStr, NodeBin) -> + ExtPidStr = erlang:pid_to_list( + binary_to_term( + <<131,103,100,(size(NodeBin)):16,NodeBin/binary,0:72>>)), + [H|_] = string:tokens(ExtPidStr, "."), + [_|T] = string:tokens(PidStr, "."), + erlang:list_to_pid(string:join([H|T], ".")).