mldonkey-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Mldonkey-commits] mldonkey config/Makefile.config.in config/Makef...


From: mldonkey-commits
Subject: [Mldonkey-commits] mldonkey config/Makefile.config.in config/Makef...
Date: Mon, 01 Nov 2010 17:19:23 +0000

CVSROOT:        /sources/mldonkey
Module name:    mldonkey
Changes by:     spiralvoice <spiralvoice>       10/11/01 17:19:23

Modified files:
        config         : Makefile.config.in Makefile.in config.h.in 
                         configure.in 
        distrib        : ChangeLog 
        src/daemon/common: commonGlobals.ml commonInteractive.ml 
                           commonOptions.ml 
        src/daemon/driver: driverCommands.ml driverInteractive.ml 
                           driverMain.ml 
        src/utils/lib  : autoconf.ml.new.in 
Added files:
        src/utils/net  : upnpClient.ml upnpClient.mli upnp_stubs.c 

Log message:
        patch #7303

CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/mldonkey/config/Makefile.config.in?cvsroot=mldonkey&r1=1.65&r2=1.66
http://cvs.savannah.gnu.org/viewcvs/mldonkey/config/Makefile.in?cvsroot=mldonkey&r1=1.195&r2=1.196
http://cvs.savannah.gnu.org/viewcvs/mldonkey/config/config.h.in?cvsroot=mldonkey&r1=1.28&r2=1.29
http://cvs.savannah.gnu.org/viewcvs/mldonkey/config/configure.in?cvsroot=mldonkey&r1=1.340&r2=1.341
http://cvs.savannah.gnu.org/viewcvs/mldonkey/distrib/ChangeLog?cvsroot=mldonkey&r1=1.1496&r2=1.1497
http://cvs.savannah.gnu.org/viewcvs/mldonkey/src/daemon/common/commonGlobals.ml?cvsroot=mldonkey&r1=1.92&r2=1.93
http://cvs.savannah.gnu.org/viewcvs/mldonkey/src/daemon/common/commonInteractive.ml?cvsroot=mldonkey&r1=1.108&r2=1.109
http://cvs.savannah.gnu.org/viewcvs/mldonkey/src/daemon/common/commonOptions.ml?cvsroot=mldonkey&r1=1.235&r2=1.236
http://cvs.savannah.gnu.org/viewcvs/mldonkey/src/daemon/driver/driverCommands.ml?cvsroot=mldonkey&r1=1.258&r2=1.259
http://cvs.savannah.gnu.org/viewcvs/mldonkey/src/daemon/driver/driverInteractive.ml?cvsroot=mldonkey&r1=1.142&r2=1.143
http://cvs.savannah.gnu.org/viewcvs/mldonkey/src/daemon/driver/driverMain.ml?cvsroot=mldonkey&r1=1.145&r2=1.146
http://cvs.savannah.gnu.org/viewcvs/mldonkey/src/utils/lib/autoconf.ml.new.in?cvsroot=mldonkey&r1=1.27&r2=1.28
http://cvs.savannah.gnu.org/viewcvs/mldonkey/src/utils/net/upnpClient.ml?cvsroot=mldonkey&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/mldonkey/src/utils/net/upnpClient.mli?cvsroot=mldonkey&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/mldonkey/src/utils/net/upnp_stubs.c?cvsroot=mldonkey&rev=1.1

Patches:
Index: config/Makefile.config.in
===================================================================
RCS file: /sources/mldonkey/mldonkey/config/Makefile.config.in,v
retrieving revision 1.65
retrieving revision 1.66
diff -u -b -r1.65 -r1.66
--- config/Makefile.config.in   29 Aug 2010 20:11:20 -0000      1.65
+++ config/Makefile.config.in   1 Nov 2010 17:19:23 -0000       1.66
@@ -66,6 +66,10 @@
 address@hidden@
 address@hidden@
 
address@hidden@
address@hidden@
address@hidden@
+
 address@hidden@
 address@hidden@
 

Index: config/Makefile.in
===================================================================
RCS file: /sources/mldonkey/mldonkey/config/Makefile.in,v
retrieving revision 1.195
retrieving revision 1.196
diff -u -b -r1.195 -r1.196
--- config/Makefile.in  1 Nov 2010 17:06:15 -0000       1.195
+++ config/Makefile.in  1 Nov 2010 17:19:23 -0000       1.196
@@ -245,6 +245,8 @@
   $(COMMON)/commonHasher_c.c
 
 COMMON_CLIENT_SRCS= \
+  $(NET)/upnpClient.ml \
+  $(NET)/upnp_stubs.c \
   $(COMMON)/commonUser.ml \
   $(COMMON)/commonNetwork.ml \
   $(COMMON)/commonServer.ml \
@@ -555,6 +557,11 @@
     $(DRIVER)/driverGraphics_nogd.ml
 endif
 
+ifeq ("$(UPNP_NATPMP)", "yes")
+  UPNP_NATPMP_LIBS_flags=-cclib "$(UPNP_NATPMP_LIBS)" -ccopt 
"$(UPNP_NATPMP_LDFLAGS)"
+  UPNP_NATPMP_STATIC_LIBS_flags=-cclib "$(UPNP_NATPMP_STATIC_LIBS)" -ccopt 
"$(UPNP_NATPMP_LDFLAGS)"
+endif
+
 DRIVER_SRCS+= \
   $(DRIVER)/driverGraphics.ml  \
   $(DRIVER)/driverInteractive.ml  \
@@ -1222,6 +1229,7 @@
 EXPAND_LIB(libcdk,cdk)
 EXPAND_LIB(libmagic,magic)
 EXPAND_LIB(libbitstring,bitstring)
+EXPAND_LIB(libupnp_natpmp,upnp_natpmp)
 EXPAND_LIB(libcommon,common)
 EXPAND_LIB(libclient,client)
 EXPAND_LIB(DRIVER,driver)
@@ -1268,6 +1276,7 @@
        $($6_LIBS_opt) $($6_LIBS_flags) \
        $($7_LIBS_opt) $($7_LIBS_flags) \
        $($8_LIBS_opt) $($8_LIBS_flags) \
+       $($9_LIBS_opt) $($9_LIBS_flags) \
        -I build $($1_CMXAS) $($1_CMXS) 
  
 $2.byte: $($1_OBJS) $($1_CMOS) $($1_CMAS)
@@ -1278,6 +1287,7 @@
        $($6_LIBS_byte) $($6_LIBS_flags) \
        $($7_LIBS_byte) $($7_LIBS_flags) \
        $($8_LIBS_byte) $($8_LIBS_flags) \
+       $($9_LIBS_byte) $($9_LIBS_flags) \
        -I build $($1_CMAS) $($1_CMOS) 
  
 $2.static: $($1_OBJS) $($1_CMXS) $($1_CMXAS)
@@ -1288,6 +1298,7 @@
        $($6_LIBS_flags) $($6_STATIC_LIBS_opt) \
        $($7_LIBS_flags) $($7_STATIC_LIBS_opt) \
        $($8_LIBS_flags) $($8_STATIC_LIBS_opt) \
+       $($9_LIBS_flags) $($9_STATIC_LIBS_opt) \
        -I build $($1_CMXAS) $($1_CMXS)
 
 $2.byte.static: $($1_OBJS) $($1_CMOS) $($1_CMAS)
@@ -1298,6 +1309,7 @@
        $($6_LIBS_flags) $($6_STATIC_LIBS_opt) \
        $($7_LIBS_flags) $($7_STATIC_LIBS_opt) \
        $($8_LIBS_flags) $($8_STATIC_LIBS_opt) \
+       $($9_LIBS_flags) $($9_STATIC_LIBS_opt) \
        -I build $($1_CMAS) $($1_CMOS) 
 ]])
 
@@ -1309,9 +1321,10 @@
 # $6 = if set link CryptoPP code (only for targets mlnet, mldonkey)
 # $7 = if set link libmagic code (only for p2p core, not for GUIs, tools etc.)
 # $8 = if set link libbitstring code (only for Bittorrent p2p core)
+# $9 = if set link libminiupnpc & libnatpmp code
 
-EXPAND(mldonkey,mldonkey,NO,mldonkey,GD,CRYPTOPP,MAGIC,BITSTRING)
-EXPAND(mldonkey+gui,mldonkey+gui,GTK,mldonkey+gui,GD,CRYPTOPP,MAGIC,BITSTRING)
+EXPAND(mldonkey,mldonkey,NO,mldonkey,GD,CRYPTOPP,MAGIC,BITSTRING,UPNP_NATPMP)
+EXPAND(mldonkey+gui,mldonkey+gui,GTK,mldonkey+gui,GD,CRYPTOPP,MAGIC,BITSTRING,UPNP_NATPMP)
 EXPAND(MLPROGRESS, mlprogress,GTK, MLPROGRESS)
 EXPAND(MLDONKEYGUI,mlgui,GTK,MLDONKEYGUI)
 
@@ -1319,29 +1332,29 @@
  EXPAND(MLDONKEYGUI2,mlgui2,GTK,MLDONKEYGUI2)
 endif
 
