From 153154133112ad91cf94890c0f9bb2161d7af380 Mon Sep 17 00:00:00 2001 From: Badlop Date: Thu, 24 Jun 2010 12:12:13 +0200 Subject: [PATCH 01/26] Fix problem when FIREWALL_WINDOW options for erl kernel were used http://www.ejabberd.im/node/4120 --- src/ejabberdctl.template | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/ejabberdctl.template b/src/ejabberdctl.template index 9ede77dfe..6e4588b5d 100644 --- a/src/ejabberdctl.template +++ b/src/ejabberdctl.template @@ -82,7 +82,7 @@ else KERNEL_OPTS="-kernel inet_dist_listen_min ${FIREWALL_WINDOW%-*} inet_dist_listen_max ${FIREWALL_WINDOW#*-}" fi -ERLANG_OPTS="+K $POLL -smp $SMP +P $ERL_PROCESSES $ERL_OPTIONS $KERNEL_OPTS" +ERLANG_OPTS="+K $POLL -smp $SMP +P $ERL_PROCESSES $ERL_OPTIONS" # define additional environment variables if [ "$EJABBERDDIR" = "" ]; then @@ -141,6 +141,7 @@ start () -noinput -detached \ -pa $EJABBERD_EBIN_PATH \ -mnesia dir \"\\\"$SPOOLDIR\\\"\" \ + $KERNEL_OPTS \ -s ejabberd \ -sasl sasl_error_logger \\{file,\\\"$SASL_LOG_PATH\\\"\\} \ $ERLANG_OPTS $ARGS \"$@\"" @@ -174,6 +175,7 @@ debug () $NAME debug-${TTY}-${ERLANG_NODE} \ -remsh $ERLANG_NODE \ -hidden \ + $KERNEL_OPTS \ $ERLANG_OPTS $ARGS \"$@\"" } @@ -203,6 +205,7 @@ live () $NAME $ERLANG_NODE \ -pa $EJABBERD_EBIN_PATH \ -mnesia dir \"\\\"$SPOOLDIR\\\"\" \ + $KERNEL_OPTS \ -s ejabberd \ $ERLANG_OPTS $ARGS \"$@\"" } @@ -310,6 +313,7 @@ ctlexec () -noinput \ -hidden \ -pa $EJABBERD_EBIN_PATH \ + $KERNEL_OPTS \ -s ejabberd_ctl -extra $ERLANG_NODE $COMMAND" } From d9e2931ed94c7d9438950d34614b3aa12b77f1f8 Mon Sep 17 00:00:00 2001 From: Badlop Date: Tue, 29 Jun 2010 11:57:54 +0200 Subject: [PATCH 02/26] Fix privacy check when serving local Last (thanks to Brian Acton)(EJAB-1271) --- src/mod_last.erl | 2 +- src/mod_last_odbc.erl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mod_last.erl b/src/mod_last.erl index 73d908f8d..d3b561f60 100644 --- a/src/mod_last.erl +++ b/src/mod_last.erl @@ -127,7 +127,7 @@ process_sm_iq(From, To, #iq{type = Type, sub_el = SubEl} = IQ) -> [User, Server, UserListRecord, {From, To, {xmlelement, "presence", [], []}}, - out]) of + in]) of allow -> get_last(IQ, SubEl, User, Server); deny -> diff --git a/src/mod_last_odbc.erl b/src/mod_last_odbc.erl index 5d6aac2b1..7616c5020 100644 --- a/src/mod_last_odbc.erl +++ b/src/mod_last_odbc.erl @@ -119,7 +119,7 @@ process_sm_iq(From, To, #iq{type = Type, sub_el = SubEl} = IQ) -> [User, Server, UserListRecord, {From, To, {xmlelement, "presence", [], []}}, - out]) of + in]) of allow -> get_last(IQ, SubEl, User, Server); deny -> From 715cc5ea3bf01ea99b2516c0d3d48e2a5ccb8174 Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Thu, 1 Jul 2010 20:54:01 +1000 Subject: [PATCH 03/26] New configure option: --enable-nif --- src/Makefile.in | 7 +- src/configure.ac | 9 ++ src/ejabberd_app.erl | 1 + src/ejabberd_c2s.erl | 8 +- src/ejabberd_s2s_in.erl | 4 +- src/ejabberd_s2s_out.erl | 2 +- src/ejabberd_service.erl | 4 +- src/mod_muc/mod_muc_room.erl | 11 +- src/mod_offline_odbc.erl | 3 +- src/web/ejabberd_http_bind.erl | 16 +-- src/xml.c | 230 +++++++++++++++++++++++++++++++++ src/xml.erl | 19 +++ 12 files changed, 290 insertions(+), 24 deletions(-) create mode 100644 src/xml.c diff --git a/src/Makefile.in b/src/Makefile.in index 94fa8b1ac..174084f64 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -55,6 +55,11 @@ ifeq (@full_xml@, true) EFLAGS+=-DFULL_XML_SUPPORT endif +ifeq (@nif@, true) + EFLAGS+=-DNIF + ERLSHLIBS=xml.so +endif + ifeq (@transient_supervisors@, false) EFLAGS+=-DNO_TRANSIENT_SUPERVISORS endif @@ -68,7 +73,7 @@ prefix = @prefix@ exec_prefix = @exec_prefix@ SUBDIRS = @mod_irc@ @mod_pubsub@ @mod_muc@ @mod_proxy65@ @eldap@ @pam@ @web@ stringprep stun @tls@ @odbc@ @ejabberd_zlib@ -ERLSHLIBS = expat_erl.so +ERLSHLIBS += expat_erl.so ERLBEHAVS = cyrsasl.erl gen_mod.erl p1_fsm.erl SOURCES_ALL = $(wildcard *.erl) SOURCES_MISC = $(ERLBEHAVS) $(DEBUGTOOLS) diff --git a/src/configure.ac b/src/configure.ac index 20bfdf6f1..70a6fb43c 100644 --- a/src/configure.ac +++ b/src/configure.ac @@ -94,6 +94,15 @@ AC_ARG_ENABLE(full_xml, esac],[full_xml=false]) AC_SUBST(full_xml) +AC_ARG_ENABLE(nif, +[AC_HELP_STRING([--enable-nif], [replace some functions with C equivalents. You should have Erlang R13B04 or higher (default: no)])], +[case "${enableval}" in + yes) nif=true ;; + no) nif=false ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-nif) ;; +esac],[nif=false]) +AC_SUBST(nif) + AC_CONFIG_FILES([Makefile $make_mod_irc $make_mod_muc diff --git a/src/ejabberd_app.erl b/src/ejabberd_app.erl index 7a54fcc37..97ae7fedd 100644 --- a/src/ejabberd_app.erl +++ b/src/ejabberd_app.erl @@ -46,6 +46,7 @@ start(normal, _Args) -> db_init(), sha:start(), stringprep_sup:start_link(), + xml:start(), start(), translate:start(), acl:start(), diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 6238cdae5..d4b68096e 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -627,7 +627,7 @@ wait_for_feature_request({xmlstreamelement, El}, StateData) -> Socket = StateData#state.socket, TLSSocket = (StateData#state.sockmod):starttls( Socket, TLSOpts, - xml:element_to_string( + xml:element_to_binary( {xmlelement, "proceed", [{"xmlns", ?NS_TLS}], []})), fsm_next_state(wait_for_stream, StateData#state{socket = TLSSocket, @@ -650,7 +650,7 @@ wait_for_feature_request({xmlstreamelement, El}, StateData) -> Socket = StateData#state.socket, ZlibSocket = (StateData#state.sockmod):compress( Socket, - xml:element_to_string( + xml:element_to_binary( {xmlelement, "compressed", [{"xmlns", ?NS_COMPRESS}], []})), fsm_next_state(wait_for_stream, @@ -1453,14 +1453,14 @@ change_shaper(StateData, JID) -> (StateData#state.sockmod):change_shaper(StateData#state.socket, Shaper). send_text(StateData, Text) -> - ?DEBUG("Send XML on stream = ~p", [lists:flatten(Text)]), + ?DEBUG("Send XML on stream = ~p", [Text]), (StateData#state.sockmod):send(StateData#state.socket, Text). send_element(StateData, El) when StateData#state.xml_socket -> (StateData#state.sockmod):send_xml(StateData#state.socket, {xmlstreamelement, El}); send_element(StateData, El) -> - send_text(StateData, xml:element_to_string(El)). + send_text(StateData, xml:element_to_binary(El)). send_header(StateData, Server, Version, Lang) when StateData#state.xml_socket -> diff --git a/src/ejabberd_s2s_in.erl b/src/ejabberd_s2s_in.erl index 9b378338c..179dc08f1 100644 --- a/src/ejabberd_s2s_in.erl +++ b/src/ejabberd_s2s_in.erl @@ -263,7 +263,7 @@ wait_for_feature_request({xmlstreamelement, El}, StateData) -> TLSOpts = StateData#state.tls_options, TLSSocket = (StateData#state.sockmod):starttls( Socket, TLSOpts, - xml:element_to_string( + xml:element_to_binary( {xmlelement, "proceed", [{"xmlns", ?NS_TLS}], []})), {next_state, wait_for_stream, StateData#state{socket = TLSSocket, @@ -618,7 +618,7 @@ send_text(StateData, Text) -> (StateData#state.sockmod):send(StateData#state.socket, Text). send_element(StateData, El) -> - send_text(StateData, xml:element_to_string(El)). + send_text(StateData, xml:element_to_binary(El)). change_shaper(StateData, Host, JID) -> diff --git a/src/ejabberd_s2s_out.erl b/src/ejabberd_s2s_out.erl index 69cbfdd22..01ab8d8aa 100644 --- a/src/ejabberd_s2s_out.erl +++ b/src/ejabberd_s2s_out.erl @@ -892,7 +892,7 @@ send_text(StateData, Text) -> ejabberd_socket:send(StateData#state.socket, Text). send_element(StateData, El) -> - send_text(StateData, xml:element_to_string(El)). + send_text(StateData, xml:element_to_binary(El)). send_queue(StateData, Q) -> case queue:out(Q) of diff --git a/src/ejabberd_service.erl b/src/ejabberd_service.erl index 44bca0b9e..bd07bfea8 100644 --- a/src/ejabberd_service.erl +++ b/src/ejabberd_service.erl @@ -347,7 +347,7 @@ handle_info({route, From, To, Packet}, StateName, StateData) -> Attrs2 = jlib:replace_from_to_attrs(jlib:jid_to_string(From), jlib:jid_to_string(To), Attrs), - Text = xml:element_to_string({xmlelement, Name, Attrs2, Els}), + Text = xml:element_to_binary({xmlelement, Name, Attrs2, Els}), send_text(StateData, Text); deny -> Err = jlib:make_error_reply(Packet, ?ERR_NOT_ALLOWED), @@ -391,7 +391,7 @@ send_text(StateData, Text) -> (StateData#state.sockmod):send(StateData#state.socket, Text). send_element(StateData, El) -> - send_text(StateData, xml:element_to_string(El)). + send_text(StateData, xml:element_to_binary(El)). new_id() -> randoms:get_string(). diff --git a/src/mod_muc/mod_muc_room.erl b/src/mod_muc/mod_muc_room.erl index 8798ace2d..b0a07178b 100644 --- a/src/mod_muc/mod_muc_room.erl +++ b/src/mod_muc/mod_muc_room.erl @@ -162,7 +162,7 @@ normal_state({route, From, "", trunc(gen_mod:get_module_opt( StateData#state.server_host, mod_muc, min_message_interval, 0) * 1000000), - Size = iolist_size(xml:element_to_string(Packet)), + Size = element_size(Packet), {MessageShaper, MessageShaperInterval} = shaper:update(Activity#activity.message_shaper, Size), if @@ -1394,7 +1394,7 @@ prepare_room_queue(StateData) -> {{value, {message, From}}, _RoomQueue} -> Activity = get_user_activity(From, StateData), Packet = Activity#activity.message, - Size = iolist_size(xml:element_to_string(Packet)), + Size = element_size(Packet), {RoomShaper, RoomShaperInterval} = shaper:update(StateData#state.room_shaper, Size), erlang:send_after( @@ -1405,7 +1405,7 @@ prepare_room_queue(StateData) -> {{value, {presence, From}}, _RoomQueue} -> Activity = get_user_activity(From, StateData), {_Nick, Packet} = Activity#activity.presence, - Size = iolist_size(xml:element_to_string(Packet)), + Size = element_size(Packet), {RoomShaper, RoomShaperInterval} = shaper:update(StateData#state.room_shaper, Size), erlang:send_after( @@ -2068,7 +2068,7 @@ add_message_to_history(FromNick, FromJID, Packet, StateData) -> jlib:jid_replace_resource(StateData#state.jid, FromNick), StateData#state.jid, TSPacket), - Size = iolist_size(xml:element_to_string(SPacket)), + Size = element_size(SPacket), Q1 = lqueue_in({FromNick, TSPacket, HaveSubject, TimeStamp, Size}, StateData#state.history), add_to_log(text, {FromNick, Packet}, StateData), @@ -3582,3 +3582,6 @@ tab_count_user(JID) -> _ -> 0 end. + +element_size(El) -> + size(xml:element_to_binary(El)). diff --git a/src/mod_offline_odbc.erl b/src/mod_offline_odbc.erl index c89beda4e..063ea709e 100644 --- a/src/mod_offline_odbc.erl +++ b/src/mod_offline_odbc.erl @@ -123,8 +123,7 @@ loop(Host, AccessMaxOfflineMsgs) -> M#offline_msg.timestamp))]}, XML = ejabberd_odbc:escape( - lists:flatten( - xml:element_to_string(Packet))), + xml:element_to_binary(Packet)), odbc_queries:add_spool_sql(Username, XML) end, Msgs), case catch odbc_queries:add_spool(Host, Query) of diff --git a/src/web/ejabberd_http_bind.erl b/src/web/ejabberd_http_bind.erl index 80ddaf3ea..27ea3c089 100644 --- a/src/web/ejabberd_http_bind.erl +++ b/src/web/ejabberd_http_bind.erl @@ -790,7 +790,7 @@ handle_http_put(Sid, Rid, Attrs, Payload, PayloadSize, StreamStart, IP) -> ?DEBUG("Trafic Shaper: Delaying request ~p", [Rid]), timer:sleep(Pause), %{200, ?HEADER, - % xml:element_to_string( + % xml:element_to_binary( % {xmlelement, "body", % [{"xmlns", ?NS_HTTP_BIND}, % {"type", "error"}], []})}; @@ -827,21 +827,21 @@ handle_http_put_error(Reason, #http_bind{pid=FsmRef, version=Version}) case Reason of not_exists -> {200, ?HEADER, - xml:element_to_string( + xml:element_to_binary( {xmlelement, "body", [{"xmlns", ?NS_HTTP_BIND}, {"type", "terminate"}, {"condition", "item-not-found"}], []})}; bad_key -> {200, ?HEADER, - xml:element_to_string( + xml:element_to_binary( {xmlelement, "body", [{"xmlns", ?NS_HTTP_BIND}, {"type", "terminate"}, {"condition", "item-not-found"}], []})}; polling_too_frequently -> {200, ?HEADER, - xml:element_to_string( + xml:element_to_binary( {xmlelement, "body", [{"xmlns", ?NS_HTTP_BIND}, {"type", "terminate"}, @@ -986,7 +986,7 @@ prepare_outpacket_response(#http_bind{id=Sid, wait=Wait, MaxInactivity = get_max_inactivity(To, ?MAX_INACTIVITY), MaxPause = get_max_pause(To), {200, ?HEADER, - xml:element_to_string( + xml:element_to_binary( {xmlelement,"body", [{"xmlns", ?NS_HTTP_BIND}, @@ -1041,7 +1041,7 @@ send_outpacket(#http_bind{pid = FsmRef}, OutPacket) -> true -> TypedEls = [check_default_xmlns(OEl) || {xmlstreamelement, OEl} <- OutPacket], - Body = xml:element_to_string( + Body = xml:element_to_binary( {xmlelement,"body", [{"xmlns", ?NS_HTTP_BIND}], @@ -1075,7 +1075,7 @@ send_outpacket(#http_bind{pid = FsmRef}, OutPacket) -> StreamTail] end, {200, ?HEADER, - xml:element_to_string( + xml:element_to_binary( {xmlelement,"body", [{"xmlns", ?NS_HTTP_BIND}], @@ -1191,7 +1191,7 @@ set_inactivity_timer(_Pause, MaxInactivity) -> elements_to_string([]) -> []; elements_to_string([El | Els]) -> - xml:element_to_string(El) ++ elements_to_string(Els). + [xml:element_to_binary(El)|elements_to_string(Els)]. %% @spec (To, Default::integer()) -> integer() %% where To = [] | {Host::string(), Version::string()} diff --git a/src/xml.c b/src/xml.c new file mode 100644 index 000000000..d1b2b7f44 --- /dev/null +++ b/src/xml.c @@ -0,0 +1,230 @@ +#include +#include +#include + +struct buf { + int limit; + int len; + unsigned char *b; +}; + +static int make_element(ErlNifEnv* env, struct buf *rbuf, ERL_NIF_TERM el); + +static struct buf *init_buf(ErlNifEnv* env) +{ + struct buf *rbuf = enif_alloc(env, sizeof(struct buf)); + rbuf->limit = 1024; + rbuf->len = 0; + rbuf->b = enif_alloc(env, rbuf->limit); + return rbuf; +} + +static void destroy_buf(ErlNifEnv* env, struct buf *rbuf) +{ + if (rbuf) { + if (rbuf->b) { + enif_free(env, rbuf->b); + }; + enif_free(env, rbuf); + }; +} + +inline void resize_buf(ErlNifEnv* env, struct buf *rbuf, int len_to_add) +{ + int new_len = rbuf->len + len_to_add; + + if (new_len >= rbuf->limit) { + rbuf->limit = ((new_len / 1024) + 1) * 1024; + rbuf->b = enif_realloc(env, rbuf->b, rbuf->limit); + }; +} + +static void buf_add_char(ErlNifEnv* env, struct buf *rbuf, unsigned char c) +{ + resize_buf(env, rbuf, 1); + (rbuf->b)[rbuf->len] = c; + rbuf->len += 1; +} + +static void buf_add_str(ErlNifEnv* env, struct buf *rbuf, char *data, int len) +{ + resize_buf(env, rbuf, len); + memcpy(rbuf->b + rbuf->len, data, len); + rbuf->len += len; +} + +inline void crypt(ErlNifEnv* env, struct buf *rbuf, unsigned char *data, int len) +{ + int i; + + for (i = 0; i < len; i++) { + switch (data[i]) { + case '&': + buf_add_str(env, rbuf, "&", 5); + break; + case '<': + buf_add_str(env, rbuf, "<", 4); + break; + case '>': + buf_add_str(env, rbuf, ">", 4); + break; + case '"': + buf_add_str(env, rbuf, """, 6); + break; + case '\'': + buf_add_str(env, rbuf, "'", 6); + break; + default: + buf_add_char(env, rbuf, data[i]); + break; + }; + }; +} + +static int make_elements(ErlNifEnv* env, struct buf *rbuf, ERL_NIF_TERM els) +{ + ERL_NIF_TERM head, tail; + int ret = 0; + + while (enif_get_list_cell(env, els, &head, &tail)) { + ret = make_element(env, rbuf, head); + if (ret) { + els = tail; + } else { + break; + }; + }; + + return ret; +} + +static int make_attrs(ErlNifEnv* env, struct buf *rbuf, ERL_NIF_TERM attrs) +{ + ErlNifBinary name, data; + ERL_NIF_TERM head, tail; + const ERL_NIF_TERM *tuple; + int arity, ret = 1; + + while (enif_get_list_cell(env, attrs, &head, &tail)) { + if (enif_get_tuple(env, head, &arity, &tuple)) { + if (arity == 2) { + if (enif_inspect_iolist_as_binary(env, tuple[0], &name) && + enif_inspect_iolist_as_binary(env, tuple[1], &data)) { + buf_add_char(env, rbuf, ' '); + buf_add_str(env, rbuf, (char *)name.data, name.size); + buf_add_str(env, rbuf, "='", 2); + crypt(env, rbuf, data.data, data.size); + buf_add_char(env, rbuf, '\''); + attrs = tail; + } else { + ret = 0; + break; + }; + } else { + ret = 0; + break; + }; + } else { + ret = 0; + break; + }; + }; + + return ret; +} + +static int make_element(ErlNifEnv* env, struct buf *rbuf, ERL_NIF_TERM el) +{ + ErlNifBinary cdata, name; + const ERL_NIF_TERM *tuple; + int arity, ret = 0; + + if (enif_get_tuple(env, el, &arity, &tuple)) { + if (arity == 2) { + if (!enif_compare(env, tuple[0], enif_make_atom(env, "xmlcdata"))) { + if (enif_inspect_iolist_as_binary(env, tuple[1], &cdata)) { + crypt(env, rbuf, cdata.data, cdata.size); + ret = 1; + }; + }; + }; + if (arity == 4) { + if (!enif_compare(env, tuple[0], enif_make_atom(env, "xmlelement"))) { + if (enif_inspect_iolist_as_binary(env, tuple[1], &name)) { + buf_add_char(env, rbuf, '<'); + buf_add_str(env, rbuf, (char *)name.data, name.size); + ret = make_attrs(env, rbuf, tuple[2]); + if (ret) { + if (enif_is_empty_list(env, tuple[3])) { + buf_add_str(env, rbuf, "/>", 2); + } else { + buf_add_char(env, rbuf, '>'); + ret = make_elements(env, rbuf, tuple[3]); + if (ret) { + buf_add_str(env, rbuf, "'); + }; + }; + }; + }; + }; + }; + }; + + return ret; +} + +static ERL_NIF_TERM element_to(ErlNifEnv* env, int argc, + const ERL_NIF_TERM argv[], + int as_string) +{ + ErlNifBinary output; + ERL_NIF_TERM result; + struct buf *rbuf; + + if (argc == 1) { + rbuf = init_buf(env); + if (make_element(env, rbuf, argv[0])) { + if (as_string) { + (rbuf->b)[rbuf->len] = 0; + result = enif_make_string(env, (char *) rbuf->b, ERL_NIF_LATIN1); + destroy_buf(env, rbuf); + return result; + } else { + if (enif_alloc_binary(env, rbuf->len, &output)) { + memcpy(output.data, rbuf->b, rbuf->len); + result = enif_make_binary(env, &output); + destroy_buf(env, rbuf); + return result; + }; + }; + }; + destroy_buf(env, rbuf); + }; + + return enif_make_badarg(env); +} + +/* static ERL_NIF_TERM element_to_string(ErlNifEnv* env, int argc, */ +/* const ERL_NIF_TERM argv[]) */ +/* { */ +/* return element_to(env, argc, argv, 1); */ +/* } */ + +static ERL_NIF_TERM element_to_binary(ErlNifEnv* env, int argc, + const ERL_NIF_TERM argv[]) +{ + return element_to(env, argc, argv, 0); +} + +static ErlNifFunc nif_funcs[] = + { + /* Stupid Erlang bug with enif_make_string() is fixed + in R14A only (OTP-8685), so we can't use + element_to_string yet.*/ + /* {"element_to_string", 1, element_to_string}, */ + {"element_to_binary", 1, element_to_binary} + }; + +ERL_NIF_INIT(xml, nif_funcs, NULL, NULL, NULL, NULL) diff --git a/src/xml.erl b/src/xml.erl index 9a9a7f833..22746b10a 100644 --- a/src/xml.erl +++ b/src/xml.erl @@ -37,8 +37,11 @@ get_subtag/2, get_subtag_cdata/2, append_subtags/2, get_path_s/2, + start/0, replace_tag_attr/3]). +-include("ejabberd.hrl"). + %% Select at compile time how to escape characters in binary text %% nodes. %% Can be choosen with ./configure --enable-full-xml @@ -48,6 +51,22 @@ -define(ESCAPE_BINARY(CData), crypt(CData)). -endif. +%% Replace element_to_binary/1 with NIF +%% Can be choosen with ./configure --enable-nif +-ifdef(NIF). +start() -> + SOPath = filename:join(ejabberd:get_so_path(), "xml"), + case catch erlang:load_nif(SOPath, 0) of + ok -> + ok; + Err -> + ?WARNING_MSG("unable to load xml NIF: ~p", [Err]) + end. +-else. +start() -> + ok. +-endif. + element_to_binary(El) -> iolist_to_binary(element_to_string(El)). From 0ac5684bf0beb3440db5dda30b5e77b52d94e4ec Mon Sep 17 00:00:00 2001 From: Badlop Date: Thu, 1 Jul 2010 16:51:26 +0200 Subject: [PATCH 04/26] Clarify that to use the optional --enable-nif, R13B04 is needed. --- src/configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/configure.ac b/src/configure.ac index 70a6fb43c..0932513ee 100644 --- a/src/configure.ac +++ b/src/configure.ac @@ -95,7 +95,7 @@ esac],[full_xml=false]) AC_SUBST(full_xml) AC_ARG_ENABLE(nif, -[AC_HELP_STRING([--enable-nif], [replace some functions with C equivalents. You should have Erlang R13B04 or higher (default: no)])], +[AC_HELP_STRING([--enable-nif], [replace some functions with C equivalents. Requires Erlang R13B04 or higher (default: no)])], [case "${enableval}" in yes) nif=true ;; no) nif=false ;; From baeb3d076e557d64c6b4b7a50842a66a7707745d Mon Sep 17 00:00:00 2001 From: Badlop Date: Thu, 1 Jul 2010 16:57:47 +0200 Subject: [PATCH 05/26] Document the optional --enable-nif --- doc/guide.tex | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/guide.tex b/doc/guide.tex index 1cc41e6c3..d0d24c5f5 100644 --- a/doc/guide.tex +++ b/doc/guide.tex @@ -382,6 +382,10 @@ Some options that you may be interested in modifying: \titem{--disable-transient-supervisors} Disable the use of Erlang/OTP supervision for transient processes. + + \titem{--enable-nif} + Replaces some critical Erlang functions with equivalents written in C to improve performance. + This feature requires Erlang/OTP R13B04 or higher. \end{description} \makesubsection{install}{Install} From ae6545989ec2833c1c6d1d9fc86e966f2c18524b Mon Sep 17 00:00:00 2001 From: Badlop Date: Thu, 1 Jul 2010 16:59:26 +0200 Subject: [PATCH 06/26] Fix typo in --enable-transient_supervisors --- src/configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/configure.ac b/src/configure.ac index 0932513ee..1497643d3 100644 --- a/src/configure.ac +++ b/src/configure.ac @@ -81,7 +81,7 @@ AC_ARG_ENABLE(transient_supervisors, [case "${enableval}" in yes) transient_supervisors=true ;; no) transient_supervisors=false ;; - *) AC_MSG_ERROR(bad value ${enableval} for --enable-full-xml) ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-transient_supervisors) ;; esac],[transient_supervisors=true]) AC_SUBST(transient_supervisors) From c3c23a04f65a98d55a1b4c4d86a82633320e83ac Mon Sep 17 00:00:00 2001 From: Badlop Date: Thu, 1 Jul 2010 17:01:13 +0200 Subject: [PATCH 07/26] Requirement of OpenSSL increased from 0.9.6 to 0.9.8 --- README | 2 +- doc/guide.tex | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README b/README index 1a8dcdd1e..da7742256 100644 --- a/README +++ b/README @@ -10,7 +10,7 @@ To compile ejabberd you need: - GCC - Libexpat 1.95 or higher - Erlang/OTP R10B-9 or higher. Recommended versions: R12B-5 and R13B04 - - OpenSSL 0.9.6 or higher, for STARTTLS, SASL and SSL encryption. + - OpenSSL 0.9.8 or higher, for STARTTLS, SASL and SSL encryption. - Zlib 1.2.3 or higher, for Stream Compression support (XEP-0138). Optional. - Erlang mysql library. Optional. MySQL authentication/storage. diff --git a/doc/guide.tex b/doc/guide.tex index d0d24c5f5..272f933b4 100644 --- a/doc/guide.tex +++ b/doc/guide.tex @@ -311,7 +311,7 @@ To compile \ejabberd{} on a `Unix-like' operating system, you need: \item GCC \item Libexpat 1.95 or higher \item Erlang/OTP R10B-9 or higher. The recommended versions are R12B-5 and R13B04. -\item OpenSSL 0.9.6 or higher, for STARTTLS, SASL and SSL encryption. +\item OpenSSL 0.9.8 or higher, for STARTTLS, SASL and SSL encryption. \item Zlib 1.2.3 or higher, for Stream Compression support (\xepref{0138}). Optional. \item Erlang mysql library. Optional. For MySQL authentication or storage. See section \ref{compilemysql}. \item Erlang pgsql library. Optional. For PostgreSQL authentication or storage. See section \ref{compilepgsql}. From fa22b2343521fa1bd4fed5b63a4abdee25e7f2a1 Mon Sep 17 00:00:00 2001 From: Badlop Date: Thu, 1 Jul 2010 17:03:36 +0200 Subject: [PATCH 08/26] Recompile the Guide and Configure --- doc/guide.html | 6 ++++-- src/configure | 19 ++++++++++++++++++- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/doc/guide.html b/doc/guide.html index 44d0fd316..d4a8ef75f 100644 --- a/doc/guide.html +++ b/doc/guide.html @@ -346,7 +346,7 @@ GNU Make
  • GCC
  • Libexpat 1.95 or higher
  • Erlang/OTP R10B-9 or higher. The recommended versions are R12B-5 and R13B04. -
  • OpenSSL 0.9.6 or higher, for STARTTLS, SASL and SSL encryption. +
  • OpenSSL 0.9.8 or higher, for STARTTLS, SASL and SSL encryption.
  • Zlib 1.2.3 or higher, for Stream Compression support (XEP-0138). Optional.
  • Erlang mysql library. Optional. For MySQL authentication or storage. See section 3.2.1.
  • Erlang pgsql library. Optional. For PostgreSQL authentication or storage. See section 3.2.3. @@ -390,7 +390,9 @@ To get the full list run the command: Enable the use of XML based optimisations. It will for example use CDATA to escape characters in the XMPP stream. Use this option only if you are sure your XMPP clients include a fully compliant XML parser.

    --disable-transient-supervisors
    - Disable the use of Erlang/OTP supervision for transient processes. + Disable the use of Erlang/OTP supervision for transient processes.

    --enable-nif
    +Replaces some critical Erlang functions with equivalents written in C to improve performance. +This feature requires Erlang/OTP R13B04 or higher.

    2.4.4  Install

    To install ejabberd in the destination directories, run the command: diff --git a/src/configure b/src/configure index db7e63b43..5ff174752 100755 --- a/src/configure +++ b/src/configure @@ -611,6 +611,7 @@ build INSTALLUSER SSL_CFLAGS SSL_LIBS +nif full_xml transient_supervisors db_type @@ -721,6 +722,7 @@ enable_roster_gateway_workaround enable_mssql enable_transient_supervisors enable_full_xml +enable_nif with_openssl enable_user ' @@ -1372,6 +1374,8 @@ Optional Features: (default: yes) --enable-full-xml use XML features in XMPP stream (ex: CDATA) (default: no, requires XML compliant clients) + --enable-nif replace some functions with C equivalents. Requires + Erlang R13B04 or higher (default: no) --enable-user[[[=USER]]] allow this system user to start ejabberd (default: no) @@ -4650,7 +4654,7 @@ if test "${enable_transient_supervisors+set}" = set; then : enableval=$enable_transient_supervisors; case "${enableval}" in yes) transient_supervisors=true ;; no) transient_supervisors=false ;; - *) as_fn_error "bad value ${enableval} for --enable-full-xml" "$LINENO" 5 ;; + *) as_fn_error "bad value ${enableval} for --enable-transient_supervisors" "$LINENO" 5 ;; esac else transient_supervisors=true @@ -4671,6 +4675,19 @@ fi +# Check whether --enable-nif was given. +if test "${enable_nif+set}" = set; then : + enableval=$enable_nif; case "${enableval}" in + yes) nif=true ;; + no) nif=false ;; + *) as_fn_error "bad value ${enableval} for --enable-nif" "$LINENO" 5 ;; +esac +else + nif=false +fi + + + ac_config_files="$ac_config_files Makefile $make_mod_irc $make_mod_muc $make_mod_pubsub $make_mod_proxy65 $make_eldap $make_pam $make_web stringprep/Makefile stun/Makefile $make_tls $make_odbc $make_ejabberd_zlib" #openssl From 4c2e7e38a1170bacad0ecbe0244d048d11fd355c Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Fri, 2 Jul 2010 20:31:42 +1000 Subject: [PATCH 09/26] Use ets insead of asking supervisor in ejabberd_odbc_sup:get_pids/1 (Thanks to Alexey Shchepin) --- src/odbc/ejabberd_odbc.erl | 2 + src/odbc/ejabberd_odbc_sup.erl | 41 +++++++++++++++----- src/p1_fsm.erl | 70 ++++++++++++++++++++++++++++++---- 3 files changed, 97 insertions(+), 16 deletions(-) diff --git a/src/odbc/ejabberd_odbc.erl b/src/odbc/ejabberd_odbc.erl index d7cdd0371..1b07fd6d9 100644 --- a/src/odbc/ejabberd_odbc.erl +++ b/src/odbc/ejabberd_odbc.erl @@ -178,6 +178,7 @@ init([Host, StartInterval]) -> end, [DBType | _] = db_opts(Host), ?GEN_FSM:send_event(self(), connect), + ejabberd_odbc_sup:add_pid(Host, self()), {ok, connecting, #state{db_type = DBType, host = Host, max_pending_requests_len = max_fsm_queue(), @@ -274,6 +275,7 @@ handle_info(Info, StateName, State) -> {next_state, StateName, State}. terminate(_Reason, _StateName, State) -> + ejabberd_odbc_sup:remove_pid(State#state.host, self()), case State#state.db_type of mysql -> %% old versions of mysql driver don't have the stop function diff --git a/src/odbc/ejabberd_odbc_sup.erl b/src/odbc/ejabberd_odbc_sup.erl index d828449ec..45ede1835 100644 --- a/src/odbc/ejabberd_odbc_sup.erl +++ b/src/odbc/ejabberd_odbc_sup.erl @@ -30,6 +30,8 @@ %% API -export([start_link/1, init/1, + add_pid/2, + remove_pid/2, get_pids/1, get_random_pid/1 ]). @@ -44,7 +46,19 @@ -define(CONNECT_TIMEOUT, 500). % milliseconds +-record(sql_pool, {host, pid}). + start_link(Host) -> + mnesia:create_table(sql_pool, + [{ram_copies, [node()]}, + {type, bag}, + {local_content, true}, + {attributes, record_info(fields, sql_pool)}]), + mnesia:add_table_copy(local_config, node(), ram_copies), + F = fun() -> + mnesia:delete({sql_pool, Host}) + end, + mnesia:ets(F), supervisor:start_link({local, gen_mod:get_module_proc(Host, ?MODULE)}, ?MODULE, [Host]). @@ -86,16 +100,25 @@ init([Host]) -> end, lists:seq(1, PoolSize))}}. get_pids(Host) -> - Proc = gen_mod:get_module_proc(Host, ?MODULE), - - % throw an exception if supervisor is not ready (i.e. if it cannot - % start its children, if the database is down for example) - sys:get_status(Proc, ?CONNECT_TIMEOUT), - - [Child || - {_Id, Child, _Type, _Modules} <- supervisor:which_children(Proc), - Child /= undefined]. + Rs = mnesia:dirty_read(sql_pool, Host), + [R#sql_pool.pid || R <- Rs]. get_random_pid(Host) -> Pids = get_pids(Host), lists:nth(erlang:phash(now(), length(Pids)), Pids). + +add_pid(Host, Pid) -> + F = fun() -> + mnesia:write( + #sql_pool{host = Host, + pid = Pid}) + end, + mnesia:ets(F). + +remove_pid(Host, Pid) -> + F = fun() -> + mnesia:delete_object( + #sql_pool{host = Host, + pid = Pid}) + end, + mnesia:ets(F). diff --git a/src/p1_fsm.erl b/src/p1_fsm.erl index 03ff7f8ce..9ca924112 100644 --- a/src/p1_fsm.erl +++ b/src/p1_fsm.erl @@ -517,6 +517,25 @@ print_event(Dev, return, {Name, StateName}) -> io:format(Dev, "*DBG* ~p switched to state ~w~n", [Name, StateName]). +relay_messages(MRef, TRef, Clone, Queue) -> + lists:foreach( + fun(Msg) -> Clone ! Msg end, + queue:to_list(Queue)), + relay_messages(MRef, TRef, Clone). + +relay_messages(MRef, TRef, Clone) -> + receive + {'DOWN', MRef, process, Clone, Reason} -> + Reason; + {'EXIT', _Parent, _Reason} -> + {migrated, Clone}; + {timeout, TRef, timeout} -> + {migrated, Clone}; + Msg -> + Clone ! Msg, + relay_messages(MRef, TRef, Clone) + end. + handle_msg(Msg, Parent, Name, StateName, StateData, Mod, _Time, Limits, Queue, QueueLen) -> %No debug here From = from(Msg), @@ -535,6 +554,23 @@ handle_msg(Msg, Parent, Name, StateName, StateData, Mod, _Time, reply(From, Reply), loop(Parent, Name, NStateName, NStateData, Mod, Time1, [], Limits, Queue, QueueLen); + {migrate, NStateData, {Node, M, F, A}, Time1} -> + Reason = case catch rpc:call(Node, M, F, A, 5000) of + {badrpc, _} = Err -> + {migration_error, Err}; + {'EXIT', _} = Err -> + {migration_error, Err}; + {error, _} = Err -> + {migration_error, Err}; + {ok, Clone} -> + process_flag(trap_exit, true), + MRef = erlang:monitor(process, Clone), + TRef = erlang:start_timer(Time1, self(), timeout), + relay_messages(MRef, TRef, Clone, Queue); + Reply -> + {migration_error, {bad_reply, Reply}} + end, + terminate(Reason, Name, Msg, Mod, StateName, NStateData, []); {stop, Reason, NStateData} -> terminate(Reason, Name, Msg, Mod, StateName, NStateData, []); {stop, Reason, Reply, NStateData} when From =/= undefined -> @@ -571,6 +607,23 @@ handle_msg(Msg, Parent, Name, StateName, StateData, Debug1 = reply(Name, From, Reply, Debug, NStateName), loop(Parent, Name, NStateName, NStateData, Mod, Time1, Debug1, Limits, Queue, QueueLen); + {migrate, NStateData, {Node, M, F, A}, Time1} -> + Reason = case catch rpc:call(Node, M, F, A, Time1) of + {badrpc, R} -> + {migration_error, R}; + {'EXIT', R} -> + {migration_error, R}; + {error, R} -> + {migration_error, R}; + {ok, Clone} -> + process_flag(trap_exit, true), + MRef = erlang:monitor(process, Clone), + TRef = erlang:start_timer(Time1, self(), timeout), + relay_messages(MRef, TRef, Clone, Queue); + Reply -> + {migration_error, {bad_reply, Reply}} + end, + terminate(Reason, Name, Msg, Mod, StateName, NStateData, Debug); {stop, Reason, NStateData} -> terminate(Reason, Name, Msg, Mod, StateName, NStateData, Debug); {stop, Reason, Reply, NStateData} when From =/= undefined -> @@ -633,12 +686,10 @@ terminate(Reason, Name, Msg, Mod, StateName, StateData, Debug) -> %% Priority shutdown should be considered as %% shutdown by SASL exit(shutdown); - {process_limit, Limit} -> - %% Priority shutdown should be considered as - %% shutdown by SASL - error_logger:error_msg("FSM limit reached (~p): ~p~n", - [self(), Limit]), - exit(shutdown); + {process_limit, _Limit} -> + exit(Reason); + {migrated, _Clone} -> + exit(normal); _ -> error_info(Mod, Reason, Name, Msg, StateName, StateData, Debug), exit(Reason) @@ -705,7 +756,12 @@ get_msg(Msg) -> Msg. format_status(Opt, StatusData) -> [PDict, SysState, Parent, Debug, [Name, StateName, StateData, Mod, _Time]] = StatusData, - Header = lists:concat(["Status for state machine ", Name]), + NameTag = if is_pid(Name) -> + pid_to_list(Name); + is_atom(Name) -> + Name + end, + Header = lists:concat(["Status for state machine ", NameTag]), Log = sys:get_debug(log, Debug, []), Specfic = case erlang:function_exported(Mod, format_status, 2) of From c100cbedd1137da62bfcc3859d289fd068f15af7 Mon Sep 17 00:00:00 2001 From: Badlop Date: Fri, 2 Jul 2010 13:08:33 +0200 Subject: [PATCH 10/26] Document the mod_muc option captcha_protected --- doc/guide.html | 4 ++++ doc/guide.tex | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/doc/guide.html b/doc/guide.html index d4a8ef75f..a0f41f8a0 100644 --- a/doc/guide.html +++ b/doc/guide.html @@ -2477,6 +2477,10 @@ the room occupants.

    {anonymous, true|false}
    The room is anonymous: occupants don’t see the real JIDs of other occupants. Note that the room moderators can always see the real JIDs of the occupants. +
    {captcha_protected, false}
    +When a user tries to join a room where he has no affiliation (not owner, admin or member), +the room requires him to fill a CAPTCHA challenge (see section 3.1.8) +in order to accept her join in the room.
    {logging, false|true}
    The public messages are logged using mod_muc_log.
    {max_users, 200}
    Maximum number of occupants in the room.
    {members_by_default, true|false}
    The occupants that enter the room are participants by default, so they have ’voice’. diff --git a/doc/guide.tex b/doc/guide.tex index 272f933b4..ac5fc5527 100644 --- a/doc/guide.tex +++ b/doc/guide.tex @@ -3201,6 +3201,10 @@ Module options: \titem{\{anonymous, true|false\}} The room is anonymous: occupants don't see the real JIDs of other occupants. Note that the room moderators can always see the real JIDs of the occupants. + \titem{\{captcha\_protected, false\}} + When a user tries to join a room where he has no affiliation (not owner, admin or member), + the room requires him to fill a CAPTCHA challenge (see section \ref{captcha}) + in order to accept her join in the room. \titem{\{logging, false|true\}} The public messages are logged using \term{mod\_muc\_log}. \titem{\{max\_users, 200\}} Maximum number of occupants in the room. \titem{\{members\_by\_default, true|false\}} The occupants that enter the room are participants by default, so they have 'voice'. From e19ac27803d2dd5a391083e2838f15a041874e12 Mon Sep 17 00:00:00 2001 From: Badlop Date: Fri, 2 Jul 2010 15:19:54 +0200 Subject: [PATCH 11/26] Show some more room options in the log file --- src/mod_muc/mod_muc_log.erl | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/mod_muc/mod_muc_log.erl b/src/mod_muc/mod_muc_log.erl index f1c57eac0..d010e86b8 100644 --- a/src/mod_muc/mod_muc_log.erl +++ b/src/mod_muc/mod_muc_log.erl @@ -860,7 +860,9 @@ roomconfig_to_string(Options, Lang, FileFormat) -> T -> case Opt of password -> "
    " ++ OptText ++ "
    "; - title -> "
    " ++ ?T("Room title") ++ ": \"" ++ htmlize(T, FileFormat) ++ "\"
    "; + max_users -> "
    " ++ OptText ++ ": \"" ++ htmlize(integer_to_list(T), FileFormat) ++ "\"
    "; + title -> "
    " ++ OptText ++ ": \"" ++ htmlize(T, FileFormat) ++ "\"
    "; + description -> "
    " ++ OptText ++ ": \"" ++ htmlize(T, FileFormat) ++ "\"
    "; _ -> "\"" ++ T ++ "\"" end end, @@ -876,7 +878,7 @@ get_roomconfig_text(public) -> "Make room public searchable"; get_roomconfig_text(public_list) -> "Make participants list public"; get_roomconfig_text(password_protected) -> "Make room password protected"; get_roomconfig_text(password) -> "Password"; -get_roomconfig_text(anonymous) -> "Make room semianonymous"; +get_roomconfig_text(anonymous) -> "This room is not anonymous"; get_roomconfig_text(members_only) -> "Make room members-only"; get_roomconfig_text(moderated) -> "Make room moderated"; get_roomconfig_text(members_by_default) -> "Default users as participants"; @@ -885,6 +887,13 @@ get_roomconfig_text(allow_private_messages) -> "Allow users to send private mess get_roomconfig_text(allow_query_users) -> "Allow users to query other users"; get_roomconfig_text(allow_user_invites) -> "Allow users to send invites"; get_roomconfig_text(logging) -> "Enable logging"; +get_roomconfig_text(allow_visitor_nickchange) -> "Allow visitors to change nickname"; +get_roomconfig_text(allow_visitor_status) -> "Allow visitors to send status text in presence updates"; +get_roomconfig_text(captcha_protected) -> "Make room captcha protected"; +get_roomconfig_text(description) -> "Room description"; +%% get_roomconfig_text(subject) -> "Subject"; +%% get_roomconfig_text(subject_author) -> "Subject author"; +get_roomconfig_text(max_users) -> "Maximum Number of Occupants"; get_roomconfig_text(_) -> undefined. %% Users = [{JID, Nick, Role}] From 7e90d6cf923327c0f6391b309dfd4ccc46eb2186 Mon Sep 17 00:00:00 2001 From: Badlop Date: Sat, 3 Jul 2010 00:42:54 +0200 Subject: [PATCH 12/26] Fix print of command result that contains ~ (thanks to Tsukasa Hamano) --- src/ejabberd_ctl.erl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/ejabberd_ctl.erl b/src/ejabberd_ctl.erl index aee1a011f..33b2fe4d0 100644 --- a/src/ejabberd_ctl.erl +++ b/src/ejabberd_ctl.erl @@ -201,8 +201,7 @@ process(Args) -> case String of [] -> ok; _ -> - io:format(String), - io:format("\n") + io:format("~s~n", [String]) end, Code. From a42a012f9435090860480118e0ad5d1dbb628e1a Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Mon, 5 Jul 2010 13:43:44 +1000 Subject: [PATCH 13/26] Added new ejabberd profiler --- src/ejabberd.app | 1 + src/p1_prof.erl | 196 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 197 insertions(+) create mode 100644 src/p1_prof.erl diff --git a/src/ejabberd.app b/src/ejabberd.app index e347daf3b..67653d241 100644 --- a/src/ejabberd.app +++ b/src/ejabberd.app @@ -115,6 +115,7 @@ nodetree_virtual, p1_fsm, p1_mnesia, + p1_prof, randoms, sha, shaper, diff --git a/src/p1_prof.erl b/src/p1_prof.erl new file mode 100644 index 000000000..38ba40e5a --- /dev/null +++ b/src/p1_prof.erl @@ -0,0 +1,196 @@ +%%%------------------------------------------------------------------- +%%% File : p1_prof.erl +%%% Author : Evgeniy Khramtsov +%%% Description : Handly wrapper around eprof and fprof +%%% +%%% Created : 23 Jan 2010 by Evgeniy Khramtsov +%%% +%%% +%%% ejabberd, Copyright (C) 2002-2010 ProcessOne +%%% +%%% This program 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 2 of the +%%% License, or (at your option) any later version. +%%% +%%% This program 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 this program; if not, write to the Free Software +%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +%%% 02111-1307 USA +%%% +%%%------------------------------------------------------------------- +-module(p1_prof). + +%% API +-export([eprof_start/0, eprof_stop/0, + fprof_start/0, fprof_start/1, + fprof_stop/0]). + +-define(APPS, [ejabberd, mnesia]). + +%%==================================================================== +%% API +%%==================================================================== +eprof_start() -> + eprof:start(), + case lists:keyfind(running, 1, application:info()) of + {_, Apps} -> + case get_procs(?APPS, Apps) of + [] -> + {error, no_procs_found}; + Procs -> + eprof:start_profiling(Procs) + end; + _ -> + {error, no_app_info} + end. + +fprof_start() -> + fprof_start(0). + +fprof_start(Duration) -> + case lists:keyfind(running, 1, application:info()) of + {_, Apps} -> + case get_procs(?APPS, Apps) of + [] -> + {error, no_procs_found}; + Procs -> + fprof:trace([start, {procs, Procs}]), + if Duration > 0 -> + timer:sleep(Duration*1000), + fprof:trace([stop]); + true-> + ok + end + end; + _ -> + {error, no_app_info} + end. + +fprof_stop() -> + fprof:trace([stop]), + fprof:profile(), + fprof:analyse([totals, no_details, {sort, own}, + no_callers, {dest, "fprof.analysis"}]), + fprof:stop(), + format_fprof_analyze(). + +eprof_stop() -> + eprof:stop_profiling(), + eprof:analyse(). + +%%==================================================================== +%% Internal functions +%%==================================================================== +get_procs(Apps, AppList) -> + io:format("Searching for processes to profile...~n", []), + Procs = lists:flatmap( + fun({App, Leader}) when is_pid(Leader) -> + case lists:member(App, Apps) of + true -> + get_procs(Leader); + false -> + [] + end; + (_) -> + [] + end, AppList), + io:format("Found ~p processes~n", [length(Procs)]), + Procs. + +get_procs(Leader) -> + lists:filter( + fun(Pid) -> + case process_info(Pid, group_leader) of + {_, Leader} -> + true; + _ -> + false + end + end, processes()). + +format_fprof_analyze() -> + case file:consult("fprof.analysis") of + {ok, [_, [{totals, _, _, TotalOWN}] | Rest]} -> + OWNs = lists:flatmap( + fun({MFA, _, _, OWN}) -> + Percent = OWN*100/TotalOWN, + case round(Percent) of + 0 -> + []; + _ -> + [{mfa_to_list(MFA), Percent}] + end + end, Rest), + ACCs = collect_accs(Rest), + MaxACC = find_max(ACCs), + MaxOWN = find_max(OWNs), + io:format("=== Sorted by OWN:~n"), + lists:foreach( + fun({MFA, Per}) -> + L = length(MFA), + S = lists:duplicate(MaxOWN - L + 2, $ ), + io:format("~s~s~.2f%~n", [MFA, S, Per]) + end, lists:reverse(lists:keysort(2, OWNs))), + io:format("~n=== Sorted by ACC:~n"), + lists:foreach( + fun({MFA, Per}) -> + L = length(MFA), + S = lists:duplicate(MaxACC - L + 2, $ ), + io:format("~s~s~.2f%~n", [MFA, S, Per]) + end, lists:reverse(lists:keysort(2, ACCs))); + Err -> + Err + end. + +mfa_to_list({M, F, A}) -> + atom_to_list(M) ++ ":" ++ atom_to_list(F) ++ "/" ++ integer_to_list(A); +mfa_to_list(F) when is_atom(F) -> + atom_to_list(F). + +find_max(List) -> + find_max(List, 0). + +find_max([{V, _}|Tail], Acc) -> + find_max(Tail, lists:max([length(V), Acc])); +find_max([], Acc) -> + Acc. + +collect_accs(List) -> + List1 = lists:filter( + fun({MFA, _, _, _}) -> + case MFA of + {sys, _, _} -> + false; + suspend -> + false; + {gen_fsm, _, _} -> + false; + {p1_fsm, _, _} -> + false; + {gen, _, _} -> + false; + {gen_server, _, _} -> + false; + {proc_lib, _, _} -> + false; + _ -> + true + end + end, List), + TotalACC = lists:sum([A || {_, _, A, _} <- List1]), + lists:flatmap( + fun({MFA, _, ACC, _}) -> + Percent = ACC*100/TotalACC, + case round(Percent) of + 0 -> + []; + _ -> + [{mfa_to_list(MFA), Percent}] + end + end, List1). From 6c96157d1b6a099dd008d61ca572760d3bd6adaf Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Sat, 10 Jul 2010 01:36:12 +1000 Subject: [PATCH 14/26] Added functions to collect statistics about queues, memory, reductions etc. Several cleanups --- src/p1_prof.erl | 149 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 145 insertions(+), 4 deletions(-) diff --git a/src/p1_prof.erl b/src/p1_prof.erl index 38ba40e5a..a7edbe139 100644 --- a/src/p1_prof.erl +++ b/src/p1_prof.erl @@ -1,7 +1,7 @@ %%%------------------------------------------------------------------- %%% File : p1_prof.erl %%% Author : Evgeniy Khramtsov -%%% Description : Handly wrapper around eprof and fprof +%%% Description : Handy wrapper around eprof and fprof %%% %%% Created : 23 Jan 2010 by Evgeniy Khramtsov %%% @@ -29,7 +29,10 @@ %% API -export([eprof_start/0, eprof_stop/0, fprof_start/0, fprof_start/1, - fprof_stop/0]). + fprof_stop/0, fprof_analyze/0, + queue/0, queue/1, memory/0, memory/1, + reds/0, reds/1, trace/1, help/0, + q/0, m/0, r/0, q/1, m/1, r/1]). -define(APPS, [ejabberd, mnesia]). @@ -61,9 +64,11 @@ fprof_start(Duration) -> {error, no_procs_found}; Procs -> fprof:trace([start, {procs, Procs}]), + io:format("Profiling started~n"), if Duration > 0 -> timer:sleep(Duration*1000), - fprof:trace([stop]); + fprof:trace([stop]), + fprof:stop(); true-> ok end @@ -80,9 +85,92 @@ fprof_stop() -> fprof:stop(), format_fprof_analyze(). +fprof_analyze() -> + fprof_stop(). + eprof_stop() -> eprof:stop_profiling(), - eprof:analyse(). + case erlang:function_exported(eprof, analyse, 0) of + true -> + eprof:analyse(); + false -> + eprof:analyze() + end. + +help() -> + M = ?MODULE, + io:format("Brief help:~n" + "~p:queue(N) - show top N pids sorted by queue length~n" + "~p:queue() - shorthand for ~p:queue(10)~n" + "~p:memory(N) - show top N pids sorted by memory usage~n" + "~p:memory() - shorthand for ~p:memory(10)~n" + "~p:reds(N) - show top N pids sorted by reductions~n" + "~p:reds() - shorthand for ~p:reds(10)~n" + "~p:q(N)|~p:q() - same as ~p:queue(N)|~p:queue()~n" + "~p:m(N)|~p:m() - same as ~p:memory(N)|~p:memory()~n" + "~p:r(N)|~p:r() - same as ~p:reds(N)|~p:reds()~n" + "~p:trace(Pid) - trace Pid; to stop tracing close " + "Erlang shell with Ctrl+C~n" + "~p:eprof_start() - start eprof on all available pids; " + "DO NOT use on production system!~n" + "~p:eprof_stop() - stop eprof and print result~n" + "~p:fprof_start() - start fprof on all available pids; " + "DO NOT use on production system!~n" + "~p:fprof_stop() - stop eprof and print formatted result~n" + "~p:fprof_start(N) - start and run fprof for N seconds; " + "use ~p:fprof_analyze() to analyze collected statistics and " + "print formatted result; use on production system with CARE~n" + "~p:fprof_analyze() - analyze previously collected statistics " + "using ~p:fprof_start(N) and print formatted result~n" + "~p:help() - print this help~n", + lists:duplicate(31, M)). + +q() -> + queue(). + +q(N) -> + queue(N). + +m() -> + memory(). + +m(N) -> + memory(N). + +r() -> + reds(). + +r(N) -> + reds(N). + +queue() -> + queue(10). + +memory() -> + memory(10). + +reds() -> + reds(10). + +queue(N) -> + dump(N, lists:reverse(lists:ukeysort(1, all_pids(queue)))). + +memory(N) -> + dump(N, lists:reverse(lists:ukeysort(2, all_pids(memory)))). + +reds(N) -> + dump(N, lists:reverse(lists:ukeysort(3, all_pids(reductions)))). + +trace(Pid) -> + erlang:trace(Pid, true, [send, 'receive']), + trace_loop(). + +trace_loop() -> + receive + M -> + io:format("~p~n", [M]), + trace_loop() + end. %%==================================================================== %% Internal functions @@ -194,3 +282,56 @@ collect_accs(List) -> [{mfa_to_list(MFA), Percent}] end end, List1). + +all_pids(Type) -> + lists:foldl( + fun(P, Acc) when P == self() -> + %% exclude ourself from statistics + Acc; + (P, Acc) -> + case catch process_info( + P, + [message_queue_len, + memory, + reductions, + dictionary, + current_function, + registered_name]) of + [{_, Len}, {_, Memory}, {_, Reds}, + {_, Dict}, {_, CurFun}, {_, RegName}] -> + if Type == queue andalso Len == 0 -> + Acc; + true -> + [{Len, Memory, Reds, Dict, CurFun, P, RegName}|Acc] + end; + _ -> + Acc + end + end, [], processes()). + +dump(N, Rs) -> + lists:foreach( + fun({MsgQLen, Memory, Reds, Dict, CurFun, Pid, RegName}) -> + PidStr = pid_to_list(Pid), + [_, Maj, Min] = string:tokens( + string:substr( + PidStr, 2, length(PidStr) - 2), "."), + io:format("** pid(0,~s,~s)~n" + "** registered name: ~p~n" + "** memory: ~p~n" + "** reductions: ~p~n" + "** message queue len: ~p~n" + "** current_function: ~p~n" + "** dictionary: ~p~n~n", + [Maj, Min, RegName, Memory, Reds, MsgQLen, CurFun, Dict]) + end, nthhead(N, Rs)). + +nthhead(N, L) -> + lists:reverse(nthhead(N, L, [])). + +nthhead(0, _L, Acc) -> + Acc; +nthhead(N, [H|T], Acc) -> + nthhead(N-1, T, [H|Acc]); +nthhead(_N, [], Acc) -> + Acc. From d106f741d90ef29d3fb3c7ab1bd3f6f85bf3228b Mon Sep 17 00:00:00 2001 From: Badlop Date: Fri, 9 Jul 2010 22:39:13 +0200 Subject: [PATCH 15/26] Some systems delete the lock dir; in such case don't use flock at all --- src/ejabberdctl.template | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ejabberdctl.template b/src/ejabberdctl.template index 6e4588b5d..7a5ff7639 100644 --- a/src/ejabberdctl.template +++ b/src/ejabberdctl.template @@ -239,7 +239,7 @@ ctl () MAXCONNID=100 CONNLOCKDIR=@LOCALSTATEDIR@/lock/ejabberdctl FLOCK='/usr/bin/flock' - if [ ! -x "$FLOCK" ] ; then + if [ ! -x "$FLOCK" || ! -d "$CONNLOCKDIR" ] ; then JOT='/usr/bin/jot' if [ ! -x "$JOT" ] ; then # no flock or jot, simply invoke ctlexec() From 0c95cf7e615a78be9df2503c8a7fd5672fd1e73d Mon Sep 17 00:00:00 2001 From: Badlop Date: Sun, 11 Jul 2010 12:14:23 +0200 Subject: [PATCH 16/26] Mention missing modules in the overview table --- doc/guide.html | 2 ++ doc/guide.tex | 2 ++ 2 files changed, 4 insertions(+) diff --git a/doc/guide.html b/doc/guide.html index a0f41f8a0..d424d3a8f 100644 --- a/doc/guide.html +++ b/doc/guide.html @@ -1898,6 +1898,8 @@ all entries end with a comma: mod_configureServer configuration using Ad-Hocmod_adhoc mod_discoService Discovery (XEP-0030mod_echoEchoes XMPP stanzas  +mod_http_bindXMPP over Bosh service (HTTP Binding)  +mod_http_fileserverSmall HTTP file server  mod_ircIRC transport  mod_lastLast Activity (XEP-0012mod_last_odbcLast Activity (XEP-0012)supported DB (*) diff --git a/doc/guide.tex b/doc/guide.tex index ac5fc5527..99e47b1f1 100644 --- a/doc/guide.tex +++ b/doc/guide.tex @@ -2505,6 +2505,8 @@ The following table lists all modules included in \ejabberd{}. \hline \modconfigure{} & Server configuration using Ad-Hoc & \modadhoc{} \\ \hline \ahrefloc{moddisco}{\moddisco{}} & Service Discovery (\xepref{0030}) & \\ \hline \ahrefloc{modecho}{\modecho{}} & Echoes XMPP stanzas & \\ + \hline \ahrefloc{modhttpbind}{\modhttpbind{}} & XMPP over Bosh service (HTTP Binding) & \\ + \hline \ahrefloc{modhttpfileserver}{\modhttpfileserver{}} & Small HTTP file server & \\ \hline \ahrefloc{modirc}{\modirc{}} & IRC transport & \\ \hline \ahrefloc{modlast}{\modlast{}} & Last Activity (\xepref{0012}) & \\ \hline \ahrefloc{modlast}{\modlastodbc{}} & Last Activity (\xepref{0012}) & supported DB (*) \\ From 12e00c57f92e03df5b574b97971af8c8013712ff Mon Sep 17 00:00:00 2001 From: Badlop Date: Fri, 9 Jul 2010 20:02:29 +0200 Subject: [PATCH 17/26] When using OTP R14, use public_key library instead of old ssl (EJAB-953) --- src/Makefile.in | 2 +- src/aclocal.m4 | 17 +++++++++-------- src/ejabberd_s2s_in.erl | 6 ++++++ src/tls/Makefile.in | 1 + src/tls/tls.erl | 10 +++++++++- src/web/Makefile.in | 2 +- src/web/mod_http_fileserver.erl | 4 ++++ 7 files changed, 31 insertions(+), 11 deletions(-) diff --git a/src/Makefile.in b/src/Makefile.in index 174084f64..364063764 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -30,7 +30,7 @@ else INIT_USER=$(INSTALLUSER) endif -EFLAGS += @ERLANG_SSL39@ -pa . +EFLAGS += @ERLANG_SSLVER@ -pa . # make debug=true to compile Erlang module with debug informations. ifdef debug diff --git a/src/aclocal.m4 b/src/aclocal.m4 index 79b0e3ec7..09b166b99 100644 --- a/src/aclocal.m4 +++ b/src/aclocal.m4 @@ -121,7 +121,6 @@ AC_DEFUN(AM_WITH_ERLANG, -author('alexey@sevcom.net'). -export([[start/0]]). --include_lib("ssl/include/ssl_pkix.hrl"). start() -> EIDirS = code:lib_dir("erl_interface") ++ "\n", @@ -130,11 +129,13 @@ start() -> file:write_file("conftest.out", list_to_binary(EIDirS ++ EILibS ++ ssldef() ++ RootDirS)), halt(). --[ifdef]('id-pkix'). -ssldef() -> "-DSSL39\n". --else. -ssldef() -> "\n". --endif. +ssldef() -> + OTP = (catch erlang:system_info(otp_release)), + if + OTP >= "R14" -> "-DSSL40\n"; + OTP >= "R12" -> "-DSSL39\n"; + true -> "" + end. %% return physical architecture based on OS/Processor archname() -> @@ -184,7 +185,7 @@ _EOF # Second line ERLANG_EI_LIB=`cat conftest.out | head -n 2 | tail -n 1` # Third line - ERLANG_SSL39=`cat conftest.out | head -n 3 | tail -n 1` + ERLANG_SSLVER=`cat conftest.out | head -n 3 | tail -n 1` # End line ERLANG_DIR=`cat conftest.out | tail -n 1` @@ -193,7 +194,7 @@ _EOF AC_SUBST(ERLANG_CFLAGS) AC_SUBST(ERLANG_LIBS) - AC_SUBST(ERLANG_SSL39) + AC_SUBST(ERLANG_SSLVER) AC_SUBST(ERLC) AC_SUBST(ERL) ]) diff --git a/src/ejabberd_s2s_in.erl b/src/ejabberd_s2s_in.erl index 179dc08f1..56086c9ef 100644 --- a/src/ejabberd_s2s_in.erl +++ b/src/ejabberd_s2s_in.erl @@ -48,6 +48,11 @@ -include("ejabberd.hrl"). -include("jlib.hrl"). +-ifdef(SSL40). +-include_lib("public_key/include/public_key.hrl"). +-define(PKIXEXPLICIT, 'OTP-PUB-KEY'). +-define(PKIXIMPLICIT, 'OTP-PUB-KEY'). +-else. -ifdef(SSL39). -include_lib("ssl/include/ssl_pkix.hrl"). -define(PKIXEXPLICIT, 'OTP-PKIX'). @@ -58,6 +63,7 @@ -define(PKIXEXPLICIT, 'PKIX1Explicit88'). -define(PKIXIMPLICIT, 'PKIX1Implicit88'). -endif. +-endif. -include("XmppAddr.hrl"). -define(DICT, dict). diff --git a/src/tls/Makefile.in b/src/tls/Makefile.in index b29e1ae29..445879657 100644 --- a/src/tls/Makefile.in +++ b/src/tls/Makefile.in @@ -21,6 +21,7 @@ ifeq ($(shell uname),SunOs) DYNAMIC_LIB_CFLAGS = -KPIC -G -z text endif +EFLAGS += @ERLANG_SSLVER@ EFLAGS += -I .. EFLAGS += -pz .. diff --git a/src/tls/tls.erl b/src/tls/tls.erl index 9aee54cfb..9c921b36f 100644 --- a/src/tls/tls.erl +++ b/src/tls/tls.erl @@ -61,6 +61,13 @@ -define(GET_VERIFY_RESULT, 8). -define(VERIFY_NONE, 16#10000). +-ifdef(SSL40). +-define(CERT_DECODE, {public_key, pkix_decode_cert, plain}). +-else. +-define(CERT_DECODE, {ssl_pkix, decode_cert, [pkix]}). +-endif. + + -record(tlssock, {tcpsock, tlsport}). start() -> @@ -232,7 +239,8 @@ close(#tlssock{tcpsock = TCPSocket, tlsport = Port}) -> get_peer_certificate(#tlssock{tlsport = Port}) -> case port_control(Port, ?GET_PEER_CERTIFICATE, []) of <<0, BCert/binary>> -> - case catch ssl_pkix:decode_cert(BCert, [pkix]) of + {CertMod, CertFun, CertSecondArg} = ?CERT_DECODE, + case catch apply(CertMod, CertFun, [BCert, CertSecondArg]) of {ok, Cert} -> {ok, Cert}; _ -> diff --git a/src/web/Makefile.in b/src/web/Makefile.in index 519314ef7..77f801410 100644 --- a/src/web/Makefile.in +++ b/src/web/Makefile.in @@ -9,7 +9,7 @@ LIBS = @LIBS@ ERLANG_CFLAGS = @ERLANG_CFLAGS@ ERLANG_LIBS = @ERLANG_LIBS@ -EFLAGS += @ERLANG_SSL39@ +EFLAGS += @ERLANG_SSLVER@ EFLAGS += -I .. EFLAGS += -pz .. diff --git a/src/web/mod_http_fileserver.erl b/src/web/mod_http_fileserver.erl index 4f683ea91..ab4e1a5bd 100644 --- a/src/web/mod_http_fileserver.erl +++ b/src/web/mod_http_fileserver.erl @@ -66,11 +66,15 @@ headers }). +-ifdef(SSL40). +-define(STRING2LOWER, string). +-else. -ifdef(SSL39). -define(STRING2LOWER, string). -else. -define(STRING2LOWER, httpd_util). -endif. +-endif. -record(state, {host, docroot, accesslog, accesslogfd, directory_indices, custom_headers, default_content_type, content_types = []}). From d539fd28c1bc81f13a45f9d9af4c99f08887fdca Mon Sep 17 00:00:00 2001 From: Badlop Date: Mon, 12 Jul 2010 15:18:15 +0200 Subject: [PATCH 18/26] Recompile the 'configure' script --- src/configure | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/configure b/src/configure index 5ff174752..a698ae8bb 100755 --- a/src/configure +++ b/src/configure @@ -648,7 +648,7 @@ EGREP GREP CPP LIBICONV -ERLANG_SSL39 +ERLANG_SSLVER ERLANG_LIBS ERLANG_CFLAGS ERL @@ -3211,7 +3211,6 @@ fi -author('alexey@sevcom.net'). -export([start/0]). --include_lib("ssl/include/ssl_pkix.hrl"). start() -> EIDirS = code:lib_dir("erl_interface") ++ "\n", @@ -3220,11 +3219,13 @@ start() -> file:write_file("conftest.out", list_to_binary(EIDirS ++ EILibS ++ ssldef() ++ RootDirS)), halt(). --ifdef('id-pkix'). -ssldef() -> "-DSSL39\n". --else. -ssldef() -> "\n". --endif. +ssldef() -> + OTP = (catch erlang:system_info(otp_release)), + if + OTP >= "R14" -> "-DSSL40\n"; + OTP >= "R12" -> "-DSSL39\n"; + true -> "" + end. %% return physical architecture based on OS/Processor archname() -> @@ -3274,7 +3275,7 @@ _EOF # Second line ERLANG_EI_LIB=`cat conftest.out | head -n 2 | tail -n 1` # Third line - ERLANG_SSL39=`cat conftest.out | head -n 3 | tail -n 1` + ERLANG_SSLVER=`cat conftest.out | head -n 3 | tail -n 1` # End line ERLANG_DIR=`cat conftest.out | tail -n 1` From 10d43c7cc60e1af6503b9ad68569a847f50df436 Mon Sep 17 00:00:00 2001 From: Badlop Date: Mon, 12 Jul 2010 16:02:41 +0200 Subject: [PATCH 19/26] Only compile and install p1_prof when: make debugtools=true --- src/Makefile.in | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Makefile.in b/src/Makefile.in index 364063764..cf600c324 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -37,9 +37,8 @@ ifdef debug EFLAGS+=+debug_info +export_all endif -DEBUGTOOLS = ejabberd_debug.erl -ifdef ejabberd_debug - EFLAGS+=-Dejabberd_debug +DEBUGTOOLS = p1_prof.erl +ifdef debugtools SOURCES+=$(DEBUGTOOLS) endif From e82db8cc7f51c2777b1e4831838b30c691488636 Mon Sep 17 00:00:00 2001 From: Badlop Date: Mon, 12 Jul 2010 15:56:34 +0200 Subject: [PATCH 20/26] Remove ejabberd_debug because p1_prof provides similar and better features --- src/ejabberd_debug.erl | 97 ------------------------------------------ 1 file changed, 97 deletions(-) delete mode 100644 src/ejabberd_debug.erl diff --git a/src/ejabberd_debug.erl b/src/ejabberd_debug.erl deleted file mode 100644 index f1baf1f78..000000000 --- a/src/ejabberd_debug.erl +++ /dev/null @@ -1,97 +0,0 @@ -%%%---------------------------------------------------------------------- -%%% File : ejabberd_debug.erl -%%% Author : Mickael Remond -%%% Purpose : ejabberd's application callback module -%%% Created : 6 may 2009 by Mickael Remond -%%% -%%% -%%% ejabberd, Copyright (C) 2002-2010 ProcessOne -%%% -%%% This program 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 2 of the -%%% License, or (at your option) any later version. -%%% -%%% This program 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 this program; if not, write to the Free Software -%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA -%%% 02111-1307 USA -%%% -%%%---------------------------------------------------------------------- - --module(ejabberd_debug). - --export([eprof_start/0, fprof_start/0, stop/0]). --export([pids/0]). - -eprof_start() -> - eprof:start(), - eprof:profile(pids()). - -fprof_start() -> - fprof:trace([start, {file, "/tmp/fprof"}, {procs, pids()}]). - -%% Stop all profilers -stop() -> - catch eprof:stop(), - catch fprof:stop(), - ok. - -pids() -> - lists:zf( - fun(Pid) -> - case process_info(Pid) of - ProcessInfo when is_list(ProcessInfo) -> - CurrentFunction = current_function(ProcessInfo), - InitialCall = initial_call(ProcessInfo), - RegisteredName = registered_name(ProcessInfo), - Ancestor = ancestor(ProcessInfo), - filter_pid(Pid, CurrentFunction, InitialCall, RegisteredName, Ancestor); - _ -> - false - end - end, - processes()). - -current_function(ProcessInfo) -> - {value, {_, {CurrentFunction, _,_}}} = - lists:keysearch(current_function, 1, ProcessInfo), - atom_to_list(CurrentFunction). - -initial_call(ProcessInfo) -> - {value, {_, {InitialCall, _,_}}} = - lists:keysearch(initial_call, 1, ProcessInfo), - atom_to_list(InitialCall). - -registered_name(ProcessInfo) -> - case lists:keysearch(registered_name, 1, ProcessInfo) of - {value, {_, Name}} when is_atom(Name) -> atom_to_list(Name); - _ -> "" - end. - -ancestor(ProcessInfo) -> - {value, {_, Dictionary}} = lists:keysearch(dictionary, 1, ProcessInfo), - case lists:keysearch('$ancestors', 1, Dictionary) of - {value, {_, [Ancestor|_T]}} when is_atom(Ancestor) -> - atom_to_list(Ancestor); - _ -> - "" - end. - -filter_pid(Pid, "ejabberd" ++ _, _InitialCall, _RegisteredName, _Ancestor) -> - {true, Pid}; -filter_pid(Pid, _CurrentFunction, "ejabberd" ++ _, _RegisteredName, _Ancestor) -> - {true, Pid}; -filter_pid(Pid, _CurrentFunction, _InitialCall, "ejabberd"++_, _Ancestor) -> - {true, Pid}; -filter_pid(Pid, _CurrentFunction, _InitialCall, "stringprep"++_, _Ancestor) -> - {true, Pid}; -filter_pid(Pid, _CurrentFunction, _InitialCall, _RegisteredName, "ejabberd"++_) -> - {true, Pid}; -filter_pid(_Pid, _CurrentFunction, _InitialCall, _RegisteredName, _Ancestor) -> - false. From 42ddc297fe4429d0e9662e522a53289266d98224 Mon Sep 17 00:00:00 2001 From: Badlop Date: Mon, 12 Jul 2010 18:53:16 +0200 Subject: [PATCH 21/26] Fix my flock change from last friday --- src/ejabberdctl.template | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ejabberdctl.template b/src/ejabberdctl.template index 7a5ff7639..fecdecc86 100644 --- a/src/ejabberdctl.template +++ b/src/ejabberdctl.template @@ -239,7 +239,7 @@ ctl () MAXCONNID=100 CONNLOCKDIR=@LOCALSTATEDIR@/lock/ejabberdctl FLOCK='/usr/bin/flock' - if [ ! -x "$FLOCK" || ! -d "$CONNLOCKDIR" ] ; then + if [ ! -x "$FLOCK" ] || [ ! -d "$CONNLOCKDIR" ] ; then JOT='/usr/bin/jot' if [ ! -x "$JOT" ] ; then # no flock or jot, simply invoke ctlexec() From d7930d7f820e5dd6b07b823f155aeb943b525e16 Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Wed, 14 Jul 2010 14:19:16 +1000 Subject: [PATCH 22/26] Use driver allocators in expat for reflecting memory in erlang:memory(system) --- src/expat_erl.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/expat_erl.c b/src/expat_erl.c index 8727e5172..f6b552c59 100644 --- a/src/expat_erl.c +++ b/src/expat_erl.c @@ -41,6 +41,8 @@ typedef struct { XML_Parser parser; } expat_data; +static XML_Memory_Handling_Suite ms = {driver_alloc, driver_realloc, driver_free}; + void *erlXML_StartElementHandler(expat_data *d, const XML_Char *name, const XML_Char **atts) @@ -98,7 +100,7 @@ static ErlDrvData expat_erl_start(ErlDrvPort port, char *buff) { expat_data* d = (expat_data*)driver_alloc(sizeof(expat_data)); d->port = port; - d->parser = XML_ParserCreate("UTF-8"); + d->parser = XML_ParserCreate_MM("UTF-8", &ms, NULL); XML_SetUserData(d->parser, d); set_port_control_flags(port, PORT_CONTROL_FLAG_BINARY); From 5030f355580ab2686b1df944ea8ab61f5a7ba93f Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Wed, 14 Jul 2010 21:23:21 +1000 Subject: [PATCH 23/26] correct handling of SQL boolean types (EJAB-1275) --- src/mod_privacy_odbc.erl | 10 +++++----- src/odbc/ejabberd_odbc.erl | 7 +++++++ 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/mod_privacy_odbc.erl b/src/mod_privacy_odbc.erl index ae572ae64..5ad2fb958 100644 --- a/src/mod_privacy_odbc.erl +++ b/src/mod_privacy_odbc.erl @@ -726,11 +726,11 @@ raw_to_item({SType, SValue, SAction, SOrder, SMatchAll, SMatchIQ, "d" -> deny end, Order = list_to_integer(SOrder), - MatchAll = SMatchAll == "1" orelse SMatchAll == "t", - MatchIQ = SMatchIQ == "1" orelse SMatchIQ == "t" , - MatchMessage = SMatchMessage == "1" orelse SMatchMessage == "t", - MatchPresenceIn = SMatchPresenceIn == "1" orelse SMatchPresenceIn == "t", - MatchPresenceOut = SMatchPresenceOut == "1" orelse SMatchPresenceOut == "t", + MatchAll = ejabberd_odbc:to_bool(SMatchAll), + MatchIQ = ejabberd_odbc:to_bool(SMatchIQ), + MatchMessage = ejabberd_odbc:to_bool(SMatchMessage), + MatchPresenceIn = ejabberd_odbc:to_bool(SMatchPresenceIn), + MatchPresenceOut = ejabberd_odbc:to_bool(SMatchPresenceOut), #listitem{type = Type, value = Value, action = Action, diff --git a/src/odbc/ejabberd_odbc.erl b/src/odbc/ejabberd_odbc.erl index 1b07fd6d9..4a6481525 100644 --- a/src/odbc/ejabberd_odbc.erl +++ b/src/odbc/ejabberd_odbc.erl @@ -39,6 +39,7 @@ sql_bloc/2, escape/1, escape_like/1, + to_bool/1, keep_alive/1]). %% gen_fsm callbacks @@ -161,6 +162,12 @@ escape_like($%) -> "\\%"; escape_like($_) -> "\\_"; escape_like(C) -> odbc_queries:escape(C). +to_bool("t") -> true; +to_bool("true") -> true; +to_bool("1") -> true; +to_bool(true) -> true; +to_bool(1) -> true; +to_bool(_) -> false. %%%---------------------------------------------------------------------- %%% Callback functions from gen_fsm From ac84267b22e6b60540f7a698f3e69432b4d75dc6 Mon Sep 17 00:00:00 2001 From: Badlop Date: Mon, 19 Jul 2010 12:08:02 +0200 Subject: [PATCH 24/26] Describe what a user gets when he hits the registration_timeout limit --- doc/guide.html | 8 +++++--- doc/guide.tex | 8 +++++--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/doc/guide.html b/doc/guide.html index d424d3a8f..3b78cba9e 100644 --- a/doc/guide.html +++ b/doc/guide.html @@ -2975,9 +2975,11 @@ the processing discipline for In-Band Registration (jabber:iq:register)

    This module reads also another option defined globally for the server: {registration_timeout, Timeout}. This option limits the frequency of registration from a given IP or username. -So, a user can’t register a new account from the same IP address or JID during -this number of seconds after previous registration. -Timeout is expressed in seconds, and must be an integer. +So, a user that tries to register a new account from the same IP address or JID during +this number of seconds after his previous registration +will receive an error resource-constraint with the explanation: +“Users are not allowed to register accounts so quickly”. +The timeout is expressed in seconds, and it must be an integer. To disable this limitation, instead of an integer put a word like: infinity. Default value: 600 seconds.

    Examples: diff --git a/doc/guide.tex b/doc/guide.tex index 99e47b1f1..ecd4815c6 100644 --- a/doc/guide.tex +++ b/doc/guide.tex @@ -3779,9 +3779,11 @@ from s2s leads to uncontrolled massive accounts creation by rogue users. This module reads also another option defined globally for the server: \term{\{registration\_timeout, Timeout\}}. \ind{options!registratimeout} This option limits the frequency of registration from a given IP or username. -So, a user can't register a new account from the same IP address or JID during -this number of seconds after previous registration. -Timeout is expressed in seconds, and must be an integer. +So, a user that tries to register a new account from the same IP address or JID during +this number of seconds after his previous registration +will receive an error \term{resource-constraint} with the explanation: +``Users are not allowed to register accounts so quickly''. +The timeout is expressed in seconds, and it must be an integer. To disable this limitation, instead of an integer put a word like: \term{infinity}. Default value: 600 seconds. From 26f6eebaa9a81752a01b1868832732fd816c0543 Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Tue, 20 Jul 2010 14:57:23 +1000 Subject: [PATCH 25/26] Use driver allocators in ejabberd_zlib_drv.c for reflecting memory in erlang:memory(system) --- src/ejabberd_zlib/ejabberd_zlib_drv.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/src/ejabberd_zlib/ejabberd_zlib_drv.c b/src/ejabberd_zlib/ejabberd_zlib_drv.c index 363eb5b01..5b420e4eb 100644 --- a/src/ejabberd_zlib/ejabberd_zlib_drv.c +++ b/src/ejabberd_zlib/ejabberd_zlib_drv.c @@ -32,6 +32,15 @@ typedef struct { z_stream *i_stream; } ejabberd_zlib_data; +static void* zlib_alloc(void* data, unsigned int items, unsigned int size) +{ + return (void*) driver_alloc(items*size); +} + +static void zlib_free(void* data, void* addr) +{ + driver_free(addr); +} static ErlDrvData ejabberd_zlib_drv_start(ErlDrvPort port, char *buff) { @@ -39,18 +48,18 @@ static ErlDrvData ejabberd_zlib_drv_start(ErlDrvPort port, char *buff) (ejabberd_zlib_data *)driver_alloc(sizeof(ejabberd_zlib_data)); d->port = port; - d->d_stream = (z_stream *)malloc(sizeof(z_stream)); + d->d_stream = (z_stream *)driver_alloc(sizeof(z_stream)); - d->d_stream->zalloc = (alloc_func)0; - d->d_stream->zfree = (free_func)0; + d->d_stream->zalloc = zlib_alloc; + d->d_stream->zfree = zlib_free; d->d_stream->opaque = (voidpf)0; deflateInit(d->d_stream, Z_DEFAULT_COMPRESSION); - d->i_stream = (z_stream *)malloc(sizeof(z_stream)); + d->i_stream = (z_stream *)driver_alloc(sizeof(z_stream)); - d->i_stream->zalloc = (alloc_func)0; - d->i_stream->zfree = (free_func)0; + d->i_stream->zalloc = zlib_alloc; + d->i_stream->zfree = zlib_free; d->i_stream->opaque = (voidpf)0; inflateInit(d->i_stream); @@ -65,10 +74,10 @@ static void ejabberd_zlib_drv_stop(ErlDrvData handle) ejabberd_zlib_data *d = (ejabberd_zlib_data *)handle; deflateEnd(d->d_stream); - free(d->d_stream); + driver_free(d->d_stream); inflateEnd(d->i_stream); - free(d->i_stream); + driver_free(d->i_stream); driver_free((char *)handle); } From 8c4884d665595f633c542e889256d193b4faa487 Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Tue, 20 Jul 2010 15:28:22 +1000 Subject: [PATCH 26/26] Use driver allocators in iconv_erl.c for reflecting memory in erlang:memory(system) --- src/mod_irc/iconv_erl.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/mod_irc/iconv_erl.c b/src/mod_irc/iconv_erl.c index 9e560610d..3212568d9 100644 --- a/src/mod_irc/iconv_erl.c +++ b/src/mod_irc/iconv_erl.c @@ -64,15 +64,15 @@ static int iconv_erl_control(ErlDrvData drv_data, ei_decode_version(buf, &index, &i); ei_decode_tuple_header(buf, &index, &i); ei_get_type(buf, &index, &i, &size); - from = malloc(size + 1); + from = driver_alloc(size + 1); ei_decode_string(buf, &index, from); ei_get_type(buf, &index, &i, &size); - to = malloc(size + 1); + to = driver_alloc(size + 1); ei_decode_string(buf, &index, to); ei_get_type(buf, &index, &i, &size); - stmp = string = malloc(size + 1); + stmp = string = driver_alloc(size + 1); ei_decode_string(buf, &index, string); /* Special mode: parse as UTF-8 if possible; otherwise assume it's @@ -92,9 +92,9 @@ static int iconv_erl_control(ErlDrvData drv_data, *rbuf = (char*)(b = driver_alloc_binary(size)); memcpy(b->orig_bytes, string, size); - free(from); - free(to); - free(string); + driver_free(from); + driver_free(to); + driver_free(string); return size; } @@ -102,7 +102,7 @@ static int iconv_erl_control(ErlDrvData drv_data, outleft = avail = 4*size; inleft = size; - rtmp = rstring = malloc(avail); + rtmp = rstring = driver_alloc(avail); while (inleft > 0) { if (iconv(cd, &stmp, &inleft, &rtmp, &outleft) == (size_t) -1) { if (invalid_utf8_as_latin1 && (*stmp & 0x80) && outleft >= 2) { @@ -121,10 +121,10 @@ static int iconv_erl_control(ErlDrvData drv_data, *rbuf = (char*)(b = driver_alloc_binary(size)); memcpy(b->orig_bytes, rstring, size); - free(from); - free(to); - free(string); - free(rstring); + driver_free(from); + driver_free(to); + driver_free(string); + driver_free(rstring); iconv_close(cd); return size;