diff options
author | eroen <eroen@occam.eroen.eu> | 2013-01-22 02:01:11 +0100 |
---|---|---|
committer | eroen <eroen@occam.eroen.eu> | 2013-01-22 02:01:11 +0100 |
commit | 9eb4f2758059ff5d057d46187d3d2184ab272ac4 (patch) | |
tree | 99eeca3bac53b06f3fb42d42d375cdb08cb6b5c3 /net-p2p/transmission | |
parent | transmission: imported from portage (diff) | |
download | eroen-9eb4f2758059ff5d057d46187d3d2184ab272ac4.tar.gz eroen-9eb4f2758059ff5d057d46187d3d2184ab272ac4.tar.bz2 eroen-9eb4f2758059ff5d057d46187d3d2184ab272ac4.zip |
transmission-2.73: bind-to-interface patch
Diffstat (limited to 'net-p2p/transmission')
-rw-r--r-- | net-p2p/transmission/Manifest | 21 | ||||
-rw-r--r-- | net-p2p/transmission/files/.transmission-2.73-bind-to-interface.patch.swp | bin | 0 -> 20480 bytes | |||
-rw-r--r-- | net-p2p/transmission/files/transmission-2.73-bind-to-interface.patch | 2216 | ||||
-rw-r--r-- | net-p2p/transmission/files/transmission-2.73-build-failure.patch | 23 | ||||
-rw-r--r-- | net-p2p/transmission/metadata.xml | 1 | ||||
-rw-r--r-- | net-p2p/transmission/transmission-2.73.ebuild | 5 |
6 files changed, 2248 insertions, 18 deletions
diff --git a/net-p2p/transmission/Manifest b/net-p2p/transmission/Manifest index 5457de2..ba606d6 100644 --- a/net-p2p/transmission/Manifest +++ b/net-p2p/transmission/Manifest @@ -1,22 +1,9 @@ ------BEGIN PGP SIGNED MESSAGE----- -Hash: SHA256 - +AUX transmission-2.73-bind-to-interface.patch 74340 SHA256 4ad0b13c7d67a73b08f73ad7ad1158213c5cf48fbfa5c8ced020105770e0789f SHA512 af3e10772e4ccb8570faa45b3f124a51a595899fb3c4477d0a94bb5dbbc7cb020547023456202304b4c5545b8980016d50fa3fc311354bcd6468ea3a13362dd3 WHIRLPOOL c549ee119b725685ca38a611022ac08d971de64fe07d12cc80a26cca410020120676c8f76aaff2444252c75ed3fe81f210164fe2bf0abc711b404c6e30879b72 +AUX transmission-2.73-build-failure.patch 742 SHA256 9a871ce80697076d0de81b25c20686e3b05e0f6791cbdf263792ebd191f9178f SHA512 14ea7e17a084a04968de2de0c8284a87bb6fff6fb9e749c0631ab846a5206009593f2e2614bb1c1cd5f972b78d4fe6f8af56deea390e6d5c147de0b1b602bc2c WHIRLPOOL f8392a956f66e3673301dbbcb9e2c736a9035cff4fcea7e0bdc5976acab5ac6a14df1d7d4be6cdd0a95b72f452db850a41b269a8a9536fb86318b4fb2ecc090a AUX transmission-daemon.confd.3 703 SHA256 4b47acf195a14a322550cfcaa735a59aac38410d1c2c63ffa824ff131c55ca70 SHA512 a3b9ac2b7bbe30e33060c8b6a693dc7072d3c6ac44f92ddd567969d8f57a0bfc1a561e781ae167703ccb4b2fd5b0e6d8f8a66c5ba14fe01d8d89a501d4501474 WHIRLPOOL 41e2937a7bd03b6e667c991d122b8370d650dc8c26ed9e5825fe0e76aa68bb356171411e6057c44c1a51780f2f2d5eb23b8f3e1ad22a89836587944a8ef9e7c5 AUX transmission-daemon.initd.8 2247 SHA256 c4383a3380c7dac82941d073a3d52451ed6e1d6bf0969ea0fe3e86aa4b8cbe2e SHA512 bc27b582c02220fe1b771581a4ff7df4d8cbe39b778e1e30f9dd7f3ee6abd5114626cbdb3ede85a41ff80dce06c0f1d99ae45b00fafd16285301e70a25908547 WHIRLPOOL 69007d64bdc660e8cded35c229e1e20dd8cc68ae9d3d2b9a3980282e4ea180b16a223aafd75c0a177046dcbb5a25e9dd67cf69f604091b11f74e265b9e40df6d DIST transmission-2.73.tar.xz 2947316 SHA256 7907f47f6eabf63f25ecc63b388f2abd4ac82f61d7d827657681ec36ff1507f6 SHA512 d591d8f14eb10edc7773ed7e13c52c3172da9a511a34487030feb300d87e4e835f4d70c83e30b49d3a119c38ae987d571ba17a11c0db6b3c9dab15527185b686 WHIRLPOOL 59cfcff5f1f3b34c062d0d9685bc793e868259fc272b1618a28e5a3f245d86aed173df6fce8c6d9fa95e48a0d9c28758da5d7710e9884ee91982beaee3633798 DIST transmission-2.76.tar.xz 2954220 SHA256 02c8c47da5b5567f9018d4a1fdad585cff58d315bd2a544da71e7bd473853b33 SHA512 ccd45cf9889534df5551394f11934ce33420749247d7e8105d684fba8b4872cceddc763f873a4b98101486acc7f49fbcb96734cdb0fcd9bbc60bc1779f3ca591 WHIRLPOOL 88d5cbd16b32432af243827b9f48db27508b96df13df48acdd62fd9315b722436a686e0bc6c36633581523b5c136168b49fee7466b84e5e6e563d639b5c21933 -EBUILD transmission-2.73.ebuild 3899 SHA256 a0e2a603a8bae826cb0909d3ceffb82cfb535581e8b52c04a616f57d061fc2e5 SHA512 8825ddb8f0d41a0fff1d05a9a492f5df9af7e14b48ac90d982fa11e644c89a87f43940aace361998179291b98033e16616036701a88a93880da1f3f123fc676f WHIRLPOOL 95d577c1d4d455b323b8e87a4cfc29fe3bd47b9717b69813c6d0bdd802ab3385b61a07f929ed625ffc501725ad5506842df6f594e1eb8f73df325c87efee4ac8 +EBUILD transmission-2.73.ebuild 4086 SHA256 9ed1df3143ee926b15365d0816684141b80803108008bd17d7efbae2d098d479 SHA512 00d36fb9263789896bd18ecee82c3cf53d68de7fbb3d7407644adb624e1366c478d01d5d7b4b4b9c8963d6694befd21fe53cf6c53cc65fb390aeef00e70911e1 WHIRLPOOL 777f283c9a54c12aba314f8d0620421a0867898c0ca020242490d745ea163df6a0a64e2fc2e7238262cb9062145d1baa036887ddccbbed37f88dd84629f5d829 EBUILD transmission-2.76.ebuild 3217 SHA256 83736332fb58841df5eabd0809164ed0901261f85ecdb86d01e15d8f480e7e98 SHA512 bf524933389973995cd715f4fb369c8f6b056905bc5e9dffa8b53dae208844afdd7442093630adc1ac02366a26e530fa63bf0df8fcc242ad14449db972a58578 WHIRLPOOL 4a4a605861e12e027fb7a057d34eb3d29966944f58405e87dae071d99ecf179add25cc0543959667985113e0e8c87bf3f0c256b8d0b6785b5a1ab116173633dd -MISC ChangeLog 38593 SHA256 b0b093f7782394738a1aa6e3052d46ea974612d0e8f7f3ed67547fa97d0de190 SHA512 3733b2e09e234ee2e9e2edd177508d4d8075b362ead017e5e3c29ebfd0c36f1bd7b11b11d843d712082b74f5748c8b7042c14e89706d2cb0811575e318784a4a WHIRLPOOL 4a6ed16f38ce94881a1ddf7c3c9026241d31a4d9a2fce9692688dbe74d08bb5041eddb83372ec075946ff20eaa52daaaa3d6bcab1d618f5174729ea7764d507b -MISC metadata.xml 661 SHA256 5dadc7aff55c289bc229fdaeb2bf63475ad8c7ff8a523d7fdc4096e0755f2cff SHA512 239d8bfc15bc6d52c079f437f01cfec4ea23022e92a333f2758249644ed5327ec941a27110ce43b1fb2f80208a473c396f24215f1c8b18716dc4fd64427472f8 WHIRLPOOL 5099446a448ad86d10d456f23e08b0a09e8c76670641565f718b8f18cf0cf8eb1b916f71e52dbc58f36b4d4522c891009e37e0eef080817db5761c6d0ecf2816 ------BEGIN PGP SIGNATURE----- -Version: GnuPG v2.0.19 (GNU/Linux) - -iQEcBAEBCAAGBQJQ8lRCAAoJEEdUh39IaPFNcSoH/1ARzCWfLCPATKCXG7AjCCbh -Q+0/72iiEmzFNn8fzRcvGtEDm+KXOBMdpIQIls83XNQD4KQHd7MwPh62eKyZTreT -QmEP42d+YgOjCUMk+/utwv93t1J7FKciCE6CNlSKhJrMPsPNOzQe3huZGpnEEtX0 -Jejts8usdytQzP5Il2oxjXNQZtgUGa7Jkz4VKy9T1Kb+vUjF57LmPr0rhWSggUSH -CrBRGpzwUZiV85ar+4IxrBJy05j29I0Wh/QWGMRdzmLaS2crdaYH+ZZkTToetDe7 -NiLBOSoSPdSXcV7yAmS9Xbjr7qej7JXc+4EvjqhaCFdSVU/AruxYWi6O1hi9rpk= -=L6FF ------END PGP SIGNATURE----- +MISC metadata.xml 768 SHA256 a5382a2d73fe7fbd7c5fd2a8212430d5e4388c61b37d76590a256ae44ab86df0 SHA512 957d2d218f7191b2d07e8a7db0ea02edc2a1a3875389d9cd7f2262e6af10ef3fa1284926bc6a33b48d5979d777d7c21b3e0d7663eeafeb3b979dec601965a83b WHIRLPOOL edbc56d299631fbaaff437e06773dd6ebce265f64d3df5b48725a83372c40b2f4f8b5c50ad7584973fdccc2bb7ffda1c511fba41849a6664a8f2ba977b438ee5 diff --git a/net-p2p/transmission/files/.transmission-2.73-bind-to-interface.patch.swp b/net-p2p/transmission/files/.transmission-2.73-bind-to-interface.patch.swp Binary files differnew file mode 100644 index 0000000..ae0efca --- /dev/null +++ b/net-p2p/transmission/files/.transmission-2.73-bind-to-interface.patch.swp diff --git a/net-p2p/transmission/files/transmission-2.73-bind-to-interface.patch b/net-p2p/transmission/files/transmission-2.73-bind-to-interface.patch new file mode 100644 index 0000000..5a1fea7 --- /dev/null +++ b/net-p2p/transmission/files/transmission-2.73-bind-to-interface.patch @@ -0,0 +1,2216 @@ +bind to interface + +From: eroen <eroen@occam.eroen.eu> + +by: ThornsArcana +source: https://trac.transmissionbt.com/ticket/2313 + +ported from bind-to-interface-r12779-trunk.patch by eroen +--- + Transmission.xcodeproj/project.pbxproj | 9 + + configure.ac | 69 ++++++++ + gtk/tr-prefs.c | 10 + + libtransmission/Makefile.am | 9 + + libtransmission/fdlimit.c | 241 +++++++++++++++++++++++++-- + libtransmission/fdlimit.h | 5 + + libtransmission/net-interfaces-test.c | 101 +++++++++++ + libtransmission/net-interfaces.c | 183 ++++++++++++++++++++ + libtransmission/net-interfaces.h | 49 +++++ + libtransmission/net.c | 175 ++++++++++++++++++- + libtransmission/net.h | 16 ++ + libtransmission/peer-io.c | 30 +++ + libtransmission/peer-mgr.c | 2 + libtransmission/resolver.c | 157 +++++++++++++++++ + libtransmission/resolver.h | 71 ++++++++ + libtransmission/resume.c | 4 + libtransmission/session.c | 289 +++++++++++++++++++++++++++++++- + libtransmission/session.h | 7 + + libtransmission/tr-dht.h | 5 + + libtransmission/tr-lpd.c | 3 + libtransmission/tr-udp.c | 4 + libtransmission/tr-utp.c | 8 + + libtransmission/transmission.h | 1 + macosx/Controller.m | 2 + third-party/libutp/utp_config.h | 4 + 25 files changed, 1413 insertions(+), 41 deletions(-) + create mode 100644 libtransmission/net-interfaces-test.c + create mode 100644 libtransmission/net-interfaces.c + create mode 100644 libtransmission/net-interfaces.h + create mode 100644 libtransmission/resolver.c + create mode 100644 libtransmission/resolver.h + +diff --git a/Transmission.xcodeproj/project.pbxproj b/Transmission.xcodeproj/project.pbxproj +index 898278b..ed26f53 100644 +--- a/Transmission.xcodeproj/project.pbxproj ++++ b/Transmission.xcodeproj/project.pbxproj +@@ -59,6 +59,8 @@ + 4DF7500D08A103AD007B0D70 /* ToolbarInfoTemplate.png in Resources */ = {isa = PBXBuildFile; fileRef = 4DF7500808A103AD007B0D70 /* ToolbarInfoTemplate.png */; }; + 4DF7500E08A103AD007B0D70 /* ToolbarRemoveTemplate.png in Resources */ = {isa = PBXBuildFile; fileRef = 4DF7500908A103AD007B0D70 /* ToolbarRemoveTemplate.png */; }; + 4DFBC2DF09C0970D00D5C571 /* Torrent.m in Sources */ = {isa = PBXBuildFile; fileRef = 4DFBC2DE09C0970D00D5C571 /* Torrent.m */; }; ++ 68FE979E11C77CE800FE4F58 /* net-interfaces.h in Headers */ = {isa = PBXBuildFile; fileRef = 68FE979D11C77CE800FE4F58 /* net-interfaces.h */; }; ++ 68FE97A011C77D1200FE4F58 /* net-interfaces.c in Sources */ = {isa = PBXBuildFile; fileRef = 68FE979F11C77D1200FE4F58 /* net-interfaces.c */; }; + 8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */; }; + 8D11072D0486CEB800E47090 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; settings = {ATTRIBUTES = (); }; }; + 8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; }; +@@ -628,6 +630,8 @@ + 4DF7500908A103AD007B0D70 /* ToolbarRemoveTemplate.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = ToolbarRemoveTemplate.png; path = macosx/Images/ToolbarRemoveTemplate.png; sourceTree = "<group>"; }; + 4DFBC2DD09C0970D00D5C571 /* Torrent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Torrent.h; path = macosx/Torrent.h; sourceTree = "<group>"; }; + 4DFBC2DE09C0970D00D5C571 /* Torrent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Torrent.m; path = macosx/Torrent.m; sourceTree = "<group>"; }; ++ 68FE979D11C77CE800FE4F58 /* net-interfaces.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "net-interfaces.h"; path = "libtransmission/net-interfaces.h"; sourceTree = "<group>"; }; ++ 68FE979F11C77D1200FE4F58 /* net-interfaces.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "net-interfaces.c"; path = "libtransmission/net-interfaces.c"; sourceTree = "<group>"; }; + 8D1107310486CEB800E47090 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; name = Info.plist; path = macosx/Info.plist; sourceTree = "<group>"; }; + 8D1107320486CEB800E47090 /* Transmission.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Transmission.app; sourceTree = BUILT_PRODUCTS_DIR; }; + A200B8390A2263BA007BBB1E /* InfoWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = InfoWindowController.h; path = macosx/InfoWindowController.h; sourceTree = "<group>"; }; +@@ -1723,6 +1727,8 @@ + A2A4EA0A0DE106E8000CE197 /* ConvertUTF.c */, + A2A4EA0B0DE106E8000CE197 /* ConvertUTF.h */, + 4DB74F070E8CD75100AEB1A8 /* wildmat.c */, ++ 68FE979D11C77CE800FE4F58 /* net-interfaces.h */, ++ 68FE979F11C77D1200FE4F58 /* net-interfaces.c */, + ); + name = libtransmission; + sourceTree = "<group>"; +@@ -3169,6 +3175,7 @@ + "-DSYS_DARWIN", + "-DWITH_UTP", + "-DHAVE_OPENSSL", ++ "-DHAVE_SYSCTLBYNAME", + "-D__TRANSMISSION__", + "-DHAVE_STRLCPY", + "-DHAVE_STRLCAT", +@@ -3317,6 +3324,7 @@ + "-DSYS_DARWIN", + "-DWITH_UTP", + "-DHAVE_OPENSSL", ++ "-DHAVE_SYSCTLBYNAME", + "-D__TRANSMISSION__", + "-DHAVE_STRLCPY", + "-DHAVE_STRLCAT", +@@ -3498,6 +3506,7 @@ + "-DSYS_DARWIN", + "-DWITH_UTP", + "-DHAVE_OPENSSL", ++ "-DHAVE_SYSCTLBYNAME", + "-D__TRANSMISSION__", + "-DHAVE_STRLCPY", + "-DHAVE_STRLCAT", +diff --git a/configure.ac b/configure.ac +index c1931c3..1fe4a14 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -177,6 +177,75 @@ AC_CHECK_HEADERS([sys/statvfs.h \ + + dnl ---------------------------------------------------------------------------- + dnl ++dnl SO_BINDTODEVICE support ++ ++AC_CACHE_CHECK([whether setsockopt accepts SO_BINDTODEVICE], ++ [ac_cv_c_so_bindtodevice], ++ [CXXFLAGS="${save_CXXFLAGS} -Wall -Werror" ++ AC_TRY_COMPILE([#include <sys/types.h> ++ #include <sys/socket.h>], ++ [return SO_BINDTODEVICE;], ++ ac_cv_c_so_bindtodevice=yes, ac_cv_c_so_bindtodevice=no)]) ++if test x"$ac_cv_c_so_bindtodevice" != x"no"; then ++ AC_DEFINE(HAVE_SO_BINDTODEVICE, 1, Define if setsockopt accepts SO_BINDTODEVICE.) ++fi ++ ++dnl ---------------------------------------------------------------------------- ++dnl ++dnl SO_BINDTODEVICE enable/disable. ++ ++AC_ARG_ENABLE([bindtodevice], ++ AS_HELP_STRING([--enable-bindtodevice],[Enable bind to device support]), ++ [want_bindtodevice=${enableval}], ++ [want_bindtodevice=${ac_cv_c_so_bindtodevice}]) ++ ++if test x"$want_bindtodevice" = x"yes" ; then ++ if test x"$ac_cv_c_so_bindtodevice" != x"no"; then ++ AC_DEFINE(USE_SO_BINDTODEVICE, 1, Define as 1 if bind to device feature is enabled.) ++ else ++ AC_DEFINE(USE_SO_BINDTODEVICE, 0, Define as 0 if bind to device feature is disabled.) ++ fi ++fi ++ ++dnl ---------------------------------------------------------------------------- ++dnl ++dnl getifaddrs ++ ++AC_CACHE_CHECK([whether getifaddrs() exists], ++ [ac_cv_c_getifaddrs], ++ [CXXFLAGS="${save_CXXFLAGS} -Wall -Werror" ++ AC_TRY_COMPILE([#include <sys/types.h> ++ #include <sys/socket.h> ++ #include <ifaddrs.h>], ++ [{struct ifaddrs * pIfa; ++ return getifaddrs(&pIfa);}], ++ ac_cv_c_getifaddrs=yes, ac_cv_c_getifaddrs=no)]) ++if test x"$ac_cv_c_getifaddrs" != x"no"; then ++ AC_DEFINE(HAVE_GETIFADDRS, 1, Define if getifaddrs is available..) ++fi ++ ++dnl ---------------------------------------------------------------------------- ++dnl ++dnl libnetlink ++ ++AC_CACHE_CHECK([whether libnetlink is available (iproute-dev)], ++ [ac_cv_c_libnetlink], ++ [CXXFLAGS="${save_CXXFLAGS} -Wall -Werror" ++ AC_TRY_COMPILE([#include <sys/types.h> ++ #include <sys/socket.h> ++ #include <stdio.h> ++ #include <libnetlink.h>], ++ [{struct rtnl_handle rth; ++ return rtnl_open(&rth, RTNLGRP_IPV4_ROUTE);}], ++ ac_cv_c_libnetlink=yes, ac_cv_c_libnetlink=no)]) ++if test x"$ac_cv_c_libnetlink" != x"no"; then ++ AC_DEFINE(HAVE_LIBNETLINK, 1, Define if libnetlink is available..) ++ dnl THIS IS A HACK: ++ LIBS="$LIBS -lnetlink" ++fi ++ ++dnl ---------------------------------------------------------------------------- ++dnl + dnl dht + + DHT_CFLAGS="-I\$(top_srcdir)/third-party/dht" +diff --git a/gtk/tr-prefs.c b/gtk/tr-prefs.c +index cc6ac6f..0caff40 100644 +--- a/gtk/tr-prefs.c ++++ b/gtk/tr-prefs.c +@@ -19,6 +19,9 @@ + #include <libtransmission/transmission.h> + #include <libtransmission/utils.h> + #include <libtransmission/version.h> ++#include <sys/time.h> /* getrlimit */ ++#include <sys/resource.h> /* getrlimit */ ++ + #include "conf.h" + #include "hig.h" + #include "tr-core.h" +@@ -1192,6 +1195,9 @@ networkPage( GObject * core ) + const char * s; + struct network_page_data * data; + guint row = 0; ++ struct rlimit limit; ++ ++ getrlimit( RLIMIT_NOFILE, &limit ); + + /* register to stop listening to core prefs changes when the page is destroyed */ + data = g_new0( struct network_page_data, 1 ); +@@ -1227,9 +1233,9 @@ networkPage( GObject * core ) + hig_workarea_add_section_divider( t, &row ); + hig_workarea_add_section_title( t, &row, _( "Peer Limits" ) ); + +- w = new_spin_button( TR_PREFS_KEY_PEER_LIMIT_TORRENT, core, 1, FD_SETSIZE, 5 ); ++ w = new_spin_button( TR_PREFS_KEY_PEER_LIMIT_TORRENT, core, 1, limit.rlim_max, 5 ); + hig_workarea_add_row( t, &row, _( "Maximum peers per _torrent:" ), w, NULL ); +- w = new_spin_button( TR_PREFS_KEY_PEER_LIMIT_GLOBAL, core, 1, FD_SETSIZE, 5 ); ++ w = new_spin_button( TR_PREFS_KEY_PEER_LIMIT_GLOBAL, core, 1, limit.rlim_max, 5 ); + hig_workarea_add_row( t, &row, _( "Maximum peers _overall:" ), w, NULL ); + + hig_workarea_add_section_divider( t, &row ); +diff --git a/libtransmission/Makefile.am b/libtransmission/Makefile.am +index aaa7412..cb9a67e 100644 +--- a/libtransmission/Makefile.am ++++ b/libtransmission/Makefile.am +@@ -41,12 +41,14 @@ libtransmission_a_SOURCES = \ + metainfo.c \ + natpmp.c \ + net.c \ ++ net-interfaces.c \ + peer-io.c \ + peer-mgr.c \ + peer-msgs.c \ + platform.c \ + port-forwarding.c \ + ptrarray.c \ ++ resolver.c \ + resume.c \ + rpcimpl.c \ + rpc-server.c \ +@@ -93,6 +95,7 @@ noinst_HEADERS = \ + metainfo.h \ + natpmp_local.h \ + net.h \ ++ net-interfaces.h \ + peer-common.h \ + peer-io.h \ + peer-mgr.h \ +@@ -100,6 +103,7 @@ noinst_HEADERS = \ + platform.h \ + port-forwarding.h \ + ptrarray.h \ ++ resolver.h \ + resume.h \ + rpcimpl.h \ + rpc-server.h \ +@@ -129,6 +133,7 @@ TESTS = \ + json-test \ + magnet-test \ + metainfo-test \ ++ net-interfaces-test \ + peer-msgs-test \ + rpc-test \ + test-peer-id \ +@@ -184,6 +189,10 @@ peer_msgs_test_SOURCES = peer-msgs-test.c + peer_msgs_test_LDADD = ${apps_ldadd} + peer_msgs_test_LDFLAGS = ${apps_ldflags} + ++net_interfaces_test_SOURCES = net-interfaces-test.c ++net_interfaces_test_LDADD = ${apps_ldadd} ++net_interfaces_test_LDFLAGS = ${apps_ldflags} ++ + rpc_test_SOURCES = rpc-test.c + rpc_test_LDADD = ${apps_ldadd} + rpc_test_LDFLAGS = ${apps_ldflags} +diff --git a/libtransmission/fdlimit.c b/libtransmission/fdlimit.c +index 58fd60e..2e92abb 100644 +--- a/libtransmission/fdlimit.c ++++ b/libtransmission/fdlimit.c +@@ -40,6 +40,8 @@ + #include <sys/resource.h> /* getrlimit */ + #include <fcntl.h> /* O_LARGEFILE posix_fadvise */ + #include <unistd.h> /* lseek(), write(), ftruncate(), pread(), pwrite(), etc */ ++#include <stdlib.h> ++#include <stdio.h> + + #include "transmission.h" + #include "fdlimit.h" +@@ -71,6 +73,204 @@ + #define O_SEQUENTIAL 0 + #endif + ++struct tr_fileset ++{ ++ struct tr_cached_file * begin; ++ const struct tr_cached_file * end; ++}; ++ ++struct tr_fdInfo ++{ ++ int peerCount; ++ struct tr_fileset fileset; ++}; ++ ++/* track activity on open file handles */ ++typedef struct OpenHandleTracker_t ++{ ++ int fd; ++ uint64_t inBytes; ++ uint64_t outBytes; ++ clock_t lastActivity; ++} TOpenHandleTracker; ++ ++static TOpenHandleTracker * g_OpenTracker = NULL; ++size_t g_OpenTrackerSize = 0; ++ ++bool tr_fdtrack_add(tr_session * session, int fd) ++{ ++ bool added = false; ++ size_t index; ++ ++ if (NULL == g_OpenTracker) ++ { ++ size_t bytes; ++ g_OpenTrackerSize = session->peerLimit; ++ ++ bytes = g_OpenTrackerSize * sizeof(TOpenHandleTracker); ++ ++ g_OpenTracker = malloc(bytes); ++ memset(g_OpenTracker, 0, bytes); ++ for(index = 0; index < g_OpenTrackerSize; index++) ++ { ++ g_OpenTracker[index].fd = -1; ++ } ++ } ++ ++ if (g_OpenTracker) ++ { ++ if (g_OpenTrackerSize < session->peerLimit) ++ { ++ size_t bytes = session->peerLimit * sizeof(TOpenHandleTracker); ++ TOpenHandleTracker * tmp = realloc(g_OpenTracker, bytes); ++ if (tmp) ++ { ++ /* realloc successful */ ++ for (index = g_OpenTrackerSize; index < session->peerLimit; index++) ++ { ++ tmp[index].fd = -1; ++ tmp[index].lastActivity = 0; ++ tmp[index].inBytes = 0; ++ tmp[index].outBytes = 0; ++ } ++ g_OpenTracker = tmp; ++ g_OpenTrackerSize = session->peerLimit; ++ } ++ } ++ } ++ ++ if (g_OpenTracker) ++ { ++ for(index = 0; index < g_OpenTrackerSize; index++) ++ { ++ if (-1 == g_OpenTracker[index].fd) ++ { ++ g_OpenTracker[index].fd = fd; ++ g_OpenTracker[index].lastActivity = clock(); ++ g_OpenTracker[index].inBytes = 0; ++ g_OpenTracker[index].outBytes = 0; ++ added = true; ++ break; ++ } ++ } ++ } ++ return added; ++} ++ ++bool tr_fdtrack_input(int fd, uint64_t inCount) ++{ ++ bool found = false; ++ size_t index; ++ ++ for (index = 0; index < g_OpenTrackerSize; index++) ++ { ++ if (fd == g_OpenTracker[index].fd) ++ { ++ g_OpenTracker[index].fd = fd; ++ g_OpenTracker[index].lastActivity = clock(); ++ g_OpenTracker[index].inBytes += inCount; ++ found = true; ++ break; ++ } ++ } ++ return found; ++} ++ ++bool tr_fdtrack_output(int fd, uint64_t outCount) ++{ ++ bool found = false; ++ size_t index; ++ ++ for (index = 0; index < g_OpenTrackerSize; index++) ++ { ++ if (fd == g_OpenTracker[index].fd) ++ { ++ g_OpenTracker[index].fd = fd; ++ g_OpenTracker[index].lastActivity = clock(); ++ g_OpenTracker[index].outBytes += outCount; ++ found = true; ++ break; ++ } ++ } ++ return found; ++} ++ ++bool tr_fdtrack_close(int fd) ++{ ++ bool found = false; ++ size_t index; ++ ++ for (index = 0; index < g_OpenTrackerSize; index++) ++ { ++ if (fd == g_OpenTracker[index].fd) ++ { ++ g_OpenTracker[index].fd = -1; ++ g_OpenTracker[index].lastActivity = 0; ++ g_OpenTracker[index].inBytes = 0; ++ g_OpenTracker[index].outBytes = 0; ++ found = true; ++ break; ++ } ++ } ++ return found; ++} ++ ++int tr_fdtrack_cleanup(tr_session * session, int secs) ++{ ++ bool cleanup = 0; ++ clock_t inClock = CLOCKS_PER_SEC * secs; ++ clock_t now = clock(); ++ ++ if (now > inClock) ++ { ++ clock_t noActivitySince = now - inClock; ++ size_t index; ++ struct tr_fdInfo * gFd = session->fdInfo; ++ size_t idxOldest = g_OpenTrackerSize; ++ clock_t clkOldest = now; ++ ++ for (index = 0; index < g_OpenTrackerSize; index++) ++ { ++ if (-1 != g_OpenTracker[index].fd) ++ { ++ if (g_OpenTracker[index].lastActivity < clkOldest) ++ { ++ clkOldest = g_OpenTracker[index].lastActivity; ++ idxOldest = index; ++ } ++ ++ if (g_OpenTracker[index].lastActivity <= noActivitySince) ++ { ++ close(g_OpenTracker[index].fd); ++ fprintf(stderr, "%d\tclose\tcleanup\n", g_OpenTracker[index].fd ); ++ ++ g_OpenTracker[index].fd = -1; ++ g_OpenTracker[index].lastActivity = 0; ++ g_OpenTracker[index].inBytes = 0; ++ g_OpenTracker[index].outBytes = 0; ++ cleanup++; ++ gFd->peerCount--; ++ } ++ } ++ } ++ ++ if ( 0 == cleanup && idxOldest < g_OpenTrackerSize ) ++ { ++ index = idxOldest; ++ close(g_OpenTracker[index].fd); ++ fprintf(stderr, "%d\tclose\tcleanup\n", g_OpenTracker[index].fd ); ++ ++ g_OpenTracker[index].fd = -1; ++ g_OpenTracker[index].lastActivity = 0; ++ g_OpenTracker[index].inBytes = 0; ++ g_OpenTracker[index].outBytes = 0; ++ cleanup++; ++ gFd->peerCount--; ++ } ++ } ++ return cleanup; ++} ++ + + static bool + preallocate_file_sparse( int fd, uint64_t length ) +@@ -413,12 +613,6 @@ cached_file_open( struct tr_cached_file * o, + **** + ***/ + +-struct tr_fileset +-{ +- struct tr_cached_file * begin; +- const struct tr_cached_file * end; +-}; +- + static void + fileset_construct( struct tr_fileset * set, int n ) + { +@@ -506,12 +700,6 @@ fileset_get_empty_slot( struct tr_fileset * set ) + **** + ***/ + +-struct tr_fdInfo +-{ +- int peerCount; +- struct tr_fileset fileset; +-}; +- + static void + ensureSessionFdInfoExists( tr_session * session ) + { +@@ -531,6 +719,7 @@ ensureSessionFdInfoExists( tr_session * session ) + /* set the open-file limit to the largest safe size wrt FD_SETSIZE */ + if( !getrlimit( RLIMIT_NOFILE, &limit ) ) + { ++#if 0 + const int old_limit = (int) limit.rlim_cur; + const int new_limit = MIN( limit.rlim_max, FD_SETSIZE ); + if( new_limit != old_limit ) +@@ -540,6 +729,9 @@ ensureSessionFdInfoExists( tr_session * session ) + getrlimit( RLIMIT_NOFILE, &limit ); + tr_inf( "Changed open file limit from %d to %d", old_limit, (int)limit.rlim_cur ); + } ++#else ++ limit.rlim_cur = limit.rlim_max; ++#endif + } + } + } +@@ -676,10 +868,28 @@ tr_fdSocketCreate( tr_session * session, int domain, int type ) + ensureSessionFdInfoExists( session ); + gFd = session->fdInfo; + +- if( gFd->peerCount < session->peerLimit ) ++ if(session->peerLimit < 100) ++ { ++ fprintf(stderr, "Peer Limit minimum of ~250. Est overhead is 100 file handles\n"); ++ } ++ ++ assert(session->peerLimit >= 100); ++ ++ if (gFd->peerCount >= (session->peerLimit - 100)) ++ { ++ fprintf(stderr, "peerCount %d < peerLimit %d - 100\n", gFd->peerCount, session->peerLimit ); ++ /* cleanup connects that have been idle for 2 minutes or more */ ++ tr_fdtrack_cleanup(session, 120); ++ } ++ ++ if( gFd->peerCount < (session->peerLimit - 100) ) ++ { + if(( s = socket( domain, type, 0 )) < 0 ) ++ { + if( sockerrno != EAFNOSUPPORT ) + tr_err( _( "Couldn't create socket: %s" ), tr_strerror( sockerrno ) ); ++ } ++ } + + if( s > -1 ) + ++gFd->peerCount; +@@ -699,6 +909,8 @@ tr_fdSocketCreate( tr_session * session, int domain, int type ) + getsockopt( s, SOL_SOCKET, SO_RCVBUF, &i, &size ); + tr_dbg( "SO_RCVBUF size is %d", i ); + } ++ tr_netBindSocketInterface(session, s); ++ tr_fdtrack_add(session, s); + } + + return s; +@@ -724,10 +936,11 @@ tr_fdSocketAccept( tr_session * s, int sockfd, tr_address * addr, tr_port * port + + if( fd >= 0 ) + { +- if( ( gFd->peerCount < s->peerLimit ) ++ if( ( gFd->peerCount < (s->peerLimit - 100) ) + && tr_address_from_sockaddr_storage( addr, port, &sock ) ) + { + ++gFd->peerCount; ++ tr_fdtrack_add(s, fd); + } + else + { +diff --git a/libtransmission/fdlimit.h b/libtransmission/fdlimit.h +index 0b01190..15b8df5 100644 +--- a/libtransmission/fdlimit.h ++++ b/libtransmission/fdlimit.h +@@ -40,6 +40,11 @@ ssize_t tr_pread(int fd, void *buf, size_t count, off_t offset); + ssize_t tr_pwrite(int fd, const void *buf, size_t count, off_t offset); + int tr_prefetch(int fd, off_t offset, size_t count); + ++bool tr_fdtrack_add(tr_session * session, int fd); ++bool tr_fdtrack_input(int fd, uint64_t inCount); ++bool tr_fdtrack_output(int fd, uint64_t outCount); ++bool tr_fdtrack_close(int fd); ++int tr_fdtrack_cleanup(tr_session * session, int secs); + + /** + * Returns an fd to the specified filename. +diff --git a/libtransmission/net-interfaces-test.c b/libtransmission/net-interfaces-test.c +new file mode 100644 +index 0000000..e719e23 +--- /dev/null ++++ b/libtransmission/net-interfaces-test.c +@@ -0,0 +1,101 @@ ++#include <stdio.h> ++#include <string.h> ++ ++#include "net-interfaces.h" ++#include "utils.h" ++ ++#define VERBOSE 1 ++// #undef VERBOSE ++ ++#ifdef VERBOSE ++ #define check( A ) \ ++ { \ ++ ++test; \ ++ if( A ){ \ ++ fprintf( stderr, "PASS test #%d (%s, %d)\n", test, __FILE__, __LINE__ ); \ ++ } else { \ ++ fprintf( stderr, "FAIL test #%d (%s, %d)\n", test, __FILE__, __LINE__ ); \ ++ return test; \ ++ } \ ++ } ++#else ++ #define check( A ) \ ++ { \ ++ ++test; \ ++ if( !( A ) ){ \ ++ fprintf( stderr, "FAIL test #%d (%s, %d)\n", test, __FILE__, __LINE__ ); \ ++ return test; \ ++ } \ ++ } ++#endif ++ ++#define info( ... ) \ ++ do { \ ++ tr_msg( __FILE__, __LINE__, TR_MSG_INF, NULL, __VA_ARGS__ ); \ ++ } while( 0 ) ++ ++ ++static void tr_list_interfaces( tr_interface ** interfaces ); ++static void tr_list_interface( tr_interface * interface ); ++ ++static void tr_list_interface( tr_interface * interface ) ++{ ++ char buf[INET6_ADDRSTRLEN]; ++ ++ info("%s:",interface->name); ++ info(" name = %s",interface->name); ++ ++ if (interface->af4) ++ { ++ tr_address_to_string_with_buf(&interface->ipv4, buf, sizeof(buf)); ++ info(" ipv4 = %s", buf); ++ } ++ if (interface->af6) ++ { ++ tr_address_to_string_with_buf(&interface->ipv6, buf, sizeof(buf)); ++ info(" ipv6 = %s", buf); ++ } ++ info(" "); ++} ++ ++static void tr_list_interfaces( tr_interface ** interfaces ) ++{ ++ if (interfaces) ++ { ++ int index; ++ for( index = 0; interfaces[index]; index++ ) ++ { ++ tr_interface * interface = interfaces[index]; ++ tr_list_interface( interface ); ++ } ++ } ++ return; ++} ++ ++static int ++test1( void ) ++{ ++ tr_interface ** interfaces; ++ ++ info("Network interfaces test..."); ++ info(" "); ++ interfaces = tr_net_interfaces(); ++ tr_list_interfaces(interfaces); ++ tr_interfacesFree(interfaces); ++ info("Done."); ++ return 0; ++} ++ ++int ++main( void ) ++{ ++ int i; ++ ++ if( ( i = test1( ) ) ) ++ return i; ++ ++#ifdef VERBOSE ++ fprintf( stderr, "net-interfaces-test passed\n" ); ++#endif ++ return 0; ++} +diff --git a/libtransmission/net-interfaces.c b/libtransmission/net-interfaces.c +new file mode 100644 +index 0000000..82ccb56 +--- /dev/null ++++ b/libtransmission/net-interfaces.c +@@ -0,0 +1,183 @@ ++/****************************************************************************** ++ * ++ * $Id$ ++ * ++ * Copyright (c) 2005-2011 Transmission authors and contributors ++ * ++ * 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. ++ *****************************************************************************/ ++ ++#include "net-interfaces.h" ++#include "utils.h" ++#include "list.h" ++ ++#include <stdlib.h> ++#include <sys/types.h> ++#include <sys/socket.h> ++#include <netinet/in.h> ++#include <arpa/inet.h> ++#include <net/if.h> ++#include <strings.h> ++ ++#if defined(HAVE_GETIFADDRS) ++ #include <ifaddrs.h> ++#endif ++ ++#include <errno.h> ++ ++#if defined(HAVE_GETIFADDRS) ++ static tr_interface ** tr_net_getinterfaces(void); ++#else ++ static tr_interface ** tr_net_dummy_interfaces(void); ++#endif ++ ++tr_interface * tr_FindInterfaceByName(tr_interface **interfaces, char * device) ++{ ++ tr_interface * found = NULL; ++ if (interfaces) ++ { ++ int entry; ++ for(entry = 0; interfaces[entry]; entry++) ++ { ++ tr_interface * test = interfaces[entry]; ++ if( 0 == strcasecmp( test->name, device ) ) ++ { ++ found = test; ++ break; ++ } ++ } ++ } ++ return found; ++} ++ ++void tr_interfacesFree( tr_interface ** interfaces ) ++{ ++ if (interfaces) ++ { ++ int entry; ++ for(entry = 0; interfaces[entry]; entry++) ++ { ++ tr_free(interfaces[entry]); ++ } ++ } ++ tr_free(interfaces); ++} ++ ++tr_interface ** tr_net_interfaces() ++{ ++#if defined(HAVE_GETIFADDRS) ++ return tr_net_getinterfaces(); ++#else ++ return tr_net_dummy_interfaces(); ++#endif ++} ++ ++#if defined(HAVE_GETIFADDRS) ++static void tr_MergeOrAppendToInterfaces(tr_interface **interfaces, struct ifaddrs * ifa); ++ ++static void tr_MergeOrAppendToInterfaces(tr_interface **interfaces, struct ifaddrs * ifa) ++{ ++ if (interfaces) ++ { ++ tr_interface * merge = tr_FindInterfaceByName(interfaces, ifa->ifa_name); ++ ++ if (merge == NULL) ++ { ++ int entry; ++ for(entry = 0; interfaces[entry]; entry++) ++ { ++ } ++ interfaces[entry] = tr_new0(tr_interface, 1); ++ merge = interfaces[entry]; ++ // Name. ++ tr_strlcpy(merge->name, ifa->ifa_name, sizeof(merge->name)); ++ } ++ ++ if (merge) ++ { ++ if (ifa->ifa_addr->sa_family == AF_INET) ++ { ++ struct sockaddr_in * s4 = (struct sockaddr_in *)(ifa->ifa_addr); ++ ++ merge->af4 = ifa->ifa_addr->sa_family; ++ merge->ipv4.type = TR_AF_INET; ++ merge->ipv4.addr.addr4 = s4->sin_addr; ++ } ++ else if (ifa->ifa_addr->sa_family == AF_INET6) ++ { ++ struct sockaddr_in6 * s6 = (struct sockaddr_in6 *)(ifa->ifa_addr); ++ ++ merge->af6 = ifa->ifa_addr->sa_family; ++ merge->ipv6.type = TR_AF_INET6; ++ merge->ipv6.addr.addr6 = s6->sin6_addr; ++ } ++ } ++ } ++} ++ ++static tr_interface ** tr_net_getinterfaces(void) ++{ ++ tr_interface ** interfaces = NULL; ++ int ifcount = 0; ++ ++ struct ifaddrs *myaddrs, *ifa; ++ int status; ++ ++ status = getifaddrs(&myaddrs); ++ if (status != 0) ++ { ++ tr_err( _( "getifaddrs error: \'%s\' (%d)" ), tr_strerror(errno), errno ); ++ } ++ ++ for (ifa = myaddrs; ifa != NULL; ifa = ifa->ifa_next) ++ { ++ if ( (ifa->ifa_addr != NULL) // has address ++ && (ifa->ifa_flags & IFF_UP)) // iface is up. ++ { ++ ifcount++; ++ } ++ } ++ ++ if (ifcount > 0) ++ { ++ // treat as a null terminated array of interfaces ++ interfaces = tr_new0( tr_interface *, ifcount + 1 ); ++ for (ifa = myaddrs; ifa != NULL; ifa = ifa->ifa_next) ++ { ++ if ( (ifa->ifa_addr != NULL) // has address ++ && (ifa->ifa_flags & IFF_UP)) // iface is up. ++ { ++ tr_MergeOrAppendToInterfaces(interfaces, ifa); ++ } ++ } ++ } ++ freeifaddrs(myaddrs); ++ ++ return interfaces; ++} ++ ++#else // HAVE_GETIFADDRS ++ ++tr_interface ** tr_net_dummy_interfaces(void) ++{ ++ // Is there a port of getifaddrs for win32? ++ return NULL; ++} ++ ++#endif +diff --git a/libtransmission/net-interfaces.h b/libtransmission/net-interfaces.h +new file mode 100644 +index 0000000..9fdfa9c +--- /dev/null ++++ b/libtransmission/net-interfaces.h +@@ -0,0 +1,49 @@ ++/****************************************************************************** ++ * $Id$ ++ * ++ * Copyright (c) 2005-2008 Transmission authors and contributors ++ * ++ * 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. ++ *****************************************************************************/ ++ ++#ifndef __TRANSMISSION__ ++#error only libtransmission should #include this header. ++#endif ++#include "net.h" ++ ++#ifndef _TR_NET_INTERFACES_H_ ++#define _TR_NET_INTERFACES_H_ ++ ++#include <net/if.h> ++ ++typedef struct tr_interface ++{ ++ char name[IF_NAMESIZE]; ++ unsigned short int af4; ++ unsigned short int af6; ++ tr_address ipv4; ++ tr_address ipv6; ++} tr_interface; ++ ++tr_interface ** tr_net_interfaces( void ); ++void tr_interfacesFree( tr_interface ** interfaces ); ++tr_interface * tr_FindInterfaceByName(tr_interface **interfaces, char * device); ++ ++ ++#endif // _TR_NET_INTERFACES_H_ +diff --git a/libtransmission/net.c b/libtransmission/net.c +index eb05de6..18ba7c5 100644 +--- a/libtransmission/net.c ++++ b/libtransmission/net.c +@@ -34,6 +34,9 @@ + #include <ws2tcpip.h> + #else + #include <netinet/tcp.h> /* TCP_CONGESTION */ ++ #include <sys/ioctl.h> ++ #include <net/if.h> ++ #include <unistd.h> + #endif + + #include <event2/util.h> +@@ -55,6 +58,43 @@ + const tr_address tr_in6addr_any = { TR_AF_INET6, { IN6ADDR_ANY_INIT } }; + const tr_address tr_inaddr_any = { TR_AF_INET, { { { { INADDR_ANY, 0x00, 0x00, 0x00 } } } } }; + ++const char * ++tr_netGetAddress( const char * node, const char * service, tr_address * addr ) ++{ ++ struct addrinfo hints, * res, * p; ++ struct sockaddr_storage * ss; ++ int rv, family = AF_UNSPEC; ++ const char * err = NULL; ++ ++ if( !addr ) ++ return _( "Invalid address argument" ); ++ ++ memset( &hints, 0, sizeof( hints ) ); ++ if( addr->type == TR_AF_INET ) ++ family = AF_INET; ++ else if( addr->type == TR_AF_INET6 ) ++ family = AF_INET6; ++ hints.ai_family = family; ++ ++ if( ( rv = getaddrinfo( node, service, &hints, &res ) ) != 0 ) ++ return gai_strerror( rv ); ++ ++ for( p = res; p; p = p->ai_next ) ++ { ++ if( family != AF_UNSPEC && p->ai_family != family ) ++ continue; ++ ss = (struct sockaddr_storage *) p->ai_addr; ++ // assert(p->ai_addrlen == sizeof( struct sockaddr_in )); ++ tr_address_from_sockaddr_storage( addr, NULL, ss ); ++ break; ++ } ++ ++ if( p == NULL ) ++ err = _( "No matching addresses found" ); ++ freeaddrinfo( res ); ++ return err; ++} ++ + void + tr_netInit( void ) + { +@@ -166,6 +206,46 @@ tr_netSetCongestionControl( int s UNUSED, const char *algorithm UNUSED ) + #endif + } + ++void ++tr_netBindSocketInterface(tr_session *session, int socket) ++{ ++#ifdef USE_SO_BINDTODEVICE ++ if ( socket >= 0 && session->publicInterface != NULL ) ++ { ++ /* ++ * Using the ifreq struct with setsockopt seems reasonably common ++ * among the POSIX and POSIX like platforms. ++ * The linux manpage here: http://linux.die.net/man/7/socket says: ++ * ""The passed option is a variable-length null terminated ++ * interface name string with the maximum size of IFNAMSIZ."" ++ * ++ * The ifreq structure contains, as it's first element, ifr_name ++ * of size IFNAMSIZ. ++ * ++ * If you find that you do not have net/if.h or the ifreq structure ++ * but you do have SO_BINDTODEVICE then you may just pass null ++ * terminated string. IFNAMSIZ is 16, quite long as net devices ++ * tend to be named eth0, eth0:1, ppp0, etc. ++ * ++ * For size you can pass either IFNAMSIZ, sizeof(struct ifreq), or the ++ * number of bytes in session->publicInterface plus the '\0'. ++ */ ++ struct ifreq request; ++ ++ memset(&request, 0, sizeof(request)); ++ tr_strlcpy(request.ifr_name, session->publicInterface, IFNAMSIZ); ++ if ( setsockopt(socket, SOL_SOCKET, SO_BINDTODEVICE, ++ &request, IFNAMSIZ) < 0 ) ++ { ++ int eno = sockerrno; ++ tr_err( _( "Bind socket to device \'%s\' error: \'%s\' (%d)" ), ++ session->publicInterface, tr_strerror(eno), eno ); ++ } ++ } ++#endif ++} ++ ++ + bool + tr_address_from_sockaddr_storage( tr_address * setme_addr, + tr_port * setme_port, +@@ -245,6 +325,10 @@ tr_netOpenPeerSocket( tr_session * session, + if( s < 0 ) + return -1; + ++ ++ ++ tr_netBindSocketInterface(session, s); ++ + /* seeds don't need much of a read buffer... */ + if( clientIsSeed ) { + int n = 8192; +@@ -309,7 +393,7 @@ tr_netOpenPeerUTPSocket( tr_session * session, + } + + static int +-tr_netBindTCPImpl( const tr_address * addr, tr_port port, bool suppressMsgs, int * errOut ) ++tr_netBindTCPImpl( tr_session * session, const tr_address * addr, tr_port port, bool suppressMsgs, int * errOut ) + { + static const int domains[NUM_TR_AF_INET_TYPES] = { AF_INET, AF_INET6 }; + struct sockaddr_storage sock; +@@ -334,6 +418,7 @@ tr_netBindTCPImpl( const tr_address * addr, tr_port port, bool suppressMsgs, int + optval = 1; + setsockopt( fd, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval) ); + setsockopt( fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval) ); ++ tr_netBindSocketInterface(session, fd); + + #ifdef IPV6_V6ONLY + if( addr->type == TR_AF_INET6 ) +@@ -382,14 +467,14 @@ tr_netBindTCPImpl( const tr_address * addr, tr_port port, bool suppressMsgs, int + } + + int +-tr_netBindTCP( const tr_address * addr, tr_port port, bool suppressMsgs ) ++tr_netBindTCP( tr_session * session, const tr_address * addr, tr_port port, bool suppressMsgs ) + { + int unused; +- return tr_netBindTCPImpl( addr, port, suppressMsgs, &unused ); ++ return tr_netBindTCPImpl( session, addr, port, suppressMsgs, &unused ); + } + + bool +-tr_net_hasIPv6( tr_port port ) ++tr_net_hasIPv6( tr_session * session, tr_port port ) + { + static bool result = false; + static bool alreadyDone = false; +@@ -397,7 +482,7 @@ tr_net_hasIPv6( tr_port port ) + if( !alreadyDone ) + { + int err; +- int fd = tr_netBindTCPImpl( &tr_in6addr_any, port, true, &err ); ++ int fd = tr_netBindTCPImpl( session, &tr_in6addr_any, port, true, &err ); + if( fd >= 0 || err != EAFNOSUPPORT ) /* we support ipv6 */ + result = true; + if( fd >= 0 ) +@@ -428,6 +513,7 @@ void + tr_netCloseSocket( int fd ) + { + evutil_closesocket( fd ); ++ tr_fdtrack_close(fd); + } + + void +@@ -643,9 +729,78 @@ isMartianAddr( const struct tr_address * a ) + bool + tr_address_is_valid_for_peers( const tr_address * addr, tr_port port ) + { +- return ( port != 0 ) +- && ( tr_address_is_valid( addr ) ) +- && ( !isIPv6LinkLocalAddress( addr ) ) +- && ( !isIPv4MappedAddress( addr ) ) +- && ( !isMartianAddr( addr ) ); ++ return ( port != 0 ) && ( tr_isValidTrackerAddress( addr ) ); ++} ++ ++bool ++tr_isValidTrackerAddress( const tr_address * addr ) ++{ ++ return tr_isAddress( addr ) ++ && !isIPv6LinkLocalAddress( addr ) ++ && !isIPv4MappedAddress( addr ) ++ && !isMartianAddr( addr ); ++} ++ ++bool isAvailableBindAddress(tr_address * address, enum tr_address_type addrType) ++{ ++ bool rval = false; ++ int s; ++ int bindResult = 0; ++ static socklen_t sourcelen; ++ struct sockaddr_storage source_sock; ++ sourcelen = setup_sockaddr( address, 0, &source_sock ); ++ ++ s = socket( (int)addrType, SOCK_DGRAM, 0 ); ++ if (s >= 0) ++ { ++ bindResult = bind( s, (struct sockaddr*)&source_sock, sourcelen ); ++ if(0 == bindResult) ++ { ++ rval = true; ++ } ++ else if (EADDRNOTAVAIL == errno) ++ { ++ rval = false; ++ } ++ else ++ { ++ int bindErr = errno; ++ ++ tr_nerr("isAvailableBindAddress", "bind() probe gave an unhandled error code %i", bindErr); ++ tr_nerr("isAvailableBindAddress", "assuming that the address (may otherwise at other times) be bind()'able"); ++ rval = true; ++ } ++ close(s); ++ } ++ return rval; + } ++ ++/* ++ * Attempt to create a dummy private address that will disable traffic. ++ */ ++tr_address * unavailableBindAddress(enum tr_address_type addrType) ++{ ++ int i; ++ tr_address * testAddr = tr_new0( tr_address, 1 ); ++ ++ switch (addrType) ++ { ++ case TR_AF_INET: tr_address_from_string( testAddr, "1.2.3.4" ); break; ++ case TR_AF_INET6: tr_address_from_string( testAddr, "fd7f:54eb:9f51:be9a:1:2:3:4" ); break; ++ default: return testAddr; ++ } ++ ++ i = 100; ++ while( isAvailableBindAddress(testAddr, addrType) && i < 100 ) ++ { ++ switch (addrType) ++ { ++ case TR_AF_INET: testAddr->addr.addr4.s_addr += 1; break; ++ case TR_AF_INET6: testAddr->addr.addr6.s6_addr[0] -= 1; break; ++ default: return testAddr; ++ } ++ i++; ++ } ++ return testAddr; ++} ++ +diff --git a/libtransmission/net.h b/libtransmission/net.h +index 09e1095..faa77c1 100644 +--- a/libtransmission/net.h ++++ b/libtransmission/net.h +@@ -25,6 +25,7 @@ + #ifndef __TRANSMISSION__ + #error only libtransmission should #include this header. + #endif ++#include "transmission.h" + + #ifndef _TR_NET_H_ + #define _TR_NET_H_ +@@ -81,6 +82,8 @@ typedef struct tr_address + extern const tr_address tr_inaddr_any; + extern const tr_address tr_in6addr_any; + ++const char* tr_netGetAddress( const char * node, const char * service, tr_address * addr ); ++ + const char* tr_address_to_string( const tr_address * addr ); + + const char* tr_address_to_string_with_buf( const tr_address * addr, +@@ -89,6 +92,12 @@ const char* tr_address_to_string_with_buf( const tr_address * addr, + + bool tr_address_from_string ( tr_address * setme, + const char * string ); ++bool tr_isValidTrackerAddress( const tr_address * addr ); ++ ++bool isAvailableBindAddress(tr_address * address, enum tr_address_type addrType); ++tr_address * unavailableBindAddress(enum tr_address_type addrType); ++ ++static inline bool tr_isAddress( const tr_address * a ) { return ( a != NULL ) && ( a->type==TR_AF_INET || a->type==TR_AF_INET6 ); } + + bool tr_address_from_sockaddr_storage( tr_address * setme, + tr_port * port, +@@ -123,7 +132,8 @@ tr_netOpenPeerUTPSocket( tr_session * session, + tr_port port, + bool clientIsSeed); + +-int tr_netBindTCP( const tr_address * addr, ++int tr_netBindTCP( tr_session * session, ++ const tr_address * addr, + tr_port port, + bool suppressMsgs ); + +@@ -143,7 +153,9 @@ void tr_netCloseSocket( int fd ); + + void tr_netInit( void ); + +-bool tr_net_hasIPv6( tr_port ); ++bool tr_net_hasIPv6( tr_session * session, tr_port port ); ++ ++void tr_netBindSocketInterface(tr_session *session, int socket); + + + /** +diff --git a/libtransmission/peer-io.c b/libtransmission/peer-io.c +index 817a6d3..a128ab9 100644 +--- a/libtransmission/peer-io.c ++++ b/libtransmission/peer-io.c +@@ -27,6 +27,7 @@ + #include "net.h" + #include "peer-common.h" /* MAX_BLOCK_SIZE */ + #include "peer-io.h" ++#include "fdlimit.h" + #include "trevent.h" /* tr_runInEventThread() */ + #include "tr-utp.h" + #include "utils.h" +@@ -160,6 +161,8 @@ didWriteWrapper( tr_peerIo * io, unsigned int bytes_transferred ) + + tr_bandwidthUsed( &io->bandwidth, TR_UP, payload, next->isPieceData, now ); + ++ tr_fdtrack_output(io->socket, payload); ++ + if( overhead > 0 ) + tr_bandwidthUsed( &io->bandwidth, TR_UP, overhead, false, now ); + +@@ -207,10 +210,16 @@ canReadWrapper( tr_peerIo * io ) + if( piece || (piece!=used) ) + { + if( piece ) ++ { + tr_bandwidthUsed( &io->bandwidth, TR_DOWN, piece, true, now ); ++ tr_fdtrack_input(io->socket, piece); ++ } + + if( used != piece ) ++ { + tr_bandwidthUsed( &io->bandwidth, TR_DOWN, used - piece, false, now ); ++ tr_fdtrack_input(io->socket, used - piece); ++ } + } + + if( overhead > 0 ) +@@ -405,6 +414,8 @@ maybeSetCongestionAlgorithm( int socket, const char * algorithm ) + #ifdef WITH_UTP + /* UTP callbacks */ + ++uint64 UTP_GetGlobalUTPBytesSent(const struct sockaddr *remote, socklen_t remotelen); ++ + static void + utp_on_read(void *closure, const unsigned char *buf, size_t buflen) + { +@@ -424,6 +435,8 @@ utp_on_read(void *closure, const unsigned char *buf, size_t buflen) + canReadWrapper( io ); + } + ++uint64 g_global_write_count = 0; ++ + static void + utp_on_write(void *closure, unsigned char *buf, size_t buflen) + { +@@ -439,6 +452,15 @@ utp_on_write(void *closure, unsigned char *buf, size_t buflen) + } + + didWriteWrapper( io, buflen ); ++ ++ g_global_write_count += buflen; ++} ++ ++uint64 UTP_GetGlobalUTPBytesSent(const struct sockaddr *remote, socklen_t remotelen) ++{ ++ (void) remote; ++ (void) remotelen; ++ return g_global_write_count; + } + + static size_t +@@ -506,7 +528,7 @@ utp_on_error(void *closure, int errcode) + } + + static void +-utp_on_overhead(void *closure, bool send, size_t count, int type UNUSED) ++utp_on_overhead(void *closure, uint8_t send, size_t count, int type UNUSED) + { + tr_peerIo *io = closure; + assert( tr_isPeerIo( io ) ); +@@ -567,7 +589,7 @@ dummy_on_error( void * closure UNUSED, int errcode UNUSED ) + } + + static void +-dummy_on_overhead( void *closure UNUSED, bool send UNUSED, size_t count UNUSED, int type UNUSED ) ++dummy_on_overhead( void *closure UNUSED, uint8_t send UNUSED, size_t count UNUSED, int type UNUSED ) + { + return; + } +@@ -635,10 +657,14 @@ tr_peerIoNew( tr_session * session, + io->socket, EV_READ, event_read_cb, io ); + io->event_write = event_new( session->event_base, + io->socket, EV_WRITE, event_write_cb, io ); ++ ++ tr_netBindSocketInterface(session, io->socket); ++ + } + #ifdef WITH_UTP + else { + UTP_SetSockopt( utp_socket, SO_RCVBUF, UTP_READ_BUFFER_SIZE ); ++ + dbgmsg( io, "%s", "calling UTP_SetCallbacks &utp_function_table" ); + UTP_SetCallbacks( utp_socket, + &utp_function_table, +diff --git a/libtransmission/peer-mgr.c b/libtransmission/peer-mgr.c +index ce8b0a5..a2263b9 100644 +--- a/libtransmission/peer-mgr.c ++++ b/libtransmission/peer-mgr.c +@@ -141,7 +141,7 @@ struct peer_atom + }; + + #ifdef NDEBUG +-#define tr_isAtom(a) (TRUE) ++#define tr_isAtom(a) (true) + #else + static bool + tr_isAtom( const struct peer_atom * atom ) +diff --git a/libtransmission/resolver.c b/libtransmission/resolver.c +new file mode 100644 +index 0000000..e3ec6f9 +--- /dev/null ++++ b/libtransmission/resolver.c +@@ -0,0 +1,157 @@ ++/****************************************************************************** ++ * ++ * $Id$ ++ * ++ * Copyright (c) Transmission authors and contributors ++ * ++ * 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. ++ *****************************************************************************/ ++ ++#include <assert.h> ++ ++#include "transmission.h" ++#include "list.h" ++#include "net.h" ++#include "platform.h" ++#include "session.h" ++#include "utils.h" ++#include "trevent.h" ++#include "resolver.h" ++ ++/* If the number of tasks waiting in the queue divided ++ * by the current number of workers is greater than this ++ * number, a new worker thread is created. */ ++#define WORKER_LOAD 5 ++ ++/* Never create more worker threads than this. */ ++#define WORKER_MAX 10 ++ ++typedef struct ++{ ++ tr_session * session; ++ char * node; ++ char * service; ++ int type; ++ tr_resolver_callback callback; ++ void * user_data; ++} ++resolver_task; ++ ++typedef struct ++{ ++ const char * err; ++ tr_address addr; ++ tr_resolver_callback callback; ++ void * user_data; ++} ++resolver_result; ++ ++static tr_list * queue; /* resolver_task */ ++static tr_lock * lock; ++static int workers, tasks; ++ ++static void spawn_workers(void); ++ ++static void ++notify( void * vres ) ++{ ++ resolver_result * res = vres; ++ res->callback( res->err, &res->addr, res->user_data ); ++ tr_free( res ); ++} ++ ++static void ++worker( void * varg UNUSED ) ++{ ++ while( 1 ) ++ { ++ resolver_task * task; ++ resolver_result * res; ++ ++ tr_lockLock( lock ); ++ if( !queue ) ++ { ++ tr_lockUnlock( lock ); ++ break; ++ } ++ task = tr_list_pop_front( &queue ); ++ tasks--; ++ tr_lockUnlock( lock ); ++ ++ res = tr_new0( resolver_result, 1 ); ++ res->addr.type = task->type; ++ res->err = tr_netGetAddress( task->node, task->service, &res->addr ); ++ res->callback = task->callback; ++ res->user_data = task->user_data; ++ ++ tr_runInEventThread( task->session, notify, res ); ++ tr_free( task->node ); ++ tr_free( task->service ); ++ tr_free( task ); ++ } ++ ++ tr_lockLock( lock ); ++ workers--; ++ tr_lockUnlock( lock ); ++} ++ ++static void spawn_workers(void) ++{ ++ tr_lockLock( lock ); ++ if( queue && ( workers < 1 || tasks / workers > WORKER_LOAD ) ++ && workers < WORKER_MAX ) ++ { ++ workers++; ++ tr_threadNew( worker, NULL ); ++ } ++ tr_lockUnlock( lock ); ++} ++ ++void ++tr_resolve_address( tr_session * session, ++ const char * node, ++ const char * service, ++ int type, ++ tr_resolver_callback callback, ++ void * user_data ) ++{ ++ resolver_task * task; ++ ++ assert( callback != NULL ); ++ ++ task = tr_new0( resolver_task, 1 ); ++ task->session = session; ++ task->node = tr_strdup( node ); ++ task->service = tr_strdup( service ); ++ task->type = type; ++ task->callback = callback; ++ task->user_data = user_data; ++ ++ if( !lock ) ++ { ++ assert( tr_amInEventThread( session ) ); ++ lock = tr_lockNew( ); ++ } ++ tr_lockLock( lock ); ++ tr_list_append( &queue, task ); ++ tasks++; ++ tr_lockUnlock( lock ); ++ ++ spawn_workers( ); ++} +diff --git a/libtransmission/resolver.h b/libtransmission/resolver.h +new file mode 100644 +index 0000000..ce44813 +--- /dev/null ++++ b/libtransmission/resolver.h +@@ -0,0 +1,71 @@ ++/****************************************************************************** ++ * $Id$ ++ * ++ * Copyright (c) Transmission authors and contributors ++ * ++ * 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. ++ *****************************************************************************/ ++ ++#ifndef __TRANSMISSION__ ++#error only libtransmission should #include this header. ++#endif ++ ++#ifndef _TR_RESOLVER_H_ ++#define _TR_RESOLVER_H_ ++ ++/** ++ * If the address resolution fails, @a err will be a string ++ * description of the error. Otherwise, @a err will be NULL ++ * and @a addr will contain the resolved address. ++ */ ++typedef void ( * tr_resolver_callback )( const char * err, ++ const tr_address * addr, ++ void * user_data ); ++ ++/** ++ * Resolve a hostname asynchronously by calling getaddrinfo(3) in ++ * another thread. If you do not care about blocking the current ++ * thread, you can just use tr_netGetAddress(). ++ * ++ * @param session @a callback will be run in the event thread of this ++ * session. ++ * @param node The name of the node to resolve. This will generally ++ * just be the hostname. ++ * @param service Same meaning as for getaddrinfo(3). Usually you ++ * can just set this to NULL. ++ * @param type The address type to prefer, either @a TR_AF_INET or ++ * @a TR_AF_INET6. Any other value will cause no particular ++ * type to be preferred and so the first valid address found ++ * will be passed to @a callback. ++ * @param callback Function to call with the result (or an error message). ++ * It will be run in the event thread of @a session by ++ * tr_runInEventThread(). ++ * @param user_data User data to pass to @a callback. ++ * ++ * @see tr_netGetAddress() ++ * @see tr_runInEventThread() ++ */ ++void tr_resolve_address( tr_session * session, ++ const char * node, ++ const char * service, ++ int type, ++ tr_resolver_callback callback, ++ void * user_data ); ++ ++#endif /* _TR_RESOLVER_H_ */ +diff --git a/libtransmission/resume.c b/libtransmission/resume.c +index a879515..341279e 100644 +--- a/libtransmission/resume.c ++++ b/libtransmission/resume.c +@@ -660,7 +660,11 @@ tr_torrentSaveResume( tr_torrent * tor ) + + filename = getResumeFilename( tor ); + if(( err = tr_bencToFile( &top, TR_FMT_BENC, filename ))) ++ { ++ bool was = tor->isStopping; + tr_torrentSetLocalError( tor, "Unable to save resume file: %s", tr_strerror( err ) ); ++ tor->isStopping = was; ++ } + tr_free( filename ); + + tr_bencFree( &top ); +diff --git a/libtransmission/session.c b/libtransmission/session.c +index c135032..f1dfdcd 100644 +--- a/libtransmission/session.c ++++ b/libtransmission/session.c +@@ -37,6 +37,7 @@ + #include "fdlimit.h" + #include "list.h" + #include "net.h" ++#include "net-interfaces.h" + #include "peer-io.h" + #include "peer-mgr.h" + #include "platform.h" /* tr_lock, tr_getTorrentDir(), tr_getFreeSpace() */ +@@ -55,6 +56,17 @@ + #include "version.h" + #include "web.h" + ++#ifdef HAVE_LIBNETLINK ++#include <stdio.h> ++#include <stdlib.h> ++#include <sys/socket.h> ++#include <libnetlink.h> ++ ++#define RTNLGRP_MSGS \ ++ (RTNLGRP_IPV4_IFADDR|RTNLGRP_IPV4_ROUTE|RTNLGRP_IPV6_IFADDR|RTNLGRP_IPV6_ROUTE) ++ ++#endif /* HAVE_LIBNETLINK */ ++ + enum + { + #ifdef TR_LIGHTWEIGHT +@@ -64,7 +76,12 @@ enum + DEFAULT_CACHE_SIZE_MB = 4, + DEFAULT_PREFETCH_ENABLED = true, + #endif +- SAVE_INTERVAL_SECS = 360 ++ SAVE_INTERVAL_SECS = 360, ++#ifdef HAVE_LIBNETLINK ++ NET_IF_POLL_INTERVAL_SECS = 30, ++#else ++ NET_IF_POLL_INTERVAL_SECS = 3, ++#endif /* HAVE_LIBNETLINK */ + }; + + +@@ -197,17 +214,19 @@ open_incoming_peer_port( tr_session * session ) + + /* bind an ipv4 port to listen for incoming peers... */ + b = session->public_ipv4; +- b->socket = tr_netBindTCP( &b->addr, session->private_peer_port, false ); ++ b->socket = tr_netBindTCP( session, &b->addr, session->private_peer_port, false ); + if( b->socket >= 0 ) { ++ tr_netBindSocketInterface(session, b->socket); + b->ev = event_new( session->event_base, b->socket, EV_READ | EV_PERSIST, accept_incoming_peer, session ); + event_add( b->ev, NULL ); + } + + /* and do the exact same thing for ipv6, if it's supported... */ +- if( tr_net_hasIPv6( session->private_peer_port ) ) { ++ if( tr_net_hasIPv6( session, session->private_peer_port ) ) { + b = session->public_ipv6; +- b->socket = tr_netBindTCP( &b->addr, session->private_peer_port, false ); ++ b->socket = tr_netBindTCP( session, &b->addr, session->private_peer_port, false ); + if( b->socket >= 0 ) { ++ tr_netBindSocketInterface(session, b->socket); + b->ev = event_new( session->event_base, b->socket, EV_READ | EV_PERSIST, accept_incoming_peer, session ); + event_add( b->ev, NULL ); + } +@@ -366,6 +385,7 @@ tr_sessionGetDefaultSettings( tr_benc * d ) + tr_bencDictAddInt ( d, TR_PREFS_KEY_UPLOAD_SLOTS_PER_TORRENT, 14 ); + tr_bencDictAddStr ( d, TR_PREFS_KEY_BIND_ADDRESS_IPV4, TR_DEFAULT_BIND_ADDRESS_IPV4 ); + tr_bencDictAddStr ( d, TR_PREFS_KEY_BIND_ADDRESS_IPV6, TR_DEFAULT_BIND_ADDRESS_IPV6 ); ++ tr_bencDictAddStr ( d, TR_PREFS_KEY_BIND_INTERFACE, "" ); + tr_bencDictAddBool( d, TR_PREFS_KEY_START, true ); + tr_bencDictAddBool( d, TR_PREFS_KEY_TRASH_ORIGINAL, false ); + } +@@ -437,6 +457,7 @@ tr_sessionGetSettings( tr_session * s, struct tr_benc * d ) + tr_bencDictAddInt ( d, TR_PREFS_KEY_UPLOAD_SLOTS_PER_TORRENT, s->uploadSlotsPerTorrent ); + tr_bencDictAddStr ( d, TR_PREFS_KEY_BIND_ADDRESS_IPV4, tr_address_to_string( &s->public_ipv4->addr ) ); + tr_bencDictAddStr ( d, TR_PREFS_KEY_BIND_ADDRESS_IPV6, tr_address_to_string( &s->public_ipv6->addr ) ); ++ tr_bencDictAddStr ( d, TR_PREFS_KEY_BIND_INTERFACE, s->publicInterface ); + tr_bencDictAddBool( d, TR_PREFS_KEY_START, !tr_sessionGetPaused( s ) ); + tr_bencDictAddBool( d, TR_PREFS_KEY_TRASH_ORIGINAL, tr_sessionGetDeleteSource( s ) ); + } +@@ -553,6 +574,7 @@ onSaveTimer( int foo UNUSED, short bar UNUSED, void * vsession ) + ***/ + + static void tr_sessionInitImpl( void * ); ++static void peerPortChanged( void * session ); + + struct init_data + { +@@ -660,6 +682,203 @@ onNowTimer( int foo UNUSED, short bar UNUSED, void * vsession ) + /* fprintf( stderr, "time %zu sec, %zu microsec\n", (size_t)tr_time(), (size_t)tv.tv_usec ); */ + } + ++static void tr_getNetworkInterfaces( tr_session * session ) ++{ ++ dbgmsg( "tr_getNetworkInterfaces: Refreshing the list of network interfaces..."); ++ tr_interfacesFree( session->networkInterfaces ); ++ session->networkInterfaces = tr_net_interfaces(); ++ dbgmsg( "tr_getNetworkInterfaces: Refreshed."); ++} ++ ++static tr_interface * tr_sessionGetInterfaceNamed(char * device, tr_session * session ) ++{ ++ return tr_FindInterfaceByName(session->networkInterfaces, device); ++} ++ ++/** ++ * If public interface name is set, refresh the bind ip addresses ++ * ie the session attributes public_ipv4 and public_ipv6 ++ * NOTE: here we don't remember a previous state of the ++ * public_interface string. So clearing this setting may not register ++ * until client restarts. We would have to add a hook funcion for GUI. ++ * At the moment this is hidden setting only, so we dont bother. ++ */ ++static void tr_refreshPublicIp( tr_session * session ) ++{ ++ tr_address old_public_ipv4_addr = session->public_ipv4->addr; ++ tr_address old_public_ipv6_addr = session->public_ipv6->addr; ++ ++ /* If user wants to bind to a specific device ++ * (ppp0, my PPTP VPN for instance). ++ */ ++ if( session->publicInterface && strlen(session->publicInterface) > 0 ) ++ { ++ tr_address * addr_ipv4 = NULL; ++ tr_address * addr_ipv6 = NULL; ++ ++ tr_interface * foundInterface = ++ tr_sessionGetInterfaceNamed(session->publicInterface, session); ++ ++ if (foundInterface) ++ { ++ if (foundInterface->af4) /* != AF_UNSPEC */ ++ { ++ tr_address ipv4null; ++ tr_address_from_string(&ipv4null, TR_DEFAULT_BIND_ADDRESS_IPV4); ++ ++ /* Check that we don't accidentally bind to all ++ * interfaces (0.0.0.0). ++ */ ++ if (0 != tr_address_compare(&ipv4null, &(foundInterface->ipv4))) ++ { ++ addr_ipv4 = &(foundInterface->ipv4); ++ } ++ } ++ if (foundInterface->af6) /* != AF_UNSPEC */ ++ { ++ tr_address ipv6null; ++ tr_address_from_string(&ipv6null, TR_DEFAULT_BIND_ADDRESS_IPV6); ++ ++ /* Check that we don't accidentally bind to all ++ * interfaces (::). ++ */ ++ if (0 != tr_address_compare(&ipv6null, &(foundInterface->ipv6))) ++ { ++ addr_ipv6 = &(foundInterface->ipv6); ++ } ++ } ++ } ++ ++ if (!addr_ipv4) ++ { ++ addr_ipv4 = unavailableBindAddress(TR_AF_INET); ++ } ++ ++ if (!addr_ipv6) ++ { ++ addr_ipv6 = unavailableBindAddress(TR_AF_INET6); ++ } ++ ++ /* if either v4 or v6 bind address has changed */ ++ if(tr_address_compare( addr_ipv4, &old_public_ipv4_addr ) || ++ tr_address_compare( addr_ipv6, &old_public_ipv6_addr )) ++ { ++ session->public_ipv4->addr = * addr_ipv4; ++ session->public_ipv6->addr = * addr_ipv6; ++ ++ /* restart future connections to bind on the new ip address */ ++ if( session->isLPDEnabled ) ++ tr_lpdUninit( session ); ++ ++ if( session->isDHTEnabled ) ++ { ++ tr_dhtUninit( session ); ++ tr_dhtInit( session ); ++ } ++ if( session->isLPDEnabled ) ++ tr_lpdInit( session, &session->public_ipv4->addr ); ++ ++ peerPortChanged( session ); ++ } ++ } ++} ++ ++ ++static void networkIFRefresh(tr_session * session) ++{ ++ assert( tr_isSession( session ) ); ++ tr_getNetworkInterfaces( session ); ++ tr_refreshPublicIp( session ); ++} ++ ++ ++/** ++ * Periodically reload the list of network interfaces ++ */ ++static void onNetworkIFTimer( int foo UNUSED, short bar UNUSED, void * vsession ) ++{ ++ tr_session * session = vsession; ++ ++ assert( tr_isSession( session ) ); ++ assert( session->networkInterfacesTimer != NULL ); ++ ++ dbgmsg( ++ "onNetworkIFTimer: the timer has timed out. Next timeout in %d secs.", ++ NET_IF_POLL_INTERVAL_SECS ); ++ ++ networkIFRefresh(session); ++ tr_timerAdd( session->networkInterfacesTimer, NET_IF_POLL_INTERVAL_SECS, 0 ); ++} ++ ++/** ++ * libnetlink support ++ */ ++ ++#ifdef HAVE_LIBNETLINK ++ ++/* ++ * Change this value to -1 to cause rtnl_listen to exit. ++ * [As per code inspection of iproute2 2.6.37] ++ */ ++static int g_listen = 0; ++ ++/* ++ * libnetlink will listen for kernel events and notify of the ++ * types we have registered for. ++ */ ++static int ++netlinkMessageCallback(const struct sockaddr_nl *who UNUSED, struct nlmsghdr *n, void *vsession) ++{ ++ switch(n->nlmsg_type) ++ { ++ case RTM_NEWLINK: ++ case RTM_DELLINK: ++ case RTM_GETLINK: ++ case RTM_SETLINK: ++ case RTM_NEWADDR: ++ case RTM_DELADDR: ++ case RTM_GETADDR: ++ case RTM_NEWROUTE: ++ case RTM_DELROUTE: ++ case RTM_GETROUTE: ++ case RTM_NEWRULE: ++ case RTM_DELRULE: ++ case RTM_GETRULE: ++ networkIFRefresh((tr_session *)vsession); ++ break; ++ ++ default: ++ break; ++ } ++ return g_listen; ++} ++ ++/* ++ * libnetlink rtnl_listen() blocks forever. ++ * Run it on a separate thread. ++ */ ++static void ++netlinkListenThreadFunc( void * vsession ) ++{ ++ struct rtnl_handle rth; ++ unsigned int groups = RTNLGRP_MSGS; ++ ++ if (rtnl_open(&rth, groups) >= 0) ++ { ++ if (rtnl_listen(&rth, netlinkMessageCallback, vsession)<0) ++ { ++ fprintf(stderr, "rtnl_listen existed.\n"); ++ } ++ } ++ else ++ { ++ fprintf(stderr, "rtnl_open failed."); ++ } ++} ++ ++#endif /* HAVE_LIBNETLINK */ ++ ++ + static void loadBlocklists( tr_session * session ); + + static void +@@ -710,6 +929,22 @@ tr_sessionInitImpl( void * vdata ) + + assert( tr_isSession( session ) ); + ++ tr_sessionSet( session, &settings ); ++ ++ /* ^^ here we set the public_ipv4 bindinfo and other settings ++ * so we are safe to go after here ++ */ ++ session->networkInterfacesTimer = evtimer_new( session->event_base, onNetworkIFTimer, session ); ++ onNetworkIFTimer( 0, 0, session ); ++ ++#ifdef HAVE_LIBNETLINK ++ /* If we have LIBNETLINK support we can listen for the kernel events associated with ++ * Links and Routes coming and going. We just simply refresh our network interface ++ * knowledge when interesting events fire. ++ */ ++ tr_threadNew( netlinkListenThreadFunc, session ); ++#endif /* HAVE_LIBNETLINK */ ++ + session->saveTimer = evtimer_new( session->event_base, onSaveTimer, session ); + tr_timerAdd( session->saveTimer, SAVE_INTERVAL_SECS, 0 ); + +@@ -723,8 +958,6 @@ tr_sessionInitImpl( void * vdata ) + + tr_webInit( session ); + +- tr_sessionSet( session, &settings ); +- + tr_udpInit( session ); + + if( session->isLPDEnabled ) +@@ -844,6 +1077,9 @@ sessionSetImpl( void * vdata ) + b.socket = -1; + session->public_ipv6 = tr_memdup( &b, sizeof( struct tr_bindinfo ) ); + ++ if( tr_bencDictFindStr( settings, TR_PREFS_KEY_BIND_INTERFACE, &str ) ) ++ tr_sessionSetPublicInterface( session, str ); ++ + /* incoming peer port */ + if( tr_bencDictFindInt ( settings, TR_PREFS_KEY_PEER_PORT_RANDOM_LOW, &i ) ) + session->randomPortLow = i; +@@ -1077,7 +1313,14 @@ peerPortChanged( void * session ) + tr_sharedPortChanged( session ); + + while(( tor = tr_torrentNext( session, tor ))) +- tr_torrentChangeMyPort( tor ); ++ { ++ if (tor->isRunning) ++ { ++ tr_torrentStop( tor ); ++ tr_torrentStart( tor ); ++ tr_torrentChangeMyPort( tor ); ++ } ++ } + } + + static void +@@ -1750,6 +1993,12 @@ sessionCloseImpl( void * vsession ) + event_free( session->nowTimer ); + session->nowTimer = NULL; + ++ evtimer_del( session->networkInterfacesTimer ); ++ tr_free( session->networkInterfacesTimer ); ++ session->networkInterfacesTimer = NULL; ++ ++ tr_interfacesFree( session->networkInterfaces ); ++ + tr_verifyClose( session ); + tr_sharedClose( session ); + tr_rpcClose( &session->rpcServer ); +@@ -1795,11 +2044,19 @@ sessionCloseImpl( void * vsession ) + tr_statsClose( session ); + tr_peerMgrFree( session->peerMgr ); + ++// BUG. Advertised IP changes to default IF somewhere after here ... ++ ++ tr_webClose( session, TR_WEB_CLOSE_WHEN_IDLE ); ++ + closeBlocklists( session ); + + tr_fdClose( session ); + ++ tr_webClose( session, TR_WEB_CLOSE_NOW ); ++ + session->isClosed = true; ++ ++ exit(0); + } + + static int +@@ -2594,6 +2851,23 @@ tr_sessionGetRPCBindAddress( const tr_session * session ) + ***** + ****/ + ++void ++tr_sessionSetPublicInterface( tr_session * session, ++ const char * publicInterface ) ++{ ++ assert( tr_isSession( session ) ); ++ ++ if( publicInterface != session->publicInterface ) ++ { ++ tr_free( session->publicInterface ); ++ session->publicInterface = tr_strdup( publicInterface ); ++ } ++} ++ ++/**** ++***** ++****/ ++ + bool + tr_sessionIsTorrentDoneScriptEnabled( const tr_session * session ) + { +@@ -2679,6 +2953,7 @@ tr_sessionSetQueueStalledMinutes( tr_session * session, int minutes ) + assert( minutes > 0 ); + + session->queueStalledMinutes = minutes; ++ + } + + void +diff --git a/libtransmission/session.h b/libtransmission/session.h +index 022d16f..152ecc6 100644 +--- a/libtransmission/session.h ++++ b/libtransmission/session.h +@@ -30,6 +30,7 @@ + #include "bandwidth.h" + #include "bencode.h" + #include "bitfield.h" ++#include "net-interfaces.h" + #include "utils.h" + + typedef enum { TR_NET_OK, TR_NET_ERROR, TR_NET_WAIT } tr_tristate_t; +@@ -211,6 +212,9 @@ struct tr_session + + struct event * nowTimer; + struct event * saveTimer; ++ struct event * networkInterfacesTimer; ++ ++ tr_interface ** networkInterfaces; + + /* monitors the "global pool" speeds */ + struct tr_bandwidth bandwidth; +@@ -219,8 +223,10 @@ struct tr_session + + uint16_t idleLimitMinutes; + ++ /* these attribute store the public bind address details */ + struct tr_bindinfo * public_ipv4; + struct tr_bindinfo * public_ipv6; ++ char * publicInterface; + + uint8_t peer_id[PEER_ID_LEN+1]; + }; +@@ -261,6 +267,7 @@ const struct tr_address* tr_sessionGetPublicAddress( const tr_session * sessio + int tr_af_type, + bool * is_default_value ); + ++void tr_sessionSetPublicInterface( tr_session * session, const char * publicInterface ); + + struct tr_bindsockets * tr_sessionGetBindSockets( tr_session * ); + +diff --git a/libtransmission/tr-dht.h b/libtransmission/tr-dht.h +index 3c244ce..3c235ce 100644 +--- a/libtransmission/tr-dht.h ++++ b/libtransmission/tr-dht.h +@@ -27,6 +27,9 @@ + #error only libtransmission should #include this header. + #endif + ++#ifndef __TR_DHT_H_ ++#define __TR_DHT_H_ ++ + enum + { + TR_DHT_STOPPED = 0, +@@ -47,3 +50,5 @@ void tr_dhtUpkeep( tr_session * ); + void tr_dhtCallback(unsigned char *buf, int buflen, + struct sockaddr *from, socklen_t fromlen, + void *sv); ++ ++#endif /* __TR_DHT_H_ */ +diff --git a/libtransmission/tr-lpd.c b/libtransmission/tr-lpd.c +index 361e4a4..f6ad1dc 100644 +--- a/libtransmission/tr-lpd.c ++++ b/libtransmission/tr-lpd.c +@@ -295,6 +295,7 @@ int tr_lpdInit( tr_session* ss, tr_address* tr_addr UNUSED ) + &opt_on, sizeof opt_on ) < 0 ) + goto fail; + ++ tr_netBindSocketInterface(ss, lpd_socket); + memset( &lpd_mcastAddr, 0, sizeof lpd_mcastAddr ); + lpd_mcastAddr.sin_family = AF_INET; + lpd_mcastAddr.sin_port = htons( lpd_mcastPort ); +@@ -330,6 +331,8 @@ int tr_lpdInit( tr_session* ss, tr_address* tr_addr UNUSED ) + if( evutil_make_socket_nonblocking( lpd_socket2 ) < 0 ) + goto fail; + ++ tr_netBindSocketInterface(ss, lpd_socket2); ++ + /* configure outbound multicast TTL */ + if( setsockopt( lpd_socket2, IPPROTO_IP, IP_MULTICAST_TTL, + &scope, sizeof scope ) < 0 ) +diff --git a/libtransmission/tr-udp.c b/libtransmission/tr-udp.c +index 99ee6be..9a61ff8 100644 +--- a/libtransmission/tr-udp.c ++++ b/libtransmission/tr-udp.c +@@ -145,6 +145,8 @@ rebind_ipv6(tr_session *ss, bool force) + setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one)); + #endif + ++ tr_netBindSocketInterface(ss, s); ++ + memset(&sin6, 0, sizeof(sin6)); + sin6.sin6_family = AF_INET6; + if(ipv6) +@@ -251,6 +253,8 @@ tr_udpInit(tr_session *ss) + goto ipv6; + } + ++ tr_netBindSocketInterface(ss, ss->udp_socket); ++ + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + public_addr = tr_sessionGetPublicAddress(ss, TR_AF_INET, &is_default); +diff --git a/libtransmission/tr-utp.c b/libtransmission/tr-utp.c +index 2d78e67..b0b1fb4 100644 +--- a/libtransmission/tr-utp.c ++++ b/libtransmission/tr-utp.c +@@ -45,6 +45,12 @@ THE SOFTWARE. + + #ifndef WITH_UTP + ++/* if no uTP we need a dummy definition for UTPSocket */ ++struct UTPSocket ++{ ++ int sock; ++}; ++ + void + UTP_Close(struct UTPSocket * socket) + { +@@ -61,7 +67,7 @@ UTP_RBDrained(struct UTPSocket *socket) + assert( 0 ); /* FIXME: this is too much for the long term, but probably needed in the short term */ + } + +-bool ++uint8_t + UTP_Write(struct UTPSocket *socket, size_t count) + { + tr_nerr( MY_NAME, "UTP_RBDrained(%p, %zu) was called.", socket, count ); +diff --git a/libtransmission/transmission.h b/libtransmission/transmission.h +index 5402ea4..507206e 100644 +--- a/libtransmission/transmission.h ++++ b/libtransmission/transmission.h +@@ -165,6 +165,7 @@ const char* tr_getDefaultDownloadDir( void ); + #define TR_PREFS_KEY_ALT_SPEED_TIME_DAY "alt-speed-time-day" + #define TR_PREFS_KEY_BIND_ADDRESS_IPV4 "bind-address-ipv4" + #define TR_PREFS_KEY_BIND_ADDRESS_IPV6 "bind-address-ipv6" ++#define TR_PREFS_KEY_BIND_INTERFACE "bind-interface" + #define TR_PREFS_KEY_BLOCKLIST_ENABLED "blocklist-enabled" + #define TR_PREFS_KEY_BLOCKLIST_URL "blocklist-url" + #define TR_PREFS_KEY_MAX_CACHE_SIZE_MB "cache-size-mb" +diff --git a/macosx/Controller.m b/macosx/Controller.m +index 34aa462..b317e95 100644 +--- a/macosx/Controller.m ++++ b/macosx/Controller.m +@@ -262,6 +262,8 @@ static void sleepCallback(void * controller, io_service_t y, natural_t messageTy + tr_bencDictAddStr(&settings, TR_PREFS_KEY_BIND_ADDRESS_IPV4, [[fDefaults stringForKey: @"BindAddressIPv4"] UTF8String]); + if ([fDefaults objectForKey: @"BindAddressIPv6"]) + tr_bencDictAddStr(&settings, TR_PREFS_KEY_BIND_ADDRESS_IPV6, [[fDefaults stringForKey: @"BindAddressIPv6"] UTF8String]); ++ if ([fDefaults objectForKey: @"BindInterface"]) ++ tr_bencDictAddStr(&settings, TR_PREFS_KEY_BIND_INTERFACE, [[fDefaults stringForKey: @"BindInterface"] UTF8String]); + + tr_bencDictAddBool(&settings, TR_PREFS_KEY_BLOCKLIST_ENABLED, [fDefaults boolForKey: @"BlocklistNew"]); + if ([fDefaults objectForKey: @"BlocklistURL"]) +diff --git a/third-party/libutp/utp_config.h b/third-party/libutp/utp_config.h +index 7ee870a..644c33d 100644 +--- a/third-party/libutp/utp_config.h ++++ b/third-party/libutp/utp_config.h +@@ -5,8 +5,8 @@ + // This should return the global number of bytes sent, used for determining dynamic + // packet size based on rate + +-#warning implement this in libtransmission +-uint64 UTP_GetGlobalUTPBytesSent(const struct sockaddr *remote, socklen_t remotelen) { return 0; } ++// #warning implement this in libtransmission ++uint64 UTP_GetGlobalUTPBytesSent(const struct sockaddr *remote, socklen_t remotelen); + + enum bandwidth_type_t { + payload_bandwidth, connect_overhead, diff --git a/net-p2p/transmission/files/transmission-2.73-build-failure.patch b/net-p2p/transmission/files/transmission-2.73-build-failure.patch new file mode 100644 index 0000000..d633f2b --- /dev/null +++ b/net-p2p/transmission/files/transmission-2.73-build-failure.patch @@ -0,0 +1,23 @@ +fix bind-to-interface build failure + +From: eroen <eroen@occam.eroen.eu> + +bind-to-interface patch introduces a build failure in the transmission-qt. +The qt project file does not link against netlink. +--- + qt/qtr.pro | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/qt/qtr.pro b/qt/qtr.pro +index 419968c..0de496d 100644 +--- a/qt/qtr.pro ++++ b/qt/qtr.pro +@@ -26,7 +26,7 @@ LIBS += $${LIBUTP_LIBS} + LIBS += $${TRANSMISSION_TOP}/third-party/dht/libdht.a + LIBS += $${LIBUPNP_LIBS} + LIBS += $${LIBNATPMP_LIBS} +-unix: LIBS += -L$${EVENT_TOP}/lib -lz -lrt ++unix: LIBS += -L$${EVENT_TOP}/lib -lz -lrt -lnetlink + win32:DEFINES += QT_DBUS + win32:LIBS += -levent-2.0 -lws2_32 -lintl + win32:LIBS += -lidn -liconv -lwldap32 -liphlpapi diff --git a/net-p2p/transmission/metadata.xml b/net-p2p/transmission/metadata.xml index 987262a..b43659e 100644 --- a/net-p2p/transmission/metadata.xml +++ b/net-p2p/transmission/metadata.xml @@ -11,6 +11,7 @@ <name>Samuli Suominen</name> </maintainer> <use> + <flag name='bindtointerface'>Apply unsupported patch to enable bind-to-interface functionality.</flag> <flag name='lightweight'>Optimize transmission for low-resource systems (smaller cache size, prefer unencrypted peer connections, etc.)</flag> <flag name='xfs'>Enable XFS filesystem capabilities by using <pkg>sys-fs/xfsprogs</pkg> headers (in building of fdlimit(.c))</flag> </use> diff --git a/net-p2p/transmission/transmission-2.73.ebuild b/net-p2p/transmission/transmission-2.73.ebuild index 94451ba..6e48bae 100644 --- a/net-p2p/transmission/transmission-2.73.ebuild +++ b/net-p2p/transmission/transmission-2.73.ebuild @@ -18,7 +18,7 @@ HOMEPAGE="http://www.transmissionbt.com/" LICENSE="GPL-2 MIT" SLOT=0 -IUSE="ayatana gtk lightweight qt4 xfs" +IUSE="ayatana bindtointerface gtk lightweight qt4 xfs" RDEPEND=" >=dev-libs/libevent-2.0.10 @@ -75,6 +75,9 @@ src_prepare() { # http://trac.transmissionbt.com/ticket/4324 sed -i -e 's|noinst\(_PROGRAMS = $(TESTS)\)|check\1|' lib${PN}/Makefile.am || die + use bindtointerface && epatch "${FILESDIR}"/transmission-2.73-bind-to-interface.patch + use bindtointerface && epatch "${FILESDIR}"/transmission-2.73-build-failure.patch + eautoreconf if use qt4; then |