-EXPAND(mldc,mldc,NO,mldc,GD,NO,MAGIC)
-EXPAND(mldc+gui,mldc+gui,GTK,mldc+gui,GD,NO,MAGIC)
-EXPAND(mlnap,mlnap,NO,mlnap,GD,NO,MAGIC)
-EXPAND(mlnap+gui,mlnap+gui,GTK,mlnap+gui,GD,NO,MAGIC)
-EXPAND(MLNET,mlnet,NO,MLNET,GD,CRYPTOPP,MAGIC,BITSTRING)
-EXPAND(mlnet+gui,mlnet+gui,GTK,mlnet+gui,GD,CRYPTOPP,MAGIC,BITSTRING)
-EXPAND(mlgnut,mlgnut,NO,mlgnut,GD,NO,MAGIC)
-EXPAND(mlgnut+gui,mlgnut+gui,GTK,mlgnut+gui,GD,NO,MAGIC)
-EXPAND(mlg2,mlg2,NO,mlg2,GD,NO,MAGIC)
-EXPAND(mlg2+gui,mlg2+gui,GTK,mlg2+gui,GD,NO,MAGIC)
-EXPAND(mlbt,mlbt,NO,mlbt,GD,NO,MAGIC,BITSTRING)
-EXPAND(mlbt+gui,mlbt+gui,GTK,mlbt+gui,GD,NO,MAGIC,BITSTRING)
-EXPAND(mlfasttrack,mlfasttrack,NO,mlfasttrack,GD,NO,MAGIC)
-EXPAND(mlfasttrack+gui,mlfasttrack+gui,GTK,mlfasttrack+gui,GD,NO,MAGIC)
-EXPAND(mlfileTP,mlfiletp,NO,mlfileTP,GD,NO,MAGIC)
-EXPAND(mlfileTP+gui,mlfiletp+gui,GTK,mlfileTP+gui,GD,NO,MAGIC)
-EXPAND(mlslsk,mlslsk,NO,mlslsk,GD,NO,MAGIC)
-EXPAND(mlslsk+gui,mlslsk+gui,GTK,mlslsk+gui,GD,NO,MAGIC)
+EXPAND(mldc,mldc,NO,mldc,GD,NO,MAGIC,NO,UPNP_NATPMP)
+EXPAND(mldc+gui,mldc+gui,GTK,mldc+gui,GD,NO,MAGIC,NO,UPNP_NATPMP)
+EXPAND(mlnap,mlnap,NO,mlnap,GD,NO,MAGIC,UPNP_NATPMP)
+EXPAND(mlnap+gui,mlnap+gui,GTK,mlnap+gui,GD,NO,MAGIC,NO,UPNP_NATPMP)
+EXPAND(MLNET,mlnet,NO,MLNET,GD,CRYPTOPP,MAGIC,BITSTRING,UPNP_NATPMP)
+EXPAND(mlnet+gui,mlnet+gui,GTK,mlnet+gui,GD,CRYPTOPP,MAGIC,BITSTRING,UPNP_NATPMP)
+EXPAND(mlgnut,mlgnut,NO,mlgnut,GD,NO,MAGIC,NO,UPNP_NATPMP)
+EXPAND(mlgnut+gui,mlgnut+gui,GTK,mlgnut+gui,GD,NO,MAGIC,NO,UPNP_NATPMP)
+EXPAND(mlg2,mlg2,NO,mlg2,GD,NO,MAGIC,NO,UPNP_NATPMP)
+EXPAND(mlg2+gui,mlg2+gui,GTK,mlg2+gui,GD,NO,MAGIC,NO,UPNP_NATPMP)
+EXPAND(mlbt,mlbt,NO,mlbt,GD,NO,MAGIC,BITSTRING,UPNP_NATPMP)
+EXPAND(mlbt+gui,mlbt+gui,GTK,mlbt+gui,GD,NO,MAGIC,BITSTRING,UPNP_NATPMP)
+EXPAND(mlfasttrack,mlfasttrack,NO,mlfasttrack,GD,NO,MAGIC,NO,UPNP_NATPMP)
+EXPAND(mlfasttrack+gui,mlfasttrack+gui,GTK,mlfasttrack+gui,GD,NO,MAGIC,NO,UPNP_NATPMP)
+EXPAND(mlfileTP,mlfiletp,NO,mlfileTP,GD,NO,MAGIC,NO,UPNP_NATPMP)
+EXPAND(mlfileTP+gui,mlfiletp+gui,GTK,mlfileTP+gui,GD,NO,MAGIC,NO,UPNP_NATPMP)
+EXPAND(mlslsk,mlslsk,NO,mlslsk,GD,NO,MAGIC,NO,UPNP_NATPMP)
+EXPAND(mlslsk+gui,mlslsk+gui,GTK,mlslsk+gui,GD,NO,MAGIC,NO,UPNP_NATPMP)
 EXPAND(STARTER,mlguistarter,GTK)
 EXPAND(OBSERVER,observer)
 EXPAND(MLD_HASH,mld_hash)
 EXPAND(OCAMLPP,ocamlpp)
-EXPAND(MAKE_TORRENT,make_torrent,NO,NO,NO,NO,MAGIC,BITSTRING)
+EXPAND(MAKE_TORRENT,make_torrent,NO,NO,NO,NO,MAGIC,BITSTRING,UPNP_NATPMP)
 EXPAND(SUBCONV,subconv)
 EXPAND(MLSPLIT,mlsplit)
 EXPAND(CONTESTER,contester,CRYPT)

Index: config/config.h.in
===================================================================
RCS file: /sources/mldonkey/mldonkey/config/config.h.in,v
retrieving revision 1.28
retrieving revision 1.29
diff -u -b -r1.28 -r1.29
--- config/config.h.in  17 Oct 2007 18:27:25 -0000      1.28
+++ config/config.h.in  1 Nov 2010 17:19:23 -0000       1.29
@@ -147,3 +147,6 @@
 
 /* Define to 1 if you have strerror_r() */
 #undef HAVE_STRERROR_R
+
+/* Define to 1 if you want to use libminiupnpc + libnatpmp */
+#undef ENABLE_UPNP_NATPMP

Index: config/configure.in
===================================================================
RCS file: /sources/mldonkey/mldonkey/config/configure.in,v
retrieving revision 1.340
retrieving revision 1.341
diff -u -b -r1.340 -r1.341
--- config/configure.in 26 Sep 2010 14:20:30 -0000      1.340
+++ config/configure.in 1 Nov 2010 17:19:23 -0000       1.341
@@ -326,6 +326,8 @@
 MAGIC=yes
 ICONV=yes
 USE_PTHREAD=yes
+UPNP_NATPMP=no
+UPNP_NATPMP_FORCE=no
 
 # **********
 
@@ -411,6 +413,8 @@
 AC_ARG_ENABLE(gd,            [  --disable-gd            disable the use of 
gd], [GD="$enableval"])
 AC_ARG_ENABLE(bzip2,         [  --disable-bzip2         disable the use of 
bzip2], [BZIP2="$enableval"])
 AC_ARG_ENABLE(magic,         [  --disable-magic         disable the use of 
libmagic (GNU file)], [MAGIC="$enableval"])
+AC_ARG_ENABLE(upnp-natpmp,   [  --enable-upnp-natpmp    enable the use of 
libminiupnpc and libnatpmp], [UPNP_NATPMP="$enableval"])
+AC_ARG_ENABLE(force-upnp-natpmp,   [  --enable-force-upnp-natpmp    force 
local compilation of libminiupnpc and libnatpmp], 
[UPNP_NATPMP_FORCE="$enableval"])
 
 if test "$FORCE_MINGW" = "yes"; then
     CC="$CC -mno-cygwin"
@@ -783,6 +787,42 @@
   AC_MSG_NOTICE(bzlib not available)
 fi
 
+if test "$UPNP_NATPMP_FORCE" = "yes"; then
+       UPNP_NATPMP=yes
+       cd $PATCH_DIR
+       $WGET http://miniupnp.tuxfamily.org/files/miniupnpc-1.4.20100609.tar.gz
+       $WGET http://miniupnp.tuxfamily.org/files/libnatpmp-20100202.tar.gz
+       mkdir -p $BUILD_DIR $LOCAL_DIR/usr/bin $LOCAL_DIR/usr/lib 
$LOCAL_DIR/usr/include/miniupnpc
+       cd $BUILD_DIR
+       rm -rf libnatpmp-20100202 miniupnpc-1.4.20100609
+       tar -xzf $PATCH_DIR/miniupnpc-1.4.20100609.tar.gz
+       tar -xzf $PATCH_DIR/libnatpmp-20100202.tar.gz
+       cd $BUILD_DIR/libnatpmp-20100202
+       make all install PREFIX=$LOCAL_DIR
+       cd $BUILD_DIR/miniupnpc-1.4.20100609
+       make all install PREFIX=$LOCAL_DIR
+       cd $CONFIG_DIR
+       rm -rf $BUILD_DIR/libnatpmp-20100202 $BUILD_DIR/miniupnpc-1.4.20100609
+       CPPFLAGS="${CPPFLAGS} -I$LOCAL_DIR/usr/include"
+       LDFLAGS="${LDFLAGS} -L$LOCAL_DIR/usr/lib"
+fi
+
+if test "$UPNP_NATPMP" = "yes"; then
+  echo "----- checking libminiupnpc >= 1.4.20100609 (optional)"
+  
AC_CHECK_HEADERS(miniupnpc/miniupnpc.h,[AC_CHECK_LIB(miniupnpc,upnpDiscover,[UPNP_NATPMP=yes],[UPNP_NATPMP=no])],[UPNP_NATPMP=no])
+fi
+
+if test "$UPNP_NATPMP" = "yes"; then
+  echo "----- checking libnatpmp >= 20100202 (optional)"
+  
AC_CHECK_HEADERS(natpmp.h,[AC_CHECK_LIB(natpmp,initnatpmp,[UPNP_NATPMP=yes],[UPNP_NATPMP=no])],[UPNP_NATPMP=no])
+fi
+
+if test "$UPNP_NATPMP" = "yes"; then
+  AC_DEFINE(ENABLE_UPNP_NATPMP, 1, [Define to 1 if you have libminiupnpc & 
libnatpmp for port forwarding support.])
+  UPNP_NATPMP_LIBS="-lminiupnpc -lnatpmp $LIBS"
+  UPNP_NATPMP_STATIC_LIBS="-lminiupnpc -lnatpmp $LIBS"
+fi
+
 if test "$MAGIC" != "no"; then
   echo "----- checking libmagic (GNU file) (optional)"
   AC_CHECK_HEADERS(magic.h,
@@ -1443,6 +1483,9 @@
 AC_SUBST(BZIP2)
 AC_SUBST(MAGIC)
 AC_SUBST(MAGICLIB)
+AC_SUBST(UPNP_NATPMP)
+AC_SUBST(UPNP_NATPMP_LIBS)
+AC_SUBST(UPNP_NATPMP_STATIC_LIBS)
 BUILD_SYSTEM="`uname -s` `uname -m` `uname -r`"
 AC_SUBST(BUILD_SYSTEM)
 AC_SUBST(GLIBC_VERSION)
@@ -1585,6 +1628,13 @@
   echo "        disabled"
 fi
 
+echo -n " - upnp & natpmp     "
+if test "$UPNP_NATPMP" = "yes"; then
+  echo "enabled"
+else
+  echo "        disabled"
+fi
+
 echo -n " - graphical stats   "
 if test "$GD" = "yes"; then
   echo "enabled"

Index: distrib/ChangeLog
===================================================================
RCS file: /sources/mldonkey/mldonkey/distrib/ChangeLog,v
retrieving revision 1.1496
retrieving revision 1.1497
diff -u -b -r1.1496 -r1.1497
--- distrib/ChangeLog   1 Nov 2010 17:09:28 -0000       1.1496
+++ distrib/ChangeLog   1 Nov 2010 17:19:23 -0000       1.1497
@@ -15,6 +15,10 @@
 =========
 
 2010/11/01
+7303: UPNP support (zzpptt)
+- to compile using pre-installed libs: configure --enable-upnp-natpmp
+- to compile UPNP libs during MLDonkey compile use --enable-force-upnp-natpmp
+- ToDo: MinGW support
 7365: HTML: improve code for sorting tables (ygrek)
 7364: KAD: parse new nodes.dat formats (ygrek)
 

Index: src/daemon/common/commonGlobals.ml
===================================================================
RCS file: /sources/mldonkey/mldonkey/src/daemon/common/commonGlobals.ml,v
retrieving revision 1.92
retrieving revision 1.93
diff -u -b -r1.92 -r1.93
--- src/daemon/common/commonGlobals.ml  23 Oct 2010 18:25:13 -0000      1.92
+++ src/daemon/common/commonGlobals.ml  1 Nov 2010 17:19:23 -0000       1.93
@@ -108,6 +108,8 @@
 in an option, and then change the option accordingly. ?> *)
 let find_other_port = ref false
 
