diff options
-rw-r--r-- | src/transport/gnunet-service-transport.c | 340 | ||||
-rwxr-xr-x | src/transport/test_transport_api_wlan | 148 | ||||
-rw-r--r-- | src/transport/test_transport_ats.conf | 11 |
3 files changed, 181 insertions, 318 deletions
diff --git a/src/transport/gnunet-service-transport.c b/src/transport/gnunet-service-transport.c index 90f491c094..62238fd63a 100644 --- a/src/transport/gnunet-service-transport.c +++ b/src/transport/gnunet-service-transport.c @@ -188,7 +188,7 @@ struct ForeignAddressList */ struct Session *session; - struct ATS_ressource_cost * ressources; + struct ATS_ressource_entry * ressources; /** * What was the last latency observed for this address, plugin and peer? @@ -837,32 +837,126 @@ struct CheckHelloValidatedContext unsigned int ve_count; }; -struct ATS_ressource_cost +struct ATS_quality_metric { int index; - int atsi_index; - struct ATS_ressource_cost * prev; - struct ATS_ressource_cost * next; - double c_1; + int atis_index; + char * name; }; -struct ATS_plugin +struct ATS_mechanism { - struct ATS_plugin * prev; - struct ATS_plugin * next; - char * short_name; - struct ATS_ressource_cost * head; - struct ATS_ressource_cost * tail; + struct ATS_mechanism * prev; + struct ATS_mechanism * next; + struct ForeignAddressList * addr; + struct TransportPlugin * plugin; + struct ATS_peer * peer; + int col_index; + int id; + struct ATS_ressource_cost * rc; }; -struct ATS_quality_metric +struct ATS_peer +{ + int id; + struct GNUNET_PeerIdentity peer; + struct NeighbourList * n; + struct ATS_mechanism * m_head; + struct ATS_mechanism * m_tail; + + /* preference value f */ + double f; + int t; +}; + +struct ATS_result +{ + int c_mechs; + int c_peers; + int solution; +}; + +struct ATS_ressource_entry { + /* index in ressources array */ int index; + /* depending ATSi parameter to calculcate limits */ int atis_index; - char * name; + /* lower bound */ + double c; }; +struct ATS_ressource +{ + /* index in ressources array */ + int index; + /* depending ATSi parameter to calculcate limits */ + int atis_index; + /* cfg option to load limits */ + char * cfg_param; + /* lower bound */ + double c_min; + /* upper bound */ + double c_max; + + /* cofficients for the specific plugins */ + double c_unix; + double c_tcp; + double c_udp; + double c_http; + double c_https; + double c_wlan; + double c_default; +}; + +static struct ATS_ressource ressources[] = +{ + /* FIXME: the coefficients for the specific plugins */ + {1, 7, "LAN_BW_LIMIT", 0, VERY_BIG_DOUBLE_VALUE, 0, 1, 1, 2, 2, 1, 3}, + {2, 7, "WAN_BW_LIMIT", 0, VERY_BIG_DOUBLE_VALUE, 0, 1, 1, 2, 2, 2, 3}, + {3, 4, "WLAN_ENERGY_LIMIT", 0, VERY_BIG_DOUBLE_VALUE, 0, 0, 0, 0, 0, 2, 1} +/* + {4, 4, "COST_ENERGY_CONSUMPTION", VERY_BIG_DOUBLE_VALUE}, + {5, 5, "COST_CONNECT", VERY_BIG_DOUBLE_VALUE}, + {6, 6, "COST_BANDWITH_AVAILABLE", VERY_BIG_DOUBLE_VALUE}, + {7, 7, "COST_NETWORK_OVERHEAD", VERY_BIG_DOUBLE_VALUE},*/ +}; + +static int available_ressources = 3; + + + +struct ATS_info +{ + + /** + * Time of last execution + */ + struct GNUNET_TIME_Absolute last; + /** + * Minimum intervall between two executions + */ + struct GNUNET_TIME_Relative min_delta; + /** + * Regular intervall when execution is triggered + */ + struct GNUNET_TIME_Relative exec_intervall; + /** + * Maximum execution time per calculation + */ + struct GNUNET_TIME_Relative max_exec_duration; + /** + * Maximum number of LP iterations per calculation + */ + int max_iterations; + + GNUNET_SCHEDULER_TaskIdentifier ats_task; + + struct ATS_plugin * head; + struct ATS_plugin * tail; +}; + /** * Our HELLO message. @@ -2464,6 +2558,7 @@ add_peer_address (struct NeighbourList *neighbour, { struct ReadyList *head; struct ForeignAddressList *ret; + int c; ret = find_peer_address (neighbour, tname, session, addr, addrlen); if (ret != NULL) @@ -2489,7 +2584,53 @@ add_peer_address (struct NeighbourList *neighbour, { ret->addr = NULL; } - ret->ressources = NULL; + + ret->ressources = GNUNET_malloc(available_ressources * sizeof (struct ATS_ressource_entry)); + int plugin; + for (c=0; c<available_ressources; c++) + { + struct ATS_ressource_entry *r = ret->ressources; + r[c].index = c; + r[c].atis_index = ressources[c].atis_index; + if (0 == strcmp(neighbour->plugins->plugin->short_name,"unix")) + { + r[c].c = ressources[c].c_unix; + plugin = 1; + } + else if (0 == strcmp(neighbour->plugins->plugin->short_name,"udp")) + { + r[c].c = ressources[c].c_udp; + plugin = 2; + } + else if (0 == strcmp(neighbour->plugins->plugin->short_name,"tcp")) + { + r[c].c = ressources[c].c_tcp; + plugin = 3; + } + else if (0 == strcmp(neighbour->plugins->plugin->short_name,"http")) + { + r[c].c = ressources[c].c_http; + plugin = 4; + } + else if (0 == strcmp(neighbour->plugins->plugin->short_name,"https")) + { + r[c].c = ressources[c].c_https; + plugin = 5; + } + else if (0 == strcmp(neighbour->plugins->plugin->short_name,"wlan")) + { + r[c].c = ressources[c].c_wlan; + plugin = 6; + } + else + { + plugin = -1; + r[c].c = ressources[c].c_default; + GNUNET_log (GNUNET_ERROR_TYPE_ERROR,"Assigning default cost to peer `%s' addr plugin `%s'! This should not happen!", + GNUNET_i2s(&neighbour->peer), neighbour->plugins->plugin->short_name); + } + } + ret->addrlen = addrlen; ret->expires = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT); @@ -4496,6 +4637,7 @@ disconnect_neighbour (struct NeighbourList *n, int check) GNUNET_SCHEDULER_cancel (peer_pos->revalidate_task); peer_pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK; } + GNUNET_free(peer_pos->ressources); GNUNET_free(peer_pos); } GNUNET_free (rpos); @@ -5510,7 +5652,6 @@ shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) struct TransportPlugin *plug; struct OwnAddressList *al; struct CheckHelloValidatedContext *chvc; - struct ATS_plugin * rc; while (neighbours != NULL) { @@ -5539,16 +5680,6 @@ shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) plug->addresses = al->next; GNUNET_free (al); } - rc = plug->rc; - struct ATS_ressource_cost * t; - while (rc->head != NULL) - { - t = rc->head; - GNUNET_CONTAINER_DLL_remove(rc->head, rc->tail, rc->head); - GNUNET_free(t); - } - - GNUNET_free(plug->rc); GNUNET_free (plug); } if (my_private_key != NULL) @@ -5598,109 +5729,9 @@ shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) GNUNET_break (bc_head == NULL); } -struct ATS_mechanism -{ - struct ATS_mechanism * prev; - struct ATS_mechanism * next; - struct ForeignAddressList * addr; - struct TransportPlugin * plugin; - struct ATS_peer * peer; - int col_index; - int id; - struct ATS_ressource_cost * rc; -}; - -struct ATS_peer -{ - int id; - struct GNUNET_PeerIdentity peer; - struct NeighbourList * n; - struct ATS_mechanism * m_head; - struct ATS_mechanism * m_tail; - - /* preference value f */ - double f; - int t; -}; - -struct ATS_result -{ - int c_mechs; - int c_peers; - int solution; -}; - -struct ATS_ressource -{ - /* index in ressources array */ - int index; - /* depending ATSi parameter to calculcate limits */ - int atis_index; - /* cfg option to load limits */ - char * cfg_param; - /* lower bound */ - double c_min; - /* upper bound */ - double c_max; - - /* cofficients for the specific plugins */ - double c_unix; - double c_tcp; - double c_udp; - double c_http; - double c_https; - double c_wlan; - double c_default; -}; - -static struct ATS_ressource ressources[] = -{ - /* FIXME: the coefficients for the specific plugins */ - {1, 7, "LAN_BW_LIMIT", 0, VERY_BIG_DOUBLE_VALUE, 0, 1, 1, 2, 2, 1, 3}, - {2, 7, "WAN_BW_LIMIT", 0, VERY_BIG_DOUBLE_VALUE, 0, 1, 1, 2, 2, 2, 3}, - {3, 4, "WLAN_ENERGY_LIMIT", VERY_BIG_DOUBLE_VALUE, 0, 0, 0, 0, 0, 2, 1} -/* - {4, 4, "COST_ENERGY_CONSUMPTION", VERY_BIG_DOUBLE_VALUE}, - {5, 5, "COST_CONNECT", VERY_BIG_DOUBLE_VALUE}, - {6, 6, "COST_BANDWITH_AVAILABLE", VERY_BIG_DOUBLE_VALUE}, - {7, 7, "COST_NETWORK_OVERHEAD", VERY_BIG_DOUBLE_VALUE},*/ -}; - -static int available_ressources = 3; - - -struct ATS_info -{ - /** - * Time of last execution - */ - struct GNUNET_TIME_Absolute last; - /** - * Minimum intervall between two executions - */ - struct GNUNET_TIME_Relative min_delta; - /** - * Regular intervall when execution is triggered - */ - struct GNUNET_TIME_Relative exec_intervall; - /** - * Maximum execution time per calculation - */ - struct GNUNET_TIME_Relative max_exec_duration; - /** - * Maximum number of LP iterations per calculation - */ - int max_iterations; - - GNUNET_SCHEDULER_TaskIdentifier ats_task; - - struct ATS_plugin * head; - struct ATS_plugin * tail; -}; - -#define DEBUG_ATS GNUNET_YES +#define DEBUG_ATS GNUNET_NO #define VERBOSE_ATS GNUNET_NO @@ -5731,7 +5762,7 @@ static int ats_solve_problem (int max_it, int max_dur , double D, double U, doub int result; int solution; - int c_c_ressources = 0; + int c_c_ressources = available_ressources; int c_q_metrics = available_quality_metrics; //double M = 10000000000; // ~10 GB @@ -5788,40 +5819,12 @@ static int ats_solve_problem (int max_it, int max_dur , double D, double U, doub struct ForeignAddressList * a_next = r_next->addresses; while (a_next != NULL) { - //struct ATS_ressource_cost *rc; - if (DEBUG_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%i Peer: `%s' plugin `%s' %x:\n", c_mechs, GNUNET_i2s(&next->id), r_next->plugin->short_name, a_next); mechanisms[c_mechs].addr = a_next; mechanisms[c_mechs].col_index = c_mechs; mechanisms[c_mechs].peer = &peers[c_peers]; mechanisms[c_mechs].next = NULL; mechanisms[c_mechs].plugin = r_next->plugin; - mechanisms[c_mechs].rc = GNUNET_malloc (available_ressources * sizeof (struct ATS_ressource_cost)); - - //rc = a_next->ressources; - /* get address specific ressource costs */ - /* - while (rc != NULL) - { - memcpy(&mechanisms[c_mechs].rc[rc->index], rc, sizeof (struct ATS_ressource_cost)); - if (DEBUG_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Set address specific rc %s = %f \n", ressources[rc->index].cfg_param, mechanisms[c_mechs].rc[rc->index].c_1); - c_c_ressources ++; - rc = rc->next; - } - // get plugin specific ressourc costs - - - rc = mechanisms[c_mechs].plugin->rc->head; - while (rc != NULL) - { - if ((mechanisms[c_mechs].rc[rc->index].c_1 == 0) && (rc->c_1 != 0)) - { - memcpy(&mechanisms[c_mechs].rc[rc->index], rc, sizeof (struct ATS_ressource_cost)); - c_c_ressources++; - } - if (DEBUG_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Set plugin specific rc %s = %f \n", ressources[rc->index].cfg_param, mechanisms[c_mechs].rc[rc->index].c_1); - rc = rc->next; - }*/ GNUNET_CONTAINER_DLL_insert_tail(peers[c_peers].m_head, peers[c_peers].m_tail, &mechanisms[c_mechs]); c_mechs++; @@ -5845,7 +5848,7 @@ static int ats_solve_problem (int max_it, int max_dur , double D, double U, doub if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Creating problem with: %i peers, %i mechanisms, %i resource entries, %i quality metrics \n", c_peers, c_mechs, c_c_ressources, c_q_metrics); - int size = 1 + 3 + 10 *c_mechs + c_peers + (c_q_metrics*c_mechs)+ c_q_metrics + c_c_ressources ; + int size = 1 + 3 + 10 *c_mechs + c_peers + (c_q_metrics*c_mechs)+ c_q_metrics + c_c_ressources + 1000; //int size = 1 + 8 *c_mechs +2 + c_mechs + c_peers + (c_q_metrics*c_mechs)+c_q_metrics + c_c_ressources ; int row_index; int array_index=1; @@ -5953,28 +5956,28 @@ static int ats_solve_problem (int max_it, int max_dur , double D, double U, doub if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Constraint 4\n"); glp_add_rows(prob, available_ressources); - //double ct_max = 0.0; - //double ct_1 = 0.0; -/* + double ct_max = VERY_BIG_DOUBLE_VALUE; + double ct_min = 0.0; + for (c=0; c<available_ressources; c++) { ct_max = ressources[c].c_max; - if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] %f\n",row_index, ct_max); - glp_set_row_bnds(prob, row_index, GLP_DB, 0.0, ct_max); + ct_min = ressources[c].c_min; + if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] %f..%f\n",row_index, ct_min, ct_max); + glp_set_row_bnds(prob, row_index, GLP_DB, ct_min, ct_max); for (c2=1; c2<=c_mechs; c2++) { - if (mechanisms[c2].rc[c].c_1 != 0) - { + double value = 0; ia[array_index] = row_index; - ja[array_index] = mechanisms[c2].col_index; - ar[array_index] = mechanisms[c2].rc[c].c_1; + ja[array_index] = c2; + value = mechanisms[c2].addr->ressources[c].c; + ar[array_index] = value; if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]); array_index++; - } } row_index ++; - }*/ + } /* Constraint 5: min number of connections*/ if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Constraint 5\n"); @@ -6311,6 +6314,7 @@ void ats_calculate_bandwidth_distribution () start = GNUNET_TIME_absolute_get(); c_mechs = ats_solve_problem(5000, 5000, 1.0, 1.0, 1.0, 1000, 5, &result); duration = GNUNET_TIME_absolute_get_difference(start,GNUNET_TIME_absolute_get()); + if (c_mechs > 0) { if (DEBUG_ATS) {GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "MLP execution time in [ms] for %i mechanisms: %llu\n", c_mechs, duration.rel_value);} diff --git a/src/transport/test_transport_api_wlan b/src/transport/test_transport_api_wlan deleted file mode 100755 index e5aab67e85..0000000000 --- a/src/transport/test_transport_api_wlan +++ /dev/null @@ -1,148 +0,0 @@ -#! /bin/bash - -# test_transport_api_wlan - temporary wrapper script for .libs/test_transport_api_wlan -# Generated by ltmain.sh (GNU libtool) 2.2.6b Debian-2.2.6b-2 -# -# The test_transport_api_wlan program cannot be directly executed until all the libtool -# libraries that it depends on are installed. -# -# This wrapper script should never be moved out of the build directory. -# If it is, it will not operate correctly. - -# Sed substitution that helps us do robust quoting. It backslashifies -# metacharacters that are still active within double-quoted strings. -Xsed='/bin/sed -e 1s/^X//' -sed_quote_subst='s/\([`"$\\]\)/\\\1/g' - -# Be Bourne compatible -if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then - emulate sh - NULLCMD=: - # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which - # is contrary to our usage. Disable this feature. - alias -g '${1+"$@"}'='"$@"' - setopt NO_GLOB_SUBST -else - case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac -fi -BIN_SH=xpg4; export BIN_SH # for Tru64 -DUALCASE=1; export DUALCASE # for MKS sh - -# The HP-UX ksh and POSIX shell print the target directory to stdout -# if CDPATH is set. -(unset CDPATH) >/dev/null 2>&1 && unset CDPATH - -relink_command="(cd /home/grothoff/svn/gnunet/src/transport; { test -z \"\${LIBRARY_PATH+set}\" || unset LIBRARY_PATH || { LIBRARY_PATH=; export LIBRARY_PATH; }; }; { test -z \"\${COMPILER_PATH+set}\" || unset COMPILER_PATH || { COMPILER_PATH=; export COMPILER_PATH; }; }; { test -z \"\${GCC_EXEC_PREFIX+set}\" || unset GCC_EXEC_PREFIX || { GCC_EXEC_PREFIX=; export GCC_EXEC_PREFIX; }; }; { test -z \"\${LD_RUN_PATH+set}\" || unset LD_RUN_PATH || { LD_RUN_PATH=; export LD_RUN_PATH; }; }; LD_LIBRARY_PATH=/home/grothoff/lib; export LD_LIBRARY_PATH; PATH=/opt/jdk1.6.0_22/bin/:/home/grothoff/gn9/bin:/home/grothoff/bin/:/usr/local/bin:/usr/bin:/bin:/usr/games; export PATH; gcc -fno-strict-aliasing -Wall -g -O0 -Wall -Werror -o \$progdir/\$file test_transport_api.o -L/home/grothoff/gn9//lib ../../src/transport/.libs/libgnunettransport.so ../../src/hello/.libs/libgnunethello.so ../../src/util/.libs/libgnunetutil.so -ldl -Wl,-rpath -Wl,/home/grothoff/svn/gnunet/src/transport/.libs -Wl,-rpath -Wl,/home/grothoff/svn/gnunet/src/hello/.libs -Wl,-rpath -Wl,/home/grothoff/svn/gnunet/src/util/.libs -Wl,-rpath -Wl,/home/grothoff/gn9/lib)" - -# This environment variable determines our operation mode. -if test "$libtool_install_magic" = "%%%MAGIC variable%%%"; then - # install mode needs the following variables: - generated_by_libtool_version='2.2.6b' - notinst_deplibs=' ../../src/transport/libgnunettransport.la ../../src/hello/libgnunethello.la ../../src/util/libgnunetutil.la' -else - # When we are sourced in execute mode, $file and $ECHO are already set. - if test "$libtool_execute_magic" != "%%%MAGIC variable%%%"; then - ECHO="echo" - file="$0" - # Make sure echo works. - if test "X$1" = X--no-reexec; then - # Discard the --no-reexec flag, and continue. - shift - elif test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t'; then - # Yippee, $ECHO works! - : - else - # Restart under the correct shell, and then maybe $ECHO will work. - exec /bin/bash "$0" --no-reexec ${1+"$@"} - fi - fi - - # Find the directory that this script lives in. - thisdir=`$ECHO "X$file" | $Xsed -e 's%/[^/]*$%%'` - test "x$thisdir" = "x$file" && thisdir=. - - # Follow symbolic links until we get to the real thisdir. - file=`ls -ld "$file" | /bin/sed -n 's/.*-> //p'` - while test -n "$file"; do - destdir=`$ECHO "X$file" | $Xsed -e 's%/[^/]*$%%'` - - # If there was a directory component, then change thisdir. - if test "x$destdir" != "x$file"; then - case "$destdir" in - [\\/]* | [A-Za-z]:[\\/]*) thisdir="$destdir" ;; - *) thisdir="$thisdir/$destdir" ;; - esac - fi - - file=`$ECHO "X$file" | $Xsed -e 's%^.*/%%'` - file=`ls -ld "$thisdir/$file" | /bin/sed -n 's/.*-> //p'` - done - - - # Usually 'no', except on cygwin/mingw when embedded into - # the cwrapper. - WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=no - if test "$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR" = "yes"; then - # special case for '.' - if test "$thisdir" = "."; then - thisdir=`pwd` - fi - # remove .libs from thisdir - case "$thisdir" in - *[\\/].libs ) thisdir=`$ECHO "X$thisdir" | $Xsed -e 's%[\\/][^\\/]*$%%'` ;; - .libs ) thisdir=. ;; - esac - fi - - # Try to get the absolute directory name. - absdir=`cd "$thisdir" && pwd` - test -n "$absdir" && thisdir="$absdir" - - program=lt-'test_transport_api_wlan' - progdir="$thisdir/.libs" - - if test ! -f "$progdir/$program" || - { file=`ls -1dt "$progdir/$program" "$progdir/../$program" 2>/dev/null | /bin/sed 1q`; \ - test "X$file" != "X$progdir/$program"; }; then - - file="$$-$program" - - if test ! -d "$progdir"; then - mkdir "$progdir" - else - rm -f "$progdir/$file" - fi - - # relink executable if necessary - if test -n "$relink_command"; then - if relink_command_output=`eval $relink_command 2>&1`; then : - else - echo "$relink_command_output" >&2 - rm -f "$progdir/$file" - exit 1 - fi - fi - - mv -f "$progdir/$file" "$progdir/$program" 2>/dev/null || - { rm -f "$progdir/$program"; - mv -f "$progdir/$file" "$progdir/$program"; } - rm -f "$progdir/$file" - fi - - if test -f "$progdir/$program"; then - if test "$libtool_execute_magic" != "%%%MAGIC variable%%%"; then - # Run the actual program with our arguments. - - exec "$progdir/$program" ${1+"$@"} - - $ECHO "$0: cannot exec $program $*" 1>&2 - exit 1 - fi - else - # The program doesn't exist. - $ECHO "$0: error: \`$progdir/$program' does not exist" 1>&2 - $ECHO "This script is just a wrapper for $program." 1>&2 - echo "See the libtool documentation for more information." 1>&2 - exit 1 - fi -fi diff --git a/src/transport/test_transport_ats.conf b/src/transport/test_transport_ats.conf index c58b0ceb94..0a26c0bc3a 100644 --- a/src/transport/test_transport_ats.conf +++ b/src/transport/test_transport_ats.conf @@ -7,10 +7,17 @@ PORT = 2564 [transport] PORT = 2565 -PLUGINS = tcp -#DEBUG = NO +PLUGINS = udp tcp +#DEBUG = YES #PREFIX = xterm -e xterm -T transport -e gdb -x cmd --args #PREFIX = valgrind --tool=memcheck --log-file=logs%p +WAN_BW_LIMIT_DOWN = 100 +WAN_BW_LIMIT_UP = 10000 +LAN_BW_LIMIT_DOWN = 100 +LAN_BW_LIMIT_UP = 50000 +WLAN_ENERGY_DOWN_LIMIT = 0 +WLAN_ENERGY_UP_LIMIT = 30 + [arm] PORT = 2566 |