Module: sip-router
Branch: master
Commit: ffcf29e66d0e78fed90d25fb70425c8ad002d6c0
URL: http://git.sip-router.org/cgi-bin/gitweb.cgi/sip-router/?a=commit;h=ffcf29e…
Author: Henning Westerholt <henning.westerholt(a)1und1.de>
Committer: Henning Westerholt <henning.westerholt(a)1und1.de>
Date: Thu May 7 15:09:09 2009 +0200
dialog(k): port db setup to different child_init behaviour on sr
- port db setup to different child_init behaviour on sr, here child_init
is called two times for PROC_MAIN
- don't open a DB connection in PROC_MAIN in DB_MODE_DELAYED
- don't close the connection during mod_destroy if nothing was opened
---
modules_k/dialog/dialog.c | 12 ++++++++----
1 files changed, 8 insertions(+), 4 deletions(-)
diff --git a/modules_k/dialog/dialog.c b/modules_k/dialog/dialog.c
index 1e6c5de..caae794 100644
--- a/modules_k/dialog/dialog.c
+++ b/modules_k/dialog/dialog.c
@@ -570,10 +570,9 @@ static int child_init(int rank)
if_update_stat(dlg_enable_stats, early_dlgs, early_dlgs_cnt);
}
- if ( (dlg_db_mode==DB_MODE_REALTIME && (rank>0 || rank==PROC_TIMER)) ||
- (dlg_db_mode==DB_MODE_SHUTDOWN && (rank==PROC_MAIN)) ||
- (dlg_db_mode==DB_MODE_DELAYED && (rank==PROC_MAIN || rank==PROC_TIMER ||
- rank>0) )){
+ if ( ((dlg_db_mode==DB_MODE_REALTIME || DB_MODE_DELAYED) &&
+ (rank>0 || rank==PROC_TIMER)) ||
+ (dlg_db_mode==DB_MODE_SHUTDOWN && (rank==PROC_MAIN)) ) {
if ( dlg_connect_db(&db_url) ) {
LM_ERR("failed to connect to database (rank=%d)\n",rank);
return -1;
@@ -584,6 +583,11 @@ static int child_init(int rank)
* for the rest of the processes will be the same as DB_MODE_NONE */
if (dlg_db_mode==DB_MODE_SHUTDOWN && rank!=PROC_MAIN)
dlg_db_mode = DB_MODE_NONE;
+ /* in DB_MODE_REALTIME and DB_MODE_DELAYED the PROC_MAIN or the ones
+ * with negative rank will have no db connection */
+ if ( (dlg_db_mode==DB_MODE_REALTIME || dlg_db_mode==DB_MODE_DELAYED) &&
+ (rank<0 || rank==PROC_MAIN))
+ dlg_db_mode = DB_MODE_NONE;
return 0;
}
Module: sip-router
Branch: master
Commit: 7c79fc7a29d4a9509f69f7aca55a992c6b4cbff7
URL: http://git.sip-router.org/cgi-bin/gitweb.cgi/sip-router/?a=commit;h=7c79fc7…
Author: Henning Westerholt <henning.westerholt(a)1und1.de>
Committer: Henning Westerholt <henning.westerholt(a)1und1.de>
Date: Thu May 7 15:26:38 2009 +0200
dialog(k): refine change ffcf29e66d, we need to take care only of PROC_MAIN
---
modules_k/dialog/dialog.c | 5 ++---
1 files changed, 2 insertions(+), 3 deletions(-)
diff --git a/modules_k/dialog/dialog.c b/modules_k/dialog/dialog.c
index caae794..7a5d198 100644
--- a/modules_k/dialog/dialog.c
+++ b/modules_k/dialog/dialog.c
@@ -583,10 +583,9 @@ static int child_init(int rank)
* for the rest of the processes will be the same as DB_MODE_NONE */
if (dlg_db_mode==DB_MODE_SHUTDOWN && rank!=PROC_MAIN)
dlg_db_mode = DB_MODE_NONE;
- /* in DB_MODE_REALTIME and DB_MODE_DELAYED the PROC_MAIN or the ones
- * with negative rank will have no db connection */
+ /* in DB_MODE_REALTIME and DB_MODE_DELAYED the PROC_MAIN have no DB handle */
if ( (dlg_db_mode==DB_MODE_REALTIME || dlg_db_mode==DB_MODE_DELAYED) &&
- (rank<0 || rank==PROC_MAIN))
+ rank==PROC_MAIN)
dlg_db_mode = DB_MODE_NONE;
return 0;
Module: sip-router
Branch: ser_core_cvs
Commit: e11d7294437cee6544fb04c2394a6f31be09c4b2
URL: http://git.sip-router.org/cgi-bin/gitweb.cgi/sip-router/?a=commit;h=e11d729…
Author: Andrei Pelinescu-Onciul <andrei(a)iptel.org>
Committer: Andrei Pelinescu-Onciul <andrei(a)iptel.org>
Date: Thu Apr 30 16:39:10 2009 +0000
sctp: internal macro/hooks for sctp events
Added macros for sctp events (for now empty, or defined to simple
example DBG()):
SCTP_EV_ASSOC_CHANGE
SCTP_EV_PEER_ADDR_CHANGE
SCTP_EV_REMOTE_ERROR
SCTP_EV_SEND_FAILED
SCTP_EV_SHUTDOWN_EVENT
SCTP_EV_SENDER_DRY_EVENT
---
sctp_ev.h | 97 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
sctp_server.c | 14 ++++++++
2 files changed, 111 insertions(+), 0 deletions(-)
diff --git a/sctp_ev.h b/sctp_ev.h
new file mode 100644
index 0000000..f801023
--- /dev/null
+++ b/sctp_ev.h
@@ -0,0 +1,97 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2009 iptelorg GmbH
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/*
+ * sctp_ev.h - sctp events
+ */
+/*
+ * History:
+ * --------
+ * 2009-04-28 initial version (andrei)
+*/
+
+#ifndef __sctp_ev_h
+#define __sctp_ev_h
+
+#include <errno.h>
+#include <string.h>
+
+#ifndef USE_SCTP_EV
+
+#define SCTP_EV_ASSOC_CHANGE(lip, lport, src, reason, state)
+#define SCTP_EV_PEER_ADDR_CHANGE(lip, lport, src, reason, state, addr_su)
+#define SCTP_EV_REMOTE_ERROR(lip, lport, src, err)
+#define SCTP_EV_SEND_FAILED(lip, lport, src, err)
+#define SCTP_EV_SHUTDOWN_EVENT(lip, lport, src)
+#define SCTP_EV_SENDER_DRY_EVENT(lip, lport, src)
+
+#else /* USE_SCTP_EV */
+
+#include "ip_addr.h"
+
+
+/** an association has either been opened or closed.
+ * called for each SCTP_ASSOC_CHANGE event.
+ *
+ * @param err - if 0 it should be ignored (no corresp. libc error), if non-0
+ * it will contain the errno.
+ * @param lip - pointer to an ip_addr containing the local ip
+ * or 0 if dynamic (WARNING can be 0).
+ * @param lport - pointer to an ip_addr containing the local port or 0
+ * if unknown/dynamic.
+ * @param src - pointer to a sockaddr_union containing the src.
+ * @param proto - protocol used
+ */
+#define SCTP_EV_ASSOC_CHANGE(lip, lport, src, reason, state) \
+ DBG("SCTP_ASSOC_CHANGE from %s on %s:%d: %s\n", \
+ su2a(src, sizeof(*(src))), ip_addr2a(lip), lport, reason)
+
+/** an address part of an assoc. changed state.
+ * called for the SCTP_PEER_ADDR_CHANGE event.*/
+#define SCTP_EV_PEER_ADDR_CHANGE(lip, lport, src, reason, state, addr_su) \
+ DBG("SCTP_PEER_ADDR_CHANGE from %s on %s:%d: %s\n", \
+ su2a(src, sizeof(*(src))), ip_addr2a(lip), lport, reason)
+
+/** remote operation error from the peer.
+ * called for the SCTP_REMOTE_ERROR event.*/
+#define SCTP_EV_REMOTE_ERROR(lip, lport, src, err) \
+ DBG("SCTP_REMOTE_ERROR from %s on %s:%d: %d\n", \
+ su2a(src, sizeof(*(src))), ip_addr2a(lip), lport, err)
+
+/** send failed.
+ * called for the SCTP_SEND_FAILED event.*/
+#define SCTP_EV_SEND_FAILED(lip, lport, src, err) \
+ DBG("SCTP_SEND_FAILED from %s on %s:%d: %d\n", \
+ su2a(src, sizeof(*(src))), ip_addr2a(lip), lport, err)
+
+/** the peer has sent a shutdown.
+ * called for the SCTP_SHUTDOWN_EVENT event.*/
+#define SCTP_EV_SHUTDOWN_EVENT(lip, lport, src) \
+ DBG("SCTP_SHUTDOWN_EVENT from %s on %s:%d\n", \
+ su2a(src, sizeof(*(src))), ip_addr2a(lip), lport)
+
+/** kernel has finished sending all the queued data.
+ * called for the SCTP_SENDER_DRY_EVENT event.*/
+#define SCTP_EV_SENDER_DRY_EVENT(lip, lport, src) \
+ DBG("SCTP_SENDER_DRY_EVENT from %s on %s:%d\n", \
+ su2a(src, sizeof(*(src))), ip_addr2a(lip), lport)
+
+#endif /* USE_SCTP_EV */
+
+#endif /*__sctp_ev_h*/
+
+/* vi: set ts=4 sw=4 tw=79:ai:cindent: */
diff --git a/sctp_server.c b/sctp_server.c
index b4aed18..077947d 100644
--- a/sctp_server.c
+++ b/sctp_server.c
@@ -59,6 +59,7 @@
#include "error.h"
#include "timer.h"
#include "sctp_stats.h"
+#include "sctp_ev.h"
@@ -1793,6 +1794,8 @@ static int sctp_handle_notification(struct socket_info* si,
case SCTP_REMOTE_ERROR:
ERR_LEN_TOO_SMALL(len, sizeof(struct sctp_remote_error), si, su,
"SCTP_REMOTE_ERROR");
+ SCTP_EV_REMOTE_ERROR(&si->address, si->port_no, su,
+ ntohs(snp->sn_remote_error.sre_error) );
SNOT("sctp notification from %s on %.*s:%d: SCTP_REMOTE_ERROR:"
" %d, len %d\n, assoc_id %d",
su2a(su, sizeof(*su)), si->name.len, si->name.s,
@@ -1805,6 +1808,8 @@ static int sctp_handle_notification(struct socket_info* si,
case SCTP_SEND_FAILED:
ERR_LEN_TOO_SMALL(len, sizeof(struct sctp_send_failed), si, su,
"SCTP_SEND_FAILED");
+ SCTP_EV_SEND_FAILED(&si->address, si->port_no, su,
+ snp->sn_send_failed.ssf_error);
SNOT("sctp notification from %s on %.*s:%d: SCTP_SEND_FAILED:"
" error %d, assoc_id %d, flags %x\n",
su2a(su, sizeof(*su)), si->name.len, si->name.s,
@@ -1816,6 +1821,10 @@ static int sctp_handle_notification(struct socket_info* si,
case SCTP_PEER_ADDR_CHANGE:
ERR_LEN_TOO_SMALL(len, sizeof(struct sctp_paddr_change), si, su,
"SCTP_PEER_ADDR_CHANGE");
+ SCTP_EV_PEER_ADDR_CHANGE(&si->address, si->port_no, su,
+ sctp_paddr_change_state2s(snp->sn_paddr_change.spc_state),
+ snp->sn_paddr_change.spc_state,
+ &snp->sn_paddr_change.spc_aaddr);
strcpy(su_buf, su2a((union sockaddr_union*)
&snp->sn_paddr_change.spc_aaddr,
sizeof(snp->sn_paddr_change.spc_aaddr)));
@@ -1831,6 +1840,7 @@ static int sctp_handle_notification(struct socket_info* si,
SCTP_STATS_REMOTE_SHUTDOWN();
ERR_LEN_TOO_SMALL(len, sizeof(struct sctp_shutdown_event), si, su,
"SCTP_SHUTDOWN_EVENT");
+ SCTP_EV_SHUTDOWN_EVENT(&si->address, si->port_no, su);
SNOT("sctp notification from %s on %.*s:%d: SCTP_SHUTDOWN_EVENT:"
" assoc_id %d\n",
su2a(su, sizeof(*su)), si->name.len, si->name.s,
@@ -1839,6 +1849,9 @@ static int sctp_handle_notification(struct socket_info* si,
case SCTP_ASSOC_CHANGE:
ERR_LEN_TOO_SMALL(len, sizeof(struct sctp_assoc_change), si, su,
"SCTP_ASSOC_CHANGE");
+ SCTP_EV_ASSOC_CHANGE(&si->address, si->port_no, su,
+ sctp_assoc_change_state2s(snp->sn_assoc_change.sac_state),
+ snp->sn_assoc_change.sac_state);
SNOT("sctp notification from %s on %.*s:%d: SCTP_ASSOC_CHANGE"
": %s: assoc_id %d, ostreams %d, istreams %d\n",
su2a(su, sizeof(*su)), si->name.len, si->name.s,
@@ -1877,6 +1890,7 @@ static int sctp_handle_notification(struct socket_info* si,
case SCTP_SENDER_DRY_EVENT:
ERR_LEN_TOO_SMALL(len, sizeof(struct sctp_sender_dry_event),
si, su, "SCTP_SENDER_DRY_EVENT");
+ SCTP_EV_REMOTE_ERROR(&si->address, si->port_no, su);
SNOT("sctp notification from %s on %.*s:%d: "
"SCTP_SENDER_DRY_EVENT on %d\n",
su2a(su, sizeof(*su)), si->name.len, si->name.s,
Module: sip-router
Branch: ser_core_cvs
Commit: 7a66235b9f972d735575ebb839f87f2eaa1b0c61
URL: http://git.sip-router.org/cgi-bin/gitweb.cgi/sip-router/?a=commit;h=7a66235…
Author: Andrei Pelinescu-Onciul <andrei(a)iptel.org>
Committer: Andrei Pelinescu-Onciul <andrei(a)iptel.org>
Date: Thu Apr 30 16:38:54 2009 +0000
sctp: internal macro-hooks for stats
Added macros for sctp statistics. (for now empty, keeping
more statistics will only involve redefining them):
SCTP_STATS_ESTABLISHED() - new association is opened successfully
SCTP_STATS_CONNECT_FAILED() - attempt to open new assoc. failed
SCTP_STATS_LOCAL_REJECT() - local reject of a "connect" attempt
(unused for now)
SCTP_STATS_REMOTE_SHUTDOWN()
SCTP_STATS_COMM_LOST() - error on open association
SCTP_STATS_SENDQ_FULL() - send failed due to full buffers (kernel)
SCTP_STATS_SEND_FAILED() - send failed for some other reason
SCTP_STATS_SEND_FORCE_RETRY() - send failed and retried
(sctp_send_retries!=0)
---
sctp_server.c | 14 ++++++++
sctp_stats.h | 99 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 113 insertions(+), 0 deletions(-)
diff --git a/sctp_server.c b/sctp_server.c
index ff2e778..b4aed18 100644
--- a/sctp_server.c
+++ b/sctp_server.c
@@ -23,6 +23,7 @@
* --------
* 2008-08-07 initial version (andrei)
* 2009-02-27 blacklist support (andrei)
+ * 2009-04-28 sctp stats & events macros (andrei)
*/
#ifdef USE_SCTP
@@ -57,6 +58,7 @@
#include "clist.h"
#include "error.h"
#include "timer.h"
+#include "sctp_stats.h"
@@ -1496,6 +1498,10 @@ int init_sctp()
int ret;
ret=0;
+ if (INIT_SCTP_STATS()!=0){
+ ERR("sctp init: failed to intialize sctp stats\n");
+ goto error;
+ }
/* sctp options must be initialized before calling this function */
sctp_conn_no=shm_malloc(sizeof(*sctp_conn_tracked));
if ( sctp_conn_no==0){
@@ -1522,6 +1528,7 @@ void destroy_sctp()
#ifdef SCTP_CONN_REUSE
destroy_sctp_con_tracking();
#endif
+ DESTROY_SCTP_STATS();
}
@@ -1613,6 +1620,7 @@ static int sctp_handle_send_failed(struct socket_info* si,
int ret;
ret=-1;
+ SCTP_STATS_SEND_FAILED();
snp=(union sctp_notification*) buf;
retries=snp->sn_send_failed.ssf_info.sinfo_context;
@@ -1623,6 +1631,7 @@ static int sctp_handle_send_failed(struct socket_info* si,
*/
if (retries && (snp->sn_send_failed.ssf_error==0)) {
DBG("sctp: RETRY-ing (%d)\n", retries);
+ SCTP_STATS_SEND_FORCE_RETRY();
retries--;
data=(char*)snp->sn_send_failed.ssf_data;
data_len=snp->sn_send_failed.ssf_length -
@@ -1685,6 +1694,7 @@ static int sctp_handle_assoc_change(struct socket_info* si,
ret=-1;
switch(state){
case SCTP_COMM_UP:
+ SCTP_STATS_ESTABLISHED();
atomic_inc(sctp_conn_no);
#ifdef SCTP_CONN_REUSE
/* new connection, track it */
@@ -1707,6 +1717,7 @@ again:
#endif /* SCTP_CONN_REUSE */
break;
case SCTP_COMM_LOST:
+ SCTP_STATS_COMM_LOST();
#ifdef USE_DST_BLACKLIST
/* blacklist only if send_retries is turned off (if on we don't
know here if we did retry or we are at the first error) */
@@ -1732,6 +1743,7 @@ again:
/* do nothing on restart */
break;
case SCTP_CANT_STR_ASSOC:
+ SCTP_STATS_CONNECT_FAILED();
/* do nothing when failing to start an assoc
(in this case we never see SCTP_COMM_UP so we never
track the assoc) */
@@ -1816,6 +1828,7 @@ static int sctp_handle_notification(struct socket_info* si,
);
break;
case SCTP_SHUTDOWN_EVENT:
+ SCTP_STATS_REMOTE_SHUTDOWN();
ERR_LEN_TOO_SMALL(len, sizeof(struct sctp_shutdown_event), si, su,
"SCTP_SHUTDOWN_EVENT");
SNOT("sctp notification from %s on %.*s:%d: SCTP_SHUTDOWN_EVENT:"
@@ -2162,6 +2175,7 @@ again:
"one possible reason is the server is bound to localhost and\n"
"attempts to send to the net\n");
}else if (errno==EAGAIN || errno==EWOULDBLOCK){
+ SCTP_STATS_SENDQ_FULL();
LOG(L_ERR, "ERROR: sctp_msg_send: failed to send, send buffers"
" full\n");
}
diff --git a/sctp_stats.h b/sctp_stats.h
new file mode 100644
index 0000000..e895ce8
--- /dev/null
+++ b/sctp_stats.h
@@ -0,0 +1,99 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2009 iptelorg GmbH
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/*
+ * sctp_stats.h - sctp statistics macros
+ */
+/*
+ * History:
+ * --------
+ * 2009-04-28 initial version (andrei)
+*/
+
+#ifndef __sctp_stats_h
+#define __sctp_stats_h
+
+
+#ifndef USE_SCTP_STATS
+
+#define INIT_SCTP_STATS() 0 /* success */
+#define DESTROY_SCTP_STATS()
+
+#define SCTP_STATS_ESTABLISHED()
+#define SCTP_STATS_CONNECT_FAILED()
+#define SCTP_STATS_LOCAL_REJECT()
+#define SCTP_STATS_REMOTE_SHUTDOWN()
+#define SCTP_STATS_COMM_LOST()
+#define SCTP_STATS_SENDQ_FULL()
+#define SCTP_STATS_SEND_FAILED()
+#define SCTP_STATS_SEND_FORCE_RETRY()
+
+#else /* USE_SCTP_STATS */
+
+#define INIT_SCTP_STATS() 0 /* success */
+
+#define DESTROY_SCTP_STATS()
+
+
+/** called each time a new sctp assoc. is established.
+ * sctp notification: SCTP_COMM_UP.
+ */
+#define SCTP_STATS_ESTABLISHED()
+
+/** called each time a new outgoing connection/assoc open fails.
+ * sctp notification: SCTP_CANT_STR_ASSOC
+ */
+#define SCTP_STATS_CONNECT_FAILED()
+
+/** called each time a new incoming connection is rejected. */
+#define SCTP_STATS_LOCAL_REJECT()
+
+
+/** called each time a connection is closed by the peer.
+ * sctp notification: SCTP_SHUTDOWN_EVENT
+ */
+#define SCTP_STATS_REMOTE_SHUTDOWN()
+
+
+/** called each time an established connection is closed due to some error.
+ * sctp notification: SCTP_COMM_LOST
+ */
+#define SCTP_STATS_COMM_LOST()
+
+
+/** called each time a send fails due to the buffering capacity being exceeded.
+ * (send fails due to full kernel buffers)
+ */
+#define SCTP_STATS_SENDQ_FULL()
+
+
+/** called each time a send fails.
+ * (send fails for any reason except buffers full)
+ * sctp notification: SCTP_SEND_FAILED
+ */
+#define SCTP_STATS_SEND_FAILED()
+
+/** called each time a failed send is force-retried.
+ * (possible only if sctp_send_retries is != 0)
+ */
+#define SCTP_STATS_SEND_FORCE_RETRY()
+
+#endif /* USE_SCTP_STATS */
+
+#endif /*__sctp_stats_h*/
+
+/* vi: set ts=4 sw=4 tw=79:ai:cindent: */
Hi,
i've tried to run some of my tests written for kamailio on kamailio-3.0 in
order to check if the modules can be load. With test/2.cfg i've run into this
error:
BUG: <core> [pt.c:283]: ERROR: fork_process(): Process limit of 36 exceeded.
Will simulate fork fail.
Is this something critical? Why is there a limit on the process number and how
can i extend this?
Thanks,
Henning
On Sonntag, 3. Mai 2009, Daniel-Constantin Mierla wrote:
> 1. Admin Guide
>
> - 1.1. Overview
> - 1.2. Dependencies
> [..]
> + 1. Overview
> + 2. Dependencies
(sent again because of some spelling errors in the first mail :-))
Hi Jan,
i noticed that the READMEs generated for modules_k looks now a bit different
then the ones generated for the modules_s. The k ones uses "1.", the s ones
"1.1", for the first chapter for example. Another thing that is missing in the
modules_s READMEs, is the list of the examples. Is this a bug or do you wanted
to change this?
Cheers,
Henning