diff options
author | Martin Langhoff <martin@laptop.org> | 2010-01-24 14:39:15 +0100 |
---|---|---|
committer | Badlop <badlop@process-one.net> | 2010-02-12 20:23:33 +0100 |
commit | 10c16b1cdf29799251f5ea19c1c004c60840b94d (patch) | |
tree | 537adc8edbe923050197ca8b60cd8bb3a0313b2b | |
parent | Remove unnecessary section about Snow Leopard with Erlang R13B (diff) |
ejabberdctl: support concurrent connections with bound conn names
If flock is available, ejabberdctl will use it to grab one
of a bound number of connection names. This allows concurrent
connections while using a bound number of atoms.
Using PID, timestamps or random strings for transient connection IDs
(which would avoid the need for flock) uses an unbound number of atoms.
This can effectively DoS servers, as these connection names are
not garbage collected.
-rw-r--r-- | src/Makefile.in | 10 | ||||
-rw-r--r-- | src/ejabberdctl.template | 78 |
2 files changed, 81 insertions, 7 deletions
diff --git a/src/Makefile.in b/src/Makefile.in index 8485caa09..02f05e89d 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -110,6 +110,9 @@ MSGSDIR = $(PRIVDIR)/msgs # /var/lib/ejabberd/ SPOOLDIR = $(DESTDIR)@localstatedir@/lib/ejabberd +# /var/lock/ejabberdctl +CTLLOCKDIR = $(DESTDIR)@localstatedir@/lock/ejabberdctl + # /var/lib/ejabberd/.erlang.cookie COOKIEFILE = $(SPOOLDIR)/.erlang.cookie @@ -230,6 +233,12 @@ install: all install -d -m 750 $(O_USER) $(SPOOLDIR) $(CHOWN_COMMAND) -R @INSTALLUSER@ $(SPOOLDIR) >$(CHOWN_OUTPUT) chmod -R 750 $(SPOOLDIR) + + # ejabberdctl lock directory + install -d -m 750 $(O_USER) $(CTLLOCKDIR) + $(CHOWN_COMMAND) -R @INSTALLUSER@ $(CTLLOCKDIR) >$(CHOWN_OUTPUT) + chmod -R 750 $(CTLLOCKDIR) + [ ! -f $(COOKIEFILE) ] || { $(CHOWN_COMMAND) @INSTALLUSER@ $(COOKIEFILE) >$(CHOWN_OUTPUT) ; chmod 400 $(COOKIEFILE) ; } # # Log directory @@ -265,6 +274,7 @@ uninstall-all: uninstall-binary rm -rf $(ETCDIR) rm -rf $(EJABBERDDIR) rm -rf $(SPOOLDIR) + rm -rf $(CTLLOCKDIR) rm -rf $(LOGDIR) clean: clean-recursive clean-local diff --git a/src/ejabberdctl.template b/src/ejabberdctl.template index 2df7be710..f5af13be2 100644 --- a/src/ejabberdctl.template +++ b/src/ejabberdctl.template @@ -14,6 +14,17 @@ ERLANG_NODE=$NODE@$HOST ERL=@erl@ INSTALLUSER=@installuser@ +# Control number of connections identifiers +# using flock if available. Expects a linux-style +# flock that can lock a file descriptor. +MAXCONNID=100 +CONNLOCKDIR=@LOCALSTATEDIR@/lock/ejabberdctl +FLOCK='/usr/bin/flock' +if [ ! -x "$FLOCK" ];then + FLOCK="" +fi + + # parse command line parameters ARGS= while [ $# -ne 0 ] ; do @@ -228,13 +239,54 @@ help () ctl () { COMMAND=$@ - $EXEC_CMD "$ERL \ - $NAME ctl-${ERLANG_NODE} \ - -noinput \ - -hidden \ - -pa $EJABBERD_EBIN_PATH \ - -s ejabberd_ctl -extra $ERLANG_NODE $COMMAND" - result=$? + + if [ ! "$FLOCK" ];then + # no flock, simply invoke ctlexec() + CTL_CONN="ctl-${EJABBERD_NODE}" + ctlexec $CTL_CONN $COMMAND + result=$? + else + # we have flock so we get a lock + # on one of a limited number of + # conn names -- this allows + # concurrent invokations using a bound + # number of atoms + for N in $(seq 1 $MAXCONNID); do + CTL_CONN="ejabberdctl-$N" + CTL_LOCKFILE="$CONNLOCKDIR/$CTL_CONN" + ( + exec 8>"$CTL_LOCKFILE" + if flock --nb 8; then + ctlexec $CTL_CONN $COMMAND + ssresult=$? + # segregate from possible flock exit(1) + ssresult=$(expr $ssresult \* 10) + exit $ssresult + else + exit 1 + fi + ) + result=$? + if [ $result -eq 1 ]; then + # means we errored out in flock + # rather than in the exec - stay in the loop + # trying other conn names... + badlock=1 + else + badlock="" + break; + fi + done + result=$(expr $result / 10) + fi + + if [ "$badlock" ];then + echo "Ran out of connections to try. Your ejabberd processes" >&2 + echo "may be stuck or this is a very busy server. For very" >&2 + echo "busy servers, consider raising MAXCONNIDS" >&2 + exit 1; + fi + case $result in 0) :;; 1) :;; @@ -244,6 +296,18 @@ ctl () return $result } +ctlexec () +{ + CONN_NAME=$1; shift + COMMAND=$@ + $EXEC_CMD "$ERL \ + $NAME ${CONN_NAME} \ + -noinput \ + -hidden \ + -pa $EJABBERD_EBIN_PATH \ + -s ejabberd_ctl -extra $ERLANG_NODE $COMMAND" +} + # display ctl usage usage () { |