+let upnp_port_forwarding () = !!upnp_port_forwarding && Autoconf.upnp_natpmp
+
 let shorten str limit =
   (* TODO: we should change all strings to utf8 when
      they come into the core instead. *)

Index: src/daemon/common/commonInteractive.ml
===================================================================
RCS file: /sources/mldonkey/mldonkey/src/daemon/common/commonInteractive.ml,v
retrieving revision 1.108
retrieving revision 1.109
diff -u -b -r1.108 -r1.109
--- src/daemon/common/commonInteractive.ml      7 Aug 2010 14:51:15 -0000       
1.108
+++ src/daemon/common/commonInteractive.ml      1 Nov 2010 17:19:23 -0000       
1.109
@@ -503,6 +503,7 @@
       lprintf_nl "Exception in contact_remove: %s" (Printexc2.to_string e)
 
 let clean_exit n =
+  begin
   let can_exit = networks_for_all network_clean_exit in
   if can_exit then exit_properly n
   else 
@@ -512,7 +513,15 @@
         if can_exit || retry_counter > !!shutdown_timeout then
          exit_properly n
        else retry_later (retry_counter + 1)) in
-    retry_later 0
+    retry_later 0;
+
+  if (upnp_port_forwarding ()) then
+    begin
+    if !!clear_upnp_port_at_exit then
+      UpnpClient.remove_all_maps 0 ;
+    UpnpClient.job_stop 3;
+    end;
+  end
 
 let time_of_sec sec =
   let hours = sec / 60 / 60 in

Index: src/daemon/common/commonOptions.ml
===================================================================
RCS file: /sources/mldonkey/mldonkey/src/daemon/common/commonOptions.ml,v
retrieving revision 1.235
retrieving revision 1.236
diff -u -b -r1.235 -r1.236
--- src/daemon/common/commonOptions.ml  23 Oct 2010 18:25:13 -0000      1.235
+++ src/daemon/common/commonOptions.ml  1 Nov 2010 17:19:23 -0000       1.236
@@ -539,6 +539,15 @@
       "exit", "q";
     ]
 
+let upnp_port_forwarding = define_option current_section 
["upnp_port_forwarding"]
+  ~restart: true
+  "upnp port forwarding"
+    bool_option false
+
+let clear_upnp_port_at_exit = define_option current_section 
["clear_upnp_port_at_exit"]
+  "clear all upnp port forwarding before mldonkey exit"
+    bool_option true
+
 let verbosity = define_expert_option current_section ["verbosity"]
   "A space-separated list of keywords. Each keyword triggers
   printing information on the corresponding messages:

Index: src/daemon/driver/driverCommands.ml
===================================================================
RCS file: /sources/mldonkey/mldonkey/src/daemon/driver/driverCommands.ml,v
retrieving revision 1.258
retrieving revision 1.259
diff -u -b -r1.258 -r1.259
--- src/daemon/driver/driverCommands.ml 1 Nov 2010 17:09:28 -0000       1.258
+++ src/daemon/driver/driverCommands.ml 1 Nov 2010 17:19:23 -0000       1.259
@@ -43,6 +43,7 @@
 open CommonUserDb
 open CommonInteractive
 open CommonEvent
+open UpnpClient
 
 open DriverInteractive
 
@@ -2147,6 +2148,12 @@
                        ] @
                        (if Autoconf.filetp = "yes" then [(strings_of_option 
enable_fileTP)] else [])
                        @ [
+                       ] @
+                       (if Autoconf.upnp_natpmp then [(strings_of_option 
upnp_port_forwarding)] else [])
+                       @ [
+                       ] @
+                       (if Autoconf.upnp_natpmp then [(strings_of_option 
clear_upnp_port_at_exit)] else [])
+                       @ [
                        strings_of_option tcpip_packet_size;
                        strings_of_option mtu_packet_size;
                        strings_of_option minimal_packet_size;
@@ -4195,4 +4202,43 @@
         CommonPictures.compute_ocaml_code dir output;
         _s "done"
     ), ":\t\t\tfor debugging only";
+
+    "debug_upnp", Arg_multiple ( fun args o ->
+               match args with
+                       | ["init"] ->  
+                               UpnpClient.init_maps ();
+
+                       | ["add"; intPort; extPort; isTcp; notes ] ->
+                               UpnpClient.maps_add_item 1 (int_of_string 
intPort) (int_of_string extPort) (int_of_string isTcp) notes;
+                               
+                       | ["start"] ->  
+                               UpnpClient.job_start ();
+                               
+                       | ["remove"; intPort; extPort; isTcp; notes] ->
+                               UpnpClient.maps_remove_item 1 (int_of_string 
intPort) (int_of_string extPort) (int_of_string isTcp) notes;
+                               
+                       | ["clear"] ->  
+                               UpnpClient.remove_all_maps 0 ;
+                               
+                       | ["stop"] ->   
+                               UpnpClient.job_stop 0;
+                               
+                       | ["show"] | [] ->
+                               let buf = o.conn_buf in
+                                       let     maps = UpnpClient.maps_get () in
+                                       Printf.bprintf buf "upnp port 
forwarding status:\n";
+                                       List.iter (fun map ->
+                                               let msg = 
UpnpClient.strings_port_map map in
+                                               Printf.bprintf buf "%s\n" msg;
+                                       ) maps;
+                                               
+                       | _ -> ();
+                               ;
+                       _s "done"
+    ), ":\t\t\t\t\t$debugging upnp\n"
+       ^"\t\t\t\t\tfor example: \"add 4662 4662 1 ed_port\" add port 
forwarding intPort extPort isTcp notes\n"
+       ^"\t\t\t\t\t\"remove 4662 4662 1 ed_port\" remove port forwarding 
intPort extPort isTcp notes\n"
+       ^"\t\t\t\t\t\"clear\" clear all port forwarding\n"
+       ^"\t\t\t\t\t\"show\" show all port forwarding info $n";
+               
   ]

Index: src/daemon/driver/driverInteractive.ml
===================================================================
RCS file: /sources/mldonkey/mldonkey/src/daemon/driver/driverInteractive.ml,v
retrieving revision 1.142
retrieving revision 1.143
diff -u -b -r1.142 -r1.143
--- src/daemon/driver/driverInteractive.ml      1 Nov 2010 17:09:28 -0000       
1.142
+++ src/daemon/driver/driverInteractive.ml      1 Nov 2010 17:19:23 -0000       
1.143
@@ -1940,6 +1940,7 @@
        | true, true -> " magic(active)"
        | true, false -> " magic(inactive)"
        | false, _ -> " no-magic") ^
+      (if Autoconf.upnp_natpmp then " upnp natpmp" else " no-upnp no-natpmp") ^
       (if Autoconf.check_bounds then " check-bounds" else " no-check-bounds")
     );
   let list = List.rev !list in

Index: src/daemon/driver/driverMain.ml
===================================================================
RCS file: /sources/mldonkey/mldonkey/src/daemon/driver/driverMain.ml,v
retrieving revision 1.145
retrieving revision 1.146
diff -u -b -r1.145 -r1.146
--- src/daemon/driver/driverMain.ml     23 May 2010 09:12:14 -0000      1.145
+++ src/daemon/driver/driverMain.ml     1 Nov 2010 17:19:23 -0000       1.146
@@ -458,10 +458,31 @@
   lprintf_nl (_b "Check http://www.mldonkey.org for updates");
   networks_iter (fun r -> network_load_complex_options r);
   lprintf_nl (_b "enabling networks: ");
+  if (upnp_port_forwarding ()) then
+    UpnpClient.init_maps ();
+    let add_upnp_port p s=
+      lprintf_nl "using port %d (%s)" p s;
+      if ((upnp_port_forwarding ())) then
+        match String2.split_simplify s ' ' with
+          | [ "client_port" ; tcpudp   ]
+          | [ "overnet_port" ; tcpudp  ]
+          | [ "kademlia_port" ; tcpudp ] ->
+          if (String2.contains tcpudp "TCP") then 
+            begin
+            UpnpClient.maps_add_item 1 p p 1 "" ;
+            lprintf_nl "add upnp port forwarding %d TCP" p;
+            end;
+          if (String2.contains tcpudp "UDP") then
+            begin
+            UpnpClient.maps_add_item 1 p p 0 "" ;
+            lprintf_nl "add upnp port forwarding %d UDP" p;
+            end
+          | _ -> ()
+  in
   networks_iter (fun r ->
       lprintf_nl (_b "---- enabling %s ----") r.network_name;
       network_enable r;
-      List.iter (fun (p,s) -> if p <> 0 then lprintf_nl "using port %d (%s)" p 
s) (network_ports r);
+      List.iter (fun (p,s) -> if p <> 0 then add_upnp_port p s) (network_ports 
r);
 (* are there drawbacks to start recover_temp unconditionally here ? *)
       if !!recover_temp_on_startup then
         network_recover_temp r;
@@ -479,6 +500,8 @@
          end);
   if not !found then lprintf (_b "none");
   lprint_newline ();
