diff --git a/docs/conf-sessions.rst b/docs/conf-sessions.rst index 4ea294efd..415a2a5fe 100644 --- a/docs/conf-sessions.rst +++ b/docs/conf-sessions.rst @@ -265,6 +265,27 @@ Here is an example of a session definition for the Jabber/XMPP protocol: +Message stamping +"""""""" + +It is possible to stamp chat message by setting ``stamped`` attribute of +```` element inside request to ``true``. The stamp will include current +timestamp and ID of the sender node. If the recipient will recognise the node ID, +it will compare the timestamp inside message with the current one. The difference +will be reported as ``xmpp_msg_latency`` metric (in milliseconds). +The aim of node ID comparison is to avoid slight inconsistencies +of timestamps on different Tsung nodes. + +Only a fraction of requests will hit the same node they originated from, +but with request rate high enough this fraction should be sufficient. + +``stamped`` is allowed only with ``size`` attribute. ``data`` will cause +``stamped`` to be ignored. There is a minimal length of the stamp, +roughly 30 bytes. When ``size`` is greater than stamp length, random +padding will be added to the stamp. If the stamp length is higher than +``size``, then only stamp will be used as messagecontent, effectively +exceeding specified length. + StartTLS """""""" diff --git a/include/ts_jabber.hrl b/include/ts_jabber.hrl index a49044016..77385a9aa 100644 --- a/include/ts_jabber.hrl +++ b/include/ts_jabber.hrl @@ -36,6 +36,7 @@ size, data, type, + stamped = false, jud_param, regexp, cle, diff --git a/src/tsung/ts_jabber.erl b/src/tsung/ts_jabber.erl index 5e9df8472..510878bdb 100644 --- a/src/tsung/ts_jabber.erl +++ b/src/tsung/ts_jabber.erl @@ -50,6 +50,7 @@ userid/1]). -export ([starttls_bidi/2, + message_bidi/2, presence_bidi/2]). %%---------------------------------------------------------------------- @@ -165,6 +166,7 @@ parse_bidi(Data, State) -> RcvdXml = binary_to_list(Data), BidiElements = [{"]*subscribe[\"\']", presence_bidi}, + {"@@@([^@]+)@@@", message_bidi}, {" case re:run(RcvdXml,Regex) of @@ -180,6 +182,22 @@ presence_bidi(RcvdXml, State)-> {match,SubMatches} = re:run(RcvdXml,"]*subscribe[\"\'][^>]*>",[global]), bidi_resp(subscribed,RcvdXml,SubMatches,State). +message_bidi(RcvdXml, State) -> + {match, [NodeStamp]} = re:run(RcvdXml, "@@@([^@]+)@@@", [{capture, all_but_first, list}]), + [NodeS, StampS] = string:tokens(NodeStamp, ","), + case integer_to_list(erlang:phash2(node())) of + NodeS -> + [MegaS, SecsS, MicroS] = string:tokens(StampS, ";"), + Mega = list_to_integer(MegaS), + Secs = list_to_integer(SecsS), + Micro = list_to_integer(MicroS), + Latency = timer:now_diff(erlang:now(), {Mega, Secs, Micro}), + ts_mon:add({ sample, xmpp_msg_latency, Latency / 1000}); + _ -> + ignore + end, + {nodata, State}. + starttls_bidi(_RcvdXml, #state_rcv{socket= Socket}=State)-> ssl:start(), Req = subst(State#state_rcv.request#ts_request.param, State#state_rcv.dynvars), diff --git a/src/tsung/ts_jabber_common.erl b/src/tsung/ts_jabber_common.erl index 95646a0f3..fa0d963ac 100644 --- a/src/tsung/ts_jabber_common.erl +++ b/src/tsung/ts_jabber_common.erl @@ -481,12 +481,19 @@ registration(#jabber{username=Name,passwd=Passwd,resource=Resource})-> %% Func: message/3 %% Purpose: send message to defined user at the Service (aim, ...) %%---------------------------------------------------------------------- -message(Dest, #jabber{size=Size,data=undefined}, Service) when is_integer(Size) -> +message(Dest, #jabber{size=Size,data=undefined,stamped=Stamped}, Service) when is_integer(Size) -> + Stamp = generate_stamp(Stamped), + PadLen = Size - length(Stamp), + Data = case PadLen > 0 of + true -> ts_utils:urandomstr_noflat(PadLen); + false -> "" + end, + StampAndData = Stamp ++ Data, put(previous, Dest), list_to_binary([ "",ts_utils:urandomstr_noflat(Size), ""]); + "' type='chat'>",StampAndData, ""]); message(Dest, #jabber{data=Data}, Service) when is_list(Data) -> put(previous, Dest), list_to_binary([ @@ -494,6 +501,15 @@ message(Dest, #jabber{data=Data}, Service) when is_list(Data) -> Dest, "@", Service, "' type='chat'>",Data, ""]). +generate_stamp(false) -> + ""; +generate_stamp(true) -> + {Mega, Secs, Micro} = erlang:now(), + TS = integer_to_list(Mega) ++ ";" + ++ integer_to_list(Secs) ++ ";" + ++ integer_to_list(Micro), + "@@@" ++ integer_to_list(erlang:phash2(node())) ++ "," ++ TS ++ "@@@". + %%---------------------------------------------------------------------- %% Func: presence/0 %%---------------------------------------------------------------------- diff --git a/src/tsung_controller/ts_config_jabber.erl b/src/tsung_controller/ts_config_jabber.erl index 65774b7e2..de8765edb 100644 --- a/src/tsung_controller/ts_config_jabber.erl +++ b/src/tsung_controller/ts_config_jabber.erl @@ -57,6 +57,7 @@ parse_config(Element = #xmlElement{name=jabber}, TypeStr = ts_config:getAttr(string,Element#xmlElement.attributes, type, "chat"), Ack = ts_config:getAttr(atom,Element#xmlElement.attributes, ack, no_ack), Dest= ts_config:getAttr(atom,Element#xmlElement.attributes, destination,random), + Stamped = ts_config:getAttr(atom,Element#xmlElement.attributes, stamped, false), Size= ts_config:getAttr(integer,Element#xmlElement.attributes, size,0), Data= ts_config:getAttr(string,Element#xmlElement.attributes, data,undefined), @@ -137,6 +138,7 @@ parse_config(Element = #xmlElement{name=jabber}, id = XMPPId, data = Data, type = Type, + stamped = Stamped, regexp = RE, dest = Dest, size = Size, diff --git a/tsung-1.0.dtd b/tsung-1.0.dtd index 736962943..9afe1889a 100644 --- a/tsung-1.0.dtd +++ b/tsung-1.0.dtd @@ -263,6 +263,7 @@ repeat | if | change_type | foreach | set_option | interaction )*> size NMTOKEN "0" data CDATA #IMPLIED type NMTOKEN #REQUIRED + stamped (true | false) "false" show (away|chat|dnd|xa) "chat" status CDATA "Available" nick CDATA #IMPLIED