+  if (upnp_port_forwarding ()) then
+    UpnpClient.job_start ();
   networks_iter_all (fun n -> network_update_options n);
   CommonOptions.start_running_plugins := true;
   CommonInteractive.force_download_quotas ();

Index: src/utils/lib/autoconf.ml.new.in
===================================================================
RCS file: /sources/mldonkey/mldonkey/src/utils/lib/autoconf.ml.new.in,v
retrieving revision 1.27
retrieving revision 1.28
diff -u -b -r1.27 -r1.28
--- src/utils/lib/autoconf.ml.new.in    17 Jun 2007 02:08:16 -0000      1.27
+++ src/utils/lib/autoconf.ml.new.in    1 Nov 2010 17:19:23 -0000       1.28
@@ -48,3 +48,4 @@
 let bzip2 = "@BZIP2@" = "yes"
 let magic = "@MAGIC@" = "yes"
 let magic_works = ref false
+let upnp_natpmp = "@UPNP_NATPMP@" = "yes"

Index: src/utils/net/upnpClient.ml
===================================================================
RCS file: src/utils/net/upnpClient.ml
diff -N src/utils/net/upnpClient.ml
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ src/utils/net/upnpClient.ml 1 Nov 2010 17:19:23 -0000       1.1
@@ -0,0 +1,67 @@
+(**************************************************************************)
+(*  Copyright (c) 2010 zzz <address@hidden>                             *)
+(*                                                                        *)
+(*  mlupnp, a ocaml wraps of libminiupnpc & libnatpmp for mldonkey        *)
+(*                                                                        *)
+(*  Permission is hereby granted, free of charge, to any person           *)
+(*  obtaining a copy of this software and associated documentation files  *)
+(*  (the "Software"), to deal in the Software without restriction,        *)
+(*  including without limitation the rights to use, copy, modify, merge,  *)
+(*  publish, distribute, sublicense, and/or sell copies of the Software,  *)
+(*  and to permit persons to whom the Software is furnished to do so,     *)
+(*  subject to the following conditions:                                  *)
+(*                                                                        *)
+(*  The above copyright notice and this permission notice shall be        *)
+(*  included in all copies or substantial portions of the Software.       *)
+(*                                                                        *)
+(*  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       *)
+(*  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES       *)
+(*  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND              *)
+(*  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS   *)
+(*  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN    *)
+(*  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN     *)
+(*  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE      *)
+(*  SOFTWARE.                                                             *)
+(**************************************************************************)
+
+(* upnp port map zzz++*)
+type ml_port_map = {
+       mutable enabled : int;
+       mutable intPort : int;
+       mutable extPort : int;
+       mutable isTcp   : int;
+       mutable natpmpStatus : int;
+       mutable upnpStatus : int;
+       mutable notes   : string;
+}
+
+let string_of_map_status status =
+  match status with
+  | 0 -> "ERROR"
+  | 1 -> "UNMAPPED"
+  | 2 -> "UNMAPPING"
+  | 3 -> "MAPPING"
+  | 4 -> "MAPPED"
+       | _ -> "N/A"
+
+let strings_port_map map =
+       Printf.sprintf "enable:%d ,intPort:%d ,extPort:%d ,isTcp:%d 
,natpmpStatus:\"%s\" ,upnpStatus:\"%s\" ,notes:\"%s\""
+       map.enabled map.intPort map.extPort map.isTcp (string_of_map_status 
map.natpmpStatus) (string_of_map_status map.upnpStatus) map.notes
+       
+
+external init_maps : unit -> unit = "ml_upnpInitMaps" "noalloc"
+(*external set_maps  : unit -> unit = "ml_upnpSetMaps" *)
+external dump_maps : unit -> unit = "ml_upnpDumpMaps" "noalloc"
+external job_start : unit -> unit = "ml_upnp_job_start" "noalloc"
+
+(* job_stop max_wait_seconds, 0=system default wait seconds *)
+external job_stop  : int -> unit = "ml_upnp_job_stop"
+
+external maps_add_item     : int -> int -> int -> int -> string -> unit  = 
"ml_upnpAddMap" 
+external maps_remove_item  : int -> int -> int -> int -> string -> unit  = 
"ml_upnpRemoveMap"
+
+(* remove_all_maps max_wait_seconds, 0=system default wait seconds *)
+external remove_all_maps   : int -> unit = "ml_upnpRemoveAllMaps"
+
+(* maps_get , get all maps info to a list *)
+external maps_get  : unit -> ml_port_map list = "ml_upnpGetMaps"

Index: src/utils/net/upnpClient.mli
===================================================================
RCS file: src/utils/net/upnpClient.mli
diff -N src/utils/net/upnpClient.mli
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ src/utils/net/upnpClient.mli        1 Nov 2010 17:19:23 -0000       1.1
@@ -0,0 +1,29 @@
+(* simples pure c api now
+(type ml_port_map  
+val upnp_map_list_add    : ml_port_map -> unit
+val upnp_map_list_remove : ml_port_map -> unit
+val create_ml_port_map   : int -> int -> int -> int -> string -> ml_port_map
+*)
+
+type ml_port_map = {
+       mutable enabled : int;
+       mutable intPort : int;
+       mutable extPort : int;
+       mutable isTcp   : int;
+       mutable natpmpStatus : int;
+       mutable upnpStatus : int;
+       mutable notes   : string;
+}
+
+val string_of_map_status : int -> string
+val strings_port_map : ml_port_map -> string
+       
+external init_maps : unit -> unit = "ml_upnpInitMaps" "noalloc"
+(*external set_maps  : unit -> unit = "ml_upnpSetMaps" *)
+external dump_maps : unit -> unit = "ml_upnpDumpMaps" "noalloc"
+external job_start : unit -> unit = "ml_upnp_job_start" "noalloc"
+external job_stop  : int -> unit = "ml_upnp_job_stop"
+external maps_add_item     : int -> int -> int -> int -> string -> unit  = 
"ml_upnpAddMap" 
+external maps_remove_item  : int -> int -> int -> int -> string -> unit  = 
"ml_upnpRemoveMap" 
+external remove_all_maps   : int -> unit = "ml_upnpRemoveAllMaps"
+external maps_get  : unit -> ml_port_map list = "ml_upnpGetMaps"
\ No newline at end of file

Index: src/utils/net/upnp_stubs.c
===================================================================
RCS file: src/utils/net/upnp_stubs.c
diff -N src/utils/net/upnp_stubs.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ src/utils/net/upnp_stubs.c  1 Nov 2010 17:19:23 -0000       1.1
@@ -0,0 +1,1185 @@
+/**************************************************************************/
+/*  Copyright (c) 2010 zzz <address@hidden>                             */
+/*                                                                        */
+/*  mlupnp, a ocaml wraps of libminiupnpc & libnatpmp for mldonkey        */
+/*                                                                        */
+/*  Permission is hereby granted, free of charge, to any person           */
+/*  obtaining a copy of this software and associated documentation files  */
+/*  (the "Software"), to deal in the Software without restriction,        */
+/*  including without limitation the rights to use, copy, modify, merge,  */
+/*  publish, distribute, sublicense, and/or sell copies of the Software,  */
+/*  and to permit persons to whom the Software is furnished to do so,     */
+/*  subject to the following conditions:                                  */
+/*                                                                        */
+/*  The above copyright notice and this permission notice shall be        */
+/*  included in all copies or substantial portions of the Software.       */
+/*                                                                        */
+/*  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/*  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES       */
+/*  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND              */
+/*  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS   */
+/*  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN    */
+/*  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN     */
+/*  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE      */
+/*  SOFTWARE.                                                             */
+/**************************************************************************/
+/* wraps for libminiupnpc libnatpmp*/
+
+#include "../../../config/config.h"
+#include "../../utils/lib/os_stubs.h"
+
+#ifdef ENABLE_UPNP_NATPMP
+
+#include <string.h>
+#include <ctype.h>
+
+#ifdef __MORPHOS__
+#include <inttypes.h>
+#endif  /* __MORPHOS__ */
+
+#ifdef HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>
+#endif /* HAVE_SYS_RESOURCE_H */
+
+#include <pthread.h>
+#include <signal.h>
+#include <sys/time.h>
+
+#ifdef WIN32
+ #include <inttypes.h>
+ #include <winsock2.h>
+ #include <WS2tcpip.h>
+ typedef int socklen_t;
+#else
+ #include <sys/types.h>
+ #include <sys/socket.h>
+ #include <netinet/in.h>
+ #include <arpa/inet.h>
+#endif
+
+#ifdef WIN32
+ #define ECONNREFUSED            WSAECONNREFUSED
+ #define ECONNRESET              WSAECONNRESET
+ #define EHOSTUNREACH            WSAEHOSTUNREACH
+ #define EINPROGRESS             WSAEINPROGRESS
+ #define ENOTCONN                WSAENOTCONN
+ #define EWOULDBLOCK             WSAEWOULDBLOCK
+ #define EAFNOSUPPORT            WSAEAFNOSUPPORT
+ #define ENETUNREACH             WSAENETUNREACH
+ #define sockerrno               WSAGetLastError( )
+#else
+ #include <errno.h>
+ #define sockerrno errno
+#endif
+
+#include <miniupnpc/miniupnpc.h>
+#include <miniupnpc/upnpcommands.h>
+#define ENABLE_STRNATPMPERR
+#include <natpmp.h>
+
+#undef  DEBUG_PRINTF_UPNP
+#ifdef  DEBUG_PRINTF_UPNP
+#define dbg_printf printf
+#else
+static void dbg_printf (const char *str, ... ){}
+#endif
+
+/* can hold max 20 port forwarding, is it enough for all mldonkey 
bt/ed2k/kad/ft clients I think */
+#define MAX_MAPS 20
+#define MAX_THREAD_WAIT 30
+#define COMMAND_WAIT_SECS 8
+#define LIFETIME_SECS 3600
+
+enum
+{
+       UPNP_IGD_NONE = 0,
+       UPNP_IGD_VALID_CONNECTED = 1,
+       UPNP_IGD_VALID_NOT_CONNECTED = 2,
+       UPNP_IGD_INVALID = 3
+};
+
+typedef enum
+{
+    ML_UPNP_IDLE = 0,
+    ML_UPNP_ERR,
+    ML_UPNP_DISCOVER,
+    ML_UPNP_MAP,
+    ML_UPNP_UNMAP
+}
+ml_upnp_state;
+
+typedef enum
+{
+       ML_NATPMP_IDLE = 0,
+       ML_NATPMP_ERR,
+       ML_NATPMP_DISCOVER,
+       ML_NATPMP_RECV_PUB,
+       ML_NATPMP_SEND_MAP,
+       ML_NATPMP_RECV_MAP,
+       ML_NATPMP_SEND_UNMAP,
+       ML_NATPMP_RECV_UNMAP
+}
+ml_natpmp_state;
+
+typedef enum
+{
+    ML_PORT_ERROR  = 0,
+    ML_PORT_UNMAPPED,
+    ML_PORT_UNMAPPING,
+    ML_PORT_MAPPING,
+    ML_PORT_MAPPED
+}
+ml_port_forwarding;
+
+typedef struct ml_upnpmp_t
+{
+       int                enabled;
+       unsigned short int intPort;
+       unsigned short int extPort;
+       int                isTcp;       /*tcp=1, udp=0*/
+       char               notes[32];
+    char               lanaddr[16];
+    int                doPortCheck;
+    time_t             overTime;
+    ml_port_forwarding natpmpStatus;
+    ml_port_forwarding upnpStatus;
+
+    int                upnpDiscovered;
+    unsigned int       upnpMapped;
+    ml_upnp_state      upnpState;
+    struct UPNPUrls    upnpUrls;
+    struct IGDdatas    upnpData;
+
+    unsigned int       natpmpMapped;
+    int                natpmpDiscovered;
+    ml_upnp_state      natpmpState;
+    time_t             renewTime;
+    time_t             commandTime;
+    natpmp_t           natpmp;
+}ml_upnpmp_t;
+
+static ml_upnpmp_t g_maps[MAX_MAPS];
+static ml_upnpmp_t g_unmaps[MAX_MAPS];
+static int g_inited = 0;
+static int g_running = 0;
+static int g_stop = 0;
+static pthread_t g_pthread;
+//static pthread_cond_t cond;
+static pthread_mutex_t g_mutex;
+static pthread_mutex_t g_delay_mutex;
+
+
+/** @brief init memset 0 g_maps g_unmaps */
+static void init_maps()
+{
+       if ( ! g_inited ){
+               memset( g_maps, 0, sizeof(g_maps) );
+               memset( g_unmaps, 0, sizeof(g_unmaps) );
+               g_inited = 1;
+       }
+}
+
+/** @brief add a ml_upnpmp_t item to g_maps */
+static int maps_add_item( ml_upnpmp_t * map )
+{
+       int i;
+       int found;
+
+       if ( ! g_inited ){
+               dbg_printf("g_maps not initialize!\n");
+               return -1;
+       }
+
+       found = 0;
+       for (i = 0; i < MAX_MAPS; i++){
+               if ( ! g_maps[i].enabled ){
+                       continue;
+               }
+               if (g_maps[i].intPort == map->intPort && \
+                       g_maps[i].extPort == map->extPort && \
+                       g_maps[i].isTcp == map->isTcp){
+                       found = 1;
+                       dbg_printf("intPort %d, extPort %d, isTcp %d 
existed\n", map->intPort, map->extPort, map->isTcp);
+                       break;
+               }
+       }
+
+       if ( ! found ){
+               for(i = 0; i < MAX_MAPS; i++){
+                       if ( ! g_maps[i].enabled ){
+                               pthread_mutex_lock(&g_mutex);
+                               memcpy(&g_maps[i], map, sizeof(ml_upnpmp_t));
+                               g_maps[i].enabled = 1;
+                               g_maps[i].upnpState   = ML_UPNP_DISCOVER;
+                               g_maps[i].natpmpState = ML_NATPMP_DISCOVER;
+                               g_maps[i].natpmp.s = -1; /* socket */
+                               g_maps[i].upnpStatus   = ML_PORT_UNMAPPED;
+                               g_maps[i].natpmpStatus = ML_PORT_UNMAPPED;
+                               g_maps[i].overTime = 0;
+                               pthread_mutex_unlock(&g_mutex);
+                               dbg_printf("intPort %d, extPort %d, isTcp %d 
added\n", map->intPort, map->extPort, map->isTcp);
+                               return 0;
+                               break;
+                       }
+               }
+       }
+
+       return 1;
+}
+
+/** @brief remove a ml_upnpmp_t item form g_maps, and add to g_unmaps */
+static int maps_remove_item( ml_upnpmp_t * map )
+{
+       int i,j;
+       int found;
+
+       if ( ! g_inited ){
+               dbg_printf("g_maps not initialize!\n");
+               return -1;
+       }
+
+       found = 0;
+       for (i = 0; i < MAX_MAPS; i++){
+               if ( ! g_maps[i].enabled ){
+                       continue;
+               }
+               if (g_maps[i].intPort == map->intPort && \
+                       g_maps[i].extPort == map->extPort && \
+                       g_maps[i].isTcp == map->isTcp){
+                       found = 1;
+                       for(j = 0; j < MAX_MAPS; j++){
+                               if ( !g_unmaps[j].extPort ){
+                                       pthread_mutex_lock(&g_mutex);
+                                       memcpy(&g_unmaps[j], &g_maps[i], 
sizeof(ml_upnpmp_t));
+                                       g_unmaps[j].enabled = 0;
+                                       g_unmaps[j].overTime = 0;
+                                       memset(&g_maps[i], 0, 
sizeof(ml_upnpmp_t));
+                                       pthread_mutex_unlock(&g_mutex);
+                                       dbg_printf("intPort %d, extPort %d, 
isTcp %d moved from maps to unmaps\n", map->intPort, map->extPort, map->isTcp);
+                                       return 0;
+                                       break;
+                               }
+                       }
+                       break;
+               }
+       }
+
+       if ( ! found ){
+               for (i = 0; i < MAX_MAPS; i++){
+                       if (g_unmaps[i].intPort == map->intPort && \
+                               g_unmaps[i].extPort == map->extPort && \
+                               g_unmaps[i].isTcp == map->isTcp){
+                               dbg_printf("intPort %d, extPort %d, isTcp %d 
existed in unmaps\n", map->intPort, map->extPort, map->isTcp);
+                               return 0;
+                               break;
+                       }
+               }
+               for(j = 0; j < MAX_MAPS; j++){
+                       if ( !g_unmaps[j].extPort ){
+                               pthread_mutex_lock(&g_mutex);
+                               memcpy(&g_unmaps[j], map, sizeof(ml_upnpmp_t));
+                               g_unmaps[j].enabled = 0;
+                               g_unmaps[j].overTime = 0;
+                               pthread_mutex_unlock(&g_mutex);
+                               dbg_printf("intPort %d, extPort %d, isTcp %d 
add to unmaps\n", map->intPort, map->extPort, map->isTcp);
+                               return 0;
+                               break;
+                       }
+               }
+       }
+
+       return 1;
+}
+
+#if 0
+/** @brief new ml_upnpmp_t struct from int_port, ext_port, type, notes */
+value
+ml_upnpSetMaps(value map_list_v) {
+       ml_upnpmp_t map;
+       int i,j;
+       int found;
+       char *s = NULL;
+       value map_v;
+
+       if ( ! g_inited ){
+               dbg_printf("g_maps not initialize!\n");
+               return Val_unit;
+       }
+       const int len = Wosize_val(map_list_v);
+       //move the map from g_maps to g_unmaps that noexist in new map_list_v
+       for (i = 0; i < MAX_MAPS; i++){
+               if ( ! g_maps[i].enabled ){
+                       continue;
+               }
+               found = 0;
+               for(j = 0; j<len && j < MAX_MAPS; j++){
+                       //memset((void*) &map, 0, sizeof(map));
+                       map_v = Field(map_list_v, j);
+                       map.enabled  = Int_val(Field(map_v, 0));
+                       if ( ! map.enabled ){
+                               continue;
+                       }
+                       map.intPort = Int_val(Field(map_v, 1));
+                       map.extPort = Int_val(Field(map_v, 2));
+                       map.isTcp   = Int_val(Field(map_v, 3));
+                       //strncpy(map.notes, String_val(Field(map_v, 4)), 32-1);
+
+                       if (g_maps[i].intPort == map.intPort && \
+                               g_maps[i].extPort == map.extPort && \
+                               g_maps[i].isTcp   == map.isTcp){
+                               found = 1;
+                               break;
+                       }
+               }
+
+               if ( ! found ){
+                       for(j = 0; j < MAX_MAPS; j++){
+                               if ( ! g_unmaps[j].enabled && ! 
g_unmaps[j].extPort ){
+                                       pthread_mutex_lock(&g_mutex);
+                                       memcpy(&g_unmaps[j], &g_maps[i], 
sizeof(ml_upnpmp_t));
+                                       g_unmaps[j].enabled = 0;
+                                       memset(&g_maps[i], 0, 
sizeof(ml_upnpmp_t));
+                                       pthread_mutex_unlock(&g_mutex);
+                                       break;
+                               }
+                       }
+               }
+       }
+
+       //add the new map from map_list_v to g_maps that noexist in g_maps
+       for (i = 0; i < len && i<MAX_MAPS; i++){
+               memset((void*) &map, 0, sizeof(map));
+               map_v = Field(map_list_v, i);
+               map.enabled  = Int_val(Field(map_v, 0));
+               if ( ! map.enabled ){
+                       continue;
+               }
+               map.intPort = Int_val(Field(map_v, 1));
+               map.extPort = Int_val(Field(map_v, 2));
+               map.isTcp   = Int_val(Field(map_v, 3));
+               s = String_val(Field(map_v, 4));
+               if (s && *s){
+                       strncpy(map.notes, s, 32-1);
+               }else{
+                       strncpy(map.notes, "mldonkey", 32-1);
+               }
+
+               found = 0;
+               for(j = 0; j < MAX_MAPS; j++){
+                       if (g_maps[j].intPort == map.intPort && \
+                               g_maps[j].extPort == map.extPort && \
+                               g_maps[j].isTcp   == map.isTcp){
+                               found = 1;
+                               break;
+                       }
+               }
+               if ( ! found  ){
+                       maps_add_item( &map );
+               }
+       }
+
+       return Val_unit;
+}
+#endif
+
+/** @brief dump ml_upnpmp_t struct */
+static void
+dumpMap(const ml_upnpmp_t * map, int type)
+{
+       if (type){
+               printf("map->enabled = %d\n", map->enabled);
+               printf("map->intPort = %d\n", map->intPort);
+               printf("map->extPort = %d\n", map->extPort);
+               printf("map->isTcp   = %d\n", map->isTcp);
+               printf("map->notes   = %s\n", map->notes);
+               printf("map->lanaddr = %02x:%02x:%02x::::%02x:%02x:%02x\n", 
map->lanaddr[0], map->lanaddr[1], map->lanaddr[2], map->lanaddr[13], 
map->lanaddr[14], map->lanaddr[15]);
+
+               printf("map->upnpDscv    = %d\n", map->upnpDiscovered);
+               printf("map->upnpMapped  = %d\n", map->upnpMapped);
+               printf("map->upnpState   = %d\n", map->upnpState);
+
+               printf("map->natpmpDscv  = %d\n", map->natpmpDiscovered);
+               printf("map->natpmpMapped= %d\n", map->natpmpMapped);
+               printf("map->natpmpState = %d\n", map->natpmpState);
+
+               printf("map->overTime    = %d\n", (unsigned int)map->overTime);
+               printf("map->natpmpStatus= %d\n", map->natpmpStatus);
+               printf("map->upnpStatus  = %d\n", map->upnpStatus);
+       }else{
+               printf("%1d ", map->enabled);
+               printf("%6d ", map->intPort);
+               printf("%6d ", map->extPort);
+               printf("%1d ", map->isTcp);
+               printf("%16s ", map->notes);
+               printf("%02x:%02x:%02x::::%02x:%02x:%02x ", map->lanaddr[0], 
map->lanaddr[1], map->lanaddr[2], map->lanaddr[13], map->lanaddr[14], 
map->lanaddr[15]);
+
+               printf("%1d ", map->upnpDiscovered);
+               printf("%1d ", map->upnpMapped);
+               printf("%1d ", map->upnpState);
+
+               printf("%1d ", map->natpmpDiscovered);
+               printf("%1d ", map->natpmpMapped);
+               printf("%1d ", map->natpmpState);
+               printf("%10d ", (unsigned int)map->overTime);
+               printf("%1d ", map->natpmpStatus);
+               printf("%1d ", map->upnpStatus);
+               printf("\n");
+       }
+}
+
+value
+ml_upnpDumpMaps(value unused)
+{
+       int i;
+       ml_upnpmp_t * map;
+
+       printf("=============== g_unmaps ===============\n");
+       printf("enabled intPort extPort isTcp notes lanaddr upnpDscv upnpMapped 
upnpState natpmpDscv natpmpMapped natpmpState overTime natpmpStatus 
upnpStatus\n");
+       for(i = 0; i < MAX_MAPS; i++ ){
+               map = &g_unmaps[i];
+               dumpMap( map, 0 );
+       }
+       printf("=============== g_maps ===============\n");
+       printf("enabled intPort extPort isTcp notes lanaddr upnpDscv upnpMapped 
upnpState natpmpDscv natpmpMapped natpmpState overTime natpmpStatus 
upnpStatus\n");
+       for(i = 0; i < MAX_MAPS; i++ ){
+               map = &g_maps[i];
+               dumpMap( map, 0 );
+       }
+
+       return Val_unit;
+}
+
+
+static inline int
+getStatus( const ml_upnpmp_t * map )
+{
+       if (map->natpmpStatus > map->upnpStatus)
+               return map->natpmpStatus;
+       else
+               return map->upnpStatus;
+}
+
+static const char*
+getNatStateStr( const int state )
+{
+    switch( state )
+    {
+        case ML_PORT_MAPPING:   return "Starting";
+        case ML_PORT_MAPPED:    return "Forwarded";
+        case ML_PORT_UNMAPPING: return "Stopping";
+        case ML_PORT_UNMAPPED:  return "Not forwarded";
+        default:                return "???";
+    }
+}
+
+const char*
+str_errno( const int i )
+{
+    const char * ret = strerror( i );
+
+    if( ret == NULL )
+        ret = "Unknown Error";
+    return ret;
+}
+
+static int
+canSendCommand( ml_upnpmp_t * map )
+{
+    return time(NULL) >= map->commandTime;
+}
+
+static void
+setCommandTime( ml_upnpmp_t * map )
+{
+    map->commandTime = time(NULL) + COMMAND_WAIT_SECS;
+}
+
+static int
+natpmpPulse( ml_upnpmp_t * map )
+{
+    int ret;
+
+    if( map->enabled && ( map->natpmpState == ML_NATPMP_DISCOVER ) )
+    {
+        int val = initnatpmp( &map->natpmp );
+        dbg_printf( "initnatpmp = %d\n", val );
+        val = sendpublicaddressrequest( &map->natpmp );
+        dbg_printf( "sendpublicaddressrequest = %d\n", val );
+        map->natpmpState = val < 0 ? ML_NATPMP_ERR : ML_NATPMP_RECV_PUB;
+        map->natpmpDiscovered = 1;
+        setCommandTime( map );
+    }
+
+    if( ( map->natpmpState == ML_NATPMP_RECV_PUB ) && canSendCommand( map ) )
+    {
+        natpmpresp_t response;
+        const int    val = readnatpmpresponseorretry( &map->natpmp,
+                                                      &response );
+        dbg_printf( "readnatpmpresponseorretry = %d\n", val );
+        if( val >= 0 )
+        {
+            dbg_printf( "Found public address \"%s\"\n", inet_ntoa( 
response.pnu.publicaddress.addr ) );
+            map->natpmpState = ML_NATPMP_IDLE;
+        }
+        else if( val != NATPMP_TRYAGAIN )
+        {
+                map->natpmpState = ML_NATPMP_ERR;
+        }
+    }
+
+    if( (  map->natpmpState == ML_NATPMP_IDLE ) || (  map->natpmpState == 
ML_NATPMP_ERR ) )
+    {
+        if(  map->natpmpMapped && ( ! map->enabled ) )
+            map->natpmpState = ML_NATPMP_SEND_UNMAP;
+    }
+
+    if( ( map->natpmpState == ML_NATPMP_SEND_UNMAP ) && canSendCommand( map ) )
+    {
+        const int val =
+            sendnewportmappingrequest( &map->natpmp, NATPMP_PROTOCOL_TCP,
+                                       map->intPort, map->extPort,
+                                       0 );
+        dbg_printf( "sendnewportmappingrequest = %d\n", val );
+        map->natpmpState = val < 0 ? ML_NATPMP_ERR : ML_NATPMP_RECV_UNMAP;
+        setCommandTime( map );
+    }
+
+    if( map->natpmpState == ML_NATPMP_RECV_UNMAP )
+    {
+        natpmpresp_t resp;
+        const int    val = readnatpmpresponseorretry( &map->natpmp, &resp );
+        dbg_printf( "readnatpmpresponseorretry = %d\n", val );
+        if( val >= 0 )
+        {
+            const int p = resp.pnu.newportmapping.privateport;
+            dbg_printf( "no longer forwarding port %d\n", p );
+            if( map->extPort == p )
+            {
+               map->extPort = 0;
+               map->natpmpState = ML_NATPMP_IDLE;
+                map->natpmpMapped = 0;
+            }
+        }
+        else if( val != NATPMP_TRYAGAIN )
+        {
+               map->natpmpState = ML_NATPMP_ERR;
+        }
+    }
+
+    if( map->natpmpState == ML_NATPMP_IDLE )
+    {
+        if( map->enabled && !map->natpmpMapped && map->natpmpDiscovered )
+               map->natpmpState = ML_NATPMP_SEND_MAP;
+
+        else if( map->natpmpMapped && time(NULL) >= map->renewTime )
+            map->natpmpState = ML_NATPMP_SEND_MAP;
+    }
+
+    if( ( map->natpmpState == ML_NATPMP_SEND_MAP ) && canSendCommand( map ) )
+    {
+        const int val =
+            sendnewportmappingrequest( &map->natpmp, NATPMP_PROTOCOL_TCP,
+                                       map->intPort,
+                                       map->extPort,
+                                       LIFETIME_SECS );
+        dbg_printf( "sendnewportmappingrequest = %d\n", val );
+        map->natpmpState = val < 0 ? ML_NATPMP_ERR : ML_NATPMP_RECV_MAP;
+        setCommandTime( map );
+    }
+
+    if( map->natpmpState == ML_NATPMP_RECV_MAP )
+    {
+        natpmpresp_t resp;
+        const int    val = readnatpmpresponseorretry( &map->natpmp, &resp );
+        dbg_printf( "readnatpmpresponseorretry = %d\n", val );
+        if( val >= 0 )
+        {
+               map->natpmpState = ML_NATPMP_IDLE;
+            map->natpmpMapped = 1;
+            map->renewTime = time(NULL) + LIFETIME_SECS;
+            map->extPort = resp.pnu.newportmapping.privateport;
+            dbg_printf( "Port %d forwarded successfully\n", map->extPort );
+        }
+        else if( val != NATPMP_TRYAGAIN )
+        {
+            map->natpmpState = ML_NATPMP_ERR;
+        }
+    }
+
+    switch( map->natpmpState )
+    {
+        case ML_NATPMP_IDLE:
+            ret = map->natpmpMapped ? ML_PORT_MAPPED : ML_PORT_UNMAPPED; break;
+
+        case ML_NATPMP_DISCOVER:
+            ret = ML_PORT_UNMAPPED; break;
+
+        case ML_NATPMP_RECV_PUB:
+        case ML_NATPMP_SEND_MAP:
+        case ML_NATPMP_RECV_MAP:
+            ret = ML_PORT_MAPPING; break;
+
+        case ML_NATPMP_SEND_UNMAP:
+        case ML_NATPMP_RECV_UNMAP:
+            ret = ML_PORT_UNMAPPING; break;
+
+        default:
+            ret = ML_PORT_ERROR; break;
+    }
+    return ret;
+}
+
+
+static int
+upnpPulse( ml_upnpmp_t * map )
+{
+    int ret;
+
+    if( map->enabled && ( map->upnpState == ML_UPNP_DISCOVER ) )
+    {
+        struct UPNPDev * devlist;
+        errno = 0;
+        devlist = upnpDiscover( 2000, NULL, NULL, 0 );
+        if( devlist == NULL )
+        {
+            dbg_printf( "upnpDiscover failed (errno %d - %s)\n", errno,  
str_errno( errno ) );
+        }
+        errno = 0;
+        if( UPNP_IGD_VALID_CONNECTED == UPNP_GetValidIGD( devlist, 
&map->upnpUrls, &map->upnpData,
+                       map->lanaddr, sizeof( map->lanaddr ) ) )
+        {
+            dbg_printf( "Found Internet Gateway Device \"%s\" \n", 
map->upnpUrls.controlURL );
+            dbg_printf( "Local Address is \"%s\" \n", map->lanaddr );
+            map->upnpState = ML_UPNP_IDLE;
+            map->upnpDiscovered = 1;
+        }
+        else
+        {
+            map->upnpState = ML_UPNP_ERR;
+            dbg_printf( "UPNP_GetValidIGD failed (errno %d - %s)\n", errno, 
str_errno( errno ) );
+            dbg_printf( "If your router supports UPnP, please make sure UPnP 
is enabled!\n" );
+        }
+        freeUPNPDevlist( devlist );
+    }
+
+    if( map->upnpState == ML_UPNP_IDLE )
+    {
+        if( map->upnpMapped && ( !map->enabled ) )
+               map->upnpState = ML_UPNP_UNMAP;
+    }
+
+    if( map->enabled && map->upnpMapped && map->doPortCheck )
+    {
+        char portStr[8];
+        char intPort[8];
+        char intClient[16];
+        char type[8];
+        int i;
+
+        snprintf( portStr, sizeof( portStr ), "%d", map->extPort );
+        snprintf( type, sizeof( type ), "%s", ( map->isTcp ? "TCP" : "UDP" ) );
+        i = UPNP_GetSpecificPortMappingEntry( map->upnpUrls.controlURL,
+                                              map->upnpData.first.servicetype, 
portStr,
+                                              type, intClient, intPort );
+        if( i != UPNPCOMMAND_SUCCESS )
+        {
+            dbg_printf( "Port %d isn't forwarded\n", map->extPort );
+            map->upnpMapped = 0;
+        }
+        map->doPortCheck = 0;
+    }
+
+    if( map->upnpState == ML_UPNP_UNMAP )
+    {
+        char portStr[16];
+        char type[8];
+        snprintf( portStr, sizeof( portStr ), "%d", map->extPort );
+        snprintf( type, sizeof( type ), "%s", ( map->isTcp ? "TCP" : "UDP" ) );
+        UPNP_DeletePortMapping( map->upnpUrls.controlURL,
+                                map->upnpData.first.servicetype,
+                                portStr, type, NULL );
+        dbg_printf( "Stopping port forwarding through \"%s\", service 
\"%s\"\n", map->upnpUrls.controlURL, map->upnpData.first.servicetype );
+        map->upnpMapped = 0;
+        map->upnpState = ML_UPNP_IDLE;
+        map->extPort = 0;
+    }
+
+    if( map->upnpState == ML_UPNP_IDLE )
+    {
+        if( map->enabled && !map->upnpMapped )
+            map->upnpState = ML_UPNP_MAP;
+    }
+
+    if( map->upnpState == ML_UPNP_MAP )
+    {
+        int  err = -1;
+        errno = 0;
+
+        if( !map->upnpUrls.controlURL || !map->upnpData.first.servicetype )
+            map->upnpMapped = 0;
+        else
+        {
+            char intPortStr[16];
+            char extPortStr[16];
+            char desc[64];
+            char type[8];
+            snprintf( intPortStr, sizeof( intPortStr ), "%d", map->intPort );
+            snprintf( extPortStr, sizeof( extPortStr ), "%d", map->extPort );
+            snprintf( desc, sizeof( desc ), "%s", map->notes );
+            snprintf( type, sizeof( type ), "%s", ( map->isTcp ? "TCP" : "UDP" 
) );
+            err = UPNP_AddPortMapping( map->upnpUrls.controlURL,
+                                       map->upnpData.first.servicetype,
+                                       extPortStr, intPortStr, map->lanaddr,
+                                       desc, type, NULL );
+            map->upnpMapped = !err;
+        }
+        dbg_printf( "Port forwarding through \"%s\", service \"%s\". (local 
address[%s:%d])\n", map->upnpUrls.controlURL, map->upnpData.first.servicetype, 
map->lanaddr, map->intPort );
+        if( map->upnpMapped )
+        {
+            dbg_printf( "Port forwarding successful!\n" );
+            //handle->port = port;
+            map->upnpState = ML_UPNP_IDLE;
+        }
+        else
+        {
+            dbg_printf( "Port forwarding failed with error %d (errno %d - 
%s)\n", err, errno, str_errno( errno ) );
+            dbg_printf( "If your router supports UPnP, please make sure UPnP 
is enabled!\n" );
+            //handle->port = -1;
+            map->upnpState = ML_UPNP_ERR;
+        }
+    }
+
+    switch( map->upnpState )
+    {
+        case ML_UPNP_DISCOVER:
+            ret = ML_PORT_UNMAPPED; break;
+
+        case ML_UPNP_MAP:
+            ret = ML_PORT_MAPPING; break;
+
+        case ML_UPNP_UNMAP:
+            ret = ML_PORT_UNMAPPING; break;
+
+        case ML_UPNP_IDLE:
+            ret = map->upnpMapped ? ML_PORT_MAPPED
+                  : ML_PORT_UNMAPPED; break;
+
+        default:
+            ret = ML_PORT_ERROR; break;
+    }
+
+    return ret;
+}
+
+
+static void *
+upnpNatpmpThread( )
+{
+       int oldStatus, newStatus;
+       int i, err;
+       time_t now;
+       struct timespec deltatime;
+
+       pthread_mutex_lock(&g_mutex);
+       g_stop = 0;
+       pthread_mutex_unlock(&g_mutex);
+
+       while( g_running ){
+               //clear in g_unmaps
+               now = time(NULL);
+               for(i = 0; i < MAX_MAPS; i++){
+                       if ( ! g_running )      break;
+
+                       if ( ! g_unmaps[i].enabled && g_unmaps[i].extPort > 0 ){
+                               if ( g_unmaps[i].overTime < now ){
+                                       oldStatus = getStatus( &g_unmaps[i] );
+
+                                       pthread_mutex_lock(&g_mutex);
+
+                                       switch (oldStatus){
+                               case ML_PORT_MAPPED:
+                                       g_unmaps[i].overTime = now + 60 * 20;
+                                       break;
+                               case ML_PORT_ERROR:
+                                       g_unmaps[i].overTime = now + 60;
+                                       break;
+                               default:
+                                   /* in progress.  pulse frequently. */
+                                       g_unmaps[i].overTime = now + 333;
+                                   break;
+                                       }
+                                       g_unmaps[i].natpmpStatus = natpmpPulse( 
&g_unmaps[i] );
+                                       g_unmaps[i].doPortCheck = 0;
+                                       g_unmaps[i].upnpStatus  = upnpPulse( 
&g_unmaps[i]);
+                                       dbg_printf( "upnpNatpmpThread 
g_unmaps[%d]\n", i);
+
+#ifdef DEBUG_PRINTF_UPNP
+                                       dumpMap(&g_unmaps[i], 1);
+#endif
+                                       newStatus    = getStatus( &g_unmaps[i] 
);
+
+                                       if( newStatus != oldStatus )
+                                               dbg_printf( "port forwarding 
state changed from \"%s\" to \"%s\"\n", getNatStateStr( oldStatus ),       
getNatStateStr( newStatus ) );
+                                       if( newStatus == ML_PORT_UNMAPPED ){
+                                               memset(&g_unmaps[i], 0, 
sizeof(ml_upnpmp_t));
+                                       }
+                                       pthread_mutex_unlock(&g_mutex);
+                               }
+                       }
+               }
+               //create,check in g_maps
+               now = time(NULL);
+               for(i = 0; i < MAX_MAPS; i++){
+                       if ( ! g_running )      break;
+
+                       if ( g_maps[i].enabled && g_maps[i].extPort ){
+                               if ( g_maps[i].overTime < now ){
+                                       oldStatus = getStatus( &g_maps[i] );
+
+                                       pthread_mutex_lock(&g_mutex);
+
+                                       switch (oldStatus){
+                               case ML_PORT_MAPPED:
+                                       g_maps[i].overTime = now + 60 * 20;
+                                       break;
+                               case ML_PORT_ERROR:
+                                       g_maps[i].overTime = now + 60;
+                                       break;
+                               default:
+                                   /* in progress.  pulse frequently. */
+                                       g_maps[i].overTime = now + 333;
+                                   break;
+                                       }
+                                       g_maps[i].natpmpStatus = natpmpPulse( 
&g_maps[i] );
+                                       g_maps[i].doPortCheck = 1;
+                                       g_maps[i].upnpStatus   = upnpPulse( 
&g_maps[i] );
+
+                                       pthread_mutex_unlock(&g_mutex);
+
+                                       dbg_printf( "upnpNatpmpThread 
g_maps[%d]\n", i);
+#ifdef DEBUG_PRINTF_UPNP
+                                       dumpMap(&g_maps[i], 1);
+#endif
+
+                                       newStatus = getStatus( &g_maps[i] );
+
+                                       if( newStatus != oldStatus )
+                                               dbg_printf( "port forwarding 
state changed from \"%s\" to \"%s\"\n", getNatStateStr( oldStatus ), 
getNatStateStr( newStatus ) );
+                               }
+                       }
+               }
+               if ( g_running ){
+                       deltatime.tv_sec = time(NULL) + 30;
+                       deltatime.tv_nsec = 0;
+                       err = pthread_mutex_timedlock(&g_delay_mutex, 
&deltatime);
+                       dbg_printf("%d seconds timedlock err=%d, running...\n", 
deltatime.tv_sec, err);
+               }else{
+                       break;
+               }
+       }
+       pthread_mutex_lock(&g_mutex);
+       g_stop = 1;
+       pthread_mutex_unlock(&g_mutex);
+       dbg_printf("upnp thread stopped!\n");
+
+       return NULL;
+}
+
+static void
+upnp_thread_start( )
+{
+       int err;
+       if ( ! g_inited ){
+               init_maps();
+       }
+
+       if ( ! g_running ){
+           pthread_attr_t attr;
+           pthread_attr_init(&attr);
+           pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+
+           //pthread_cond_init(&cond, NULL);
+           pthread_mutex_init(&g_mutex, NULL);
+           pthread_mutex_init(&g_delay_mutex, NULL);
+           pthread_mutex_unlock(&g_mutex);
+
+           err = pthread_create(&g_pthread, &attr, upnpNatpmpThread, NULL);
+
+           if(err){
+               perror("Error while starting upnp thread\n");
+               exit(2);
+           }
+               g_inited  = 1;
+           pthread_mutex_lock(&g_mutex);
+               g_running = 1;
+               g_stop = 0;
+           pthread_mutex_unlock(&g_mutex);
+       }else{
+               dbg_printf("threading had started\n");
+       }
+       return;
+}
+
+static void
+upnp_thread_stop( int wait_seconds )
+{
+       int i = 0;
+       int wait = wait_seconds;
+
+       if (wait < 1) wait = MAX_THREAD_WAIT;
+
+       pthread_mutex_lock(&g_mutex);
+       g_stop = 0;
+       g_running = 0;
+       pthread_mutex_unlock(&g_mutex);
+       pthread_mutex_unlock(&g_delay_mutex);
+
+       for (i=0; i<wait; i++){
+               if (g_stop){
+                       pthread_mutex_lock(&g_mutex);
+                       g_stop = 0;
+                       pthread_mutex_unlock(&g_mutex);
+                       break;
+               }else{
+                       sleep(1);
+               }
+       }
+
+       if (i >= wait){
+               pthread_cancel(g_pthread);
+       }
+       pthread_mutex_destroy(&g_mutex);
+       pthread_mutex_destroy(&g_delay_mutex);
+       return;
+}
+
+/** @brief ocaml api, init memset g_maps g_unmaps to 0 */
+value
+ml_upnpInitMaps(value unused)
+{
+       init_maps();
+       return Val_unit;
+}
+
+
+/** @brief ocaml api, start the upnp thread */
+value
+ml_upnp_job_start( value unused )
+{
+       upnp_thread_start( );
+       return Val_unit;
+}
+
+
+/** @brief ocaml api, stop the upnp thread */
+value
+ml_upnp_job_stop( value wait_v )
+{
+       int wait;
+       wait = Val_int( wait_v );
+
+       upnp_thread_stop( wait );
+       return Val_unit;
+}
+
+/** @brief caml api, new ml_upnpmp_t struct from int_port, ext_port, type, 
notes, and add to g_maps */
+value
+ml_upnpAddMap(value m_enabled, value m_intPort, value m_extPort, value m_type, 
value m_notes)
+{
+       ml_upnpmp_t map;
+       char *s = NULL;
+
+       memset(&map, 0, sizeof(ml_upnpmp_t));
+
+       map.enabled = Int_val(m_enabled);
+       map.intPort = Int_val(m_intPort);
+       map.extPort = Int_val(m_extPort);
+       map.isTcp   = Int_val(m_type);
+       s = String_val(m_notes);
+       if (s && *s){
+               strncpy(map.notes, s, 32-1);
+       }else{
+               strncpy(map.notes, "mldonkey", 32-1);
+       }
+
+       maps_add_item( &map );
+
+       return Val_unit;
+}
+
+/** @brief caml api, new ml_upnpmp_t struct from int_port, ext_port, type, 
notes, and remove from g_maps, add to g_unmaps */
+value
+ml_upnpRemoveMap(value m_enabled, value m_intPort, value m_extPort, value 
m_type, value m_notes)
+{
+       ml_upnpmp_t map;
+       char *s = NULL;
+
+       memset(&map, 0, sizeof(ml_upnpmp_t));
+
+       map.enabled = Int_val(m_enabled);
+       map.intPort = Int_val(m_intPort);
+       map.extPort = Int_val(m_extPort);
+       map.isTcp   = Int_val(m_type);
+       s =  String_val(m_notes);
+       if (s && *s){
+               strncpy(map.notes, s, 32-1);
+       }else{
+               strncpy(map.notes, "mldonkey", 32-1);
+       }
+       maps_remove_item( &map );
+
+       return Val_unit;
+}
+
+/** @brief caml api, stop all maps in g_maps, call before mldonkey exit to 
clear router */
+value
+ml_upnpRemoveAllMaps(value wait_v)
+{
+       int i,j;
+       int found;
+       int wait;
+       wait = Val_int( wait_v );
+       if (wait < 1) wait = MAX_THREAD_WAIT;
+
+       if ( ! g_inited ){
+               dbg_printf("g_maps not initialize!\n");
+               return Val_unit;
+       }
+
+       for (i = 0; i < MAX_MAPS; i++){
+               if ( ! g_maps[i].enabled ){
+                       continue;
+               }
+               found = 0;
+               for(j = 0; j < MAX_MAPS; j++){
+                       if (g_maps[i].intPort == g_unmaps[j].intPort && \
+                               g_maps[i].extPort == g_unmaps[j].extPort && \
+                               g_maps[i].isTcp   == g_unmaps[j].isTcp){
+                               found = 1;
+                               break;
+                       }
+               }
+
+               if ( ! found ){
+                       for(j = 0; j < MAX_MAPS; j++){
+                               if ( ! g_unmaps[j].enabled && ! 
g_unmaps[j].extPort ){
+                                       pthread_mutex_lock(&g_mutex);
+                                       memcpy(&g_unmaps[j], &g_maps[i], 
sizeof(ml_upnpmp_t));
+                                       g_unmaps[j].enabled = 0;
+                                       g_unmaps[j].overTime = 0;
+                                       memset(&g_maps[i], 0, 
sizeof(ml_upnpmp_t));
+                                       pthread_mutex_unlock(&g_mutex);
+                                       break;
+                               }
+                       }
+               }
+       }
+       pthread_mutex_unlock( &g_delay_mutex );
+
+       for (i=0; i<wait; i++){
+               sleep(1);
+               found = 0;
+               for(j = 0; j < MAX_MAPS; j++){
+                       if (g_unmaps[j].extPort){
+                               found = 1;
+                               break;
+                       }
+               }
+               if ( ! found ){
+                       break;
+               }
+       }
+       return Val_unit;
+}
+
+/** @brief caml api, reutrn all maps in g_maps to a list[tuple(7 items)] */
+value
+ml_upnpGetMaps(value unused)
+{
+       CAMLparam0 ();
+       int i;
+
+       CAMLlocal3( maps, map, cons );
+       maps = Val_emptylist;
+
+       if ( ! g_inited ){
+               dbg_printf("g_maps not initialize!\n");
+               CAMLreturn( Val_unit );
+       }
+
+       for (i = MAX_MAPS - 1; i > 0; i--){
+               if ( ! g_maps[i].enabled ){
+                       continue;
+               }
+
+               map = caml_alloc_tuple( 7 );
+               Store_field( map, 0, Val_int(g_maps[i].enabled) );
+               Store_field( map, 1, Val_int(g_maps[i].intPort) );
+               Store_field( map, 2, Val_int(g_maps[i].extPort) );
+               Store_field( map, 3, Val_int(g_maps[i].isTcp) );
+               Store_field( map, 4, Val_int(g_maps[i].natpmpStatus) );
+               Store_field( map, 5, Val_int(g_maps[i].upnpStatus) );
+               Store_field( map, 6, caml_copy_string(g_maps[i].notes) );
+
+               cons = caml_alloc( 2, 0 );
+               Store_field( cons, 0, map ); // head
+               Store_field( cons, 1, maps ); // tail
+               maps = cons;
+       }
+       CAMLreturn( maps );
+}
+
+
+#else /* for ifdef ENABLE_UPNP_NATPMP */
+/* no include upnp natpmp, dummy api here */
+value
+ml_upnpInitMaps(value unused)
+{
+       return Val_unit;
+}
+
+/** @brief ocaml api, start the upnp thread */
+value
+ml_upnp_job_start( value unused )
+{
+       return Val_unit;
+}
+
+/** @brief ocaml api, stop the upnp thread */
+value
+ml_upnp_job_stop( value wait_v )
+{
+       return Val_unit;
+}
+
+value
+ml_upnpDumpMaps(value unused)
+{
+       return Val_unit;
+}
+
+value
+ml_upnpAddMap(value m_enabled, value m_intPort, value m_extPort, value m_type, 
value m_notes)
+{
+       return Val_unit;
+}
+
+value
+ml_upnpRemoveMap(value m_enabled, value m_intPort, value m_extPort, value 
m_type, value m_notes)
+{
+       return Val_unit;
+}
+
+value
+ml_upnpRemoveAllMaps(value wait_v)
+{
+       return Val_unit;
+}
+
+value
+ml_upnpGetMaps(value unused)
+{
+       return Val_emptylist;
+}
+
+#endif



reply via email to

[Prev in Thread] Current Thread [Next in Thread]