summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoreroen <eroen@occam.eroen.eu>2013-01-22 02:01:11 +0100
committereroen <eroen@occam.eroen.eu>2013-01-22 02:01:11 +0100
commit9eb4f2758059ff5d057d46187d3d2184ab272ac4 (patch)
tree99eeca3bac53b06f3fb42d42d375cdb08cb6b5c3 /net-p2p/transmission
parenttransmission: imported from portage (diff)
downloaderoen-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/Manifest21
-rw-r--r--net-p2p/transmission/files/.transmission-2.73-bind-to-interface.patch.swpbin0 -> 20480 bytes
-rw-r--r--net-p2p/transmission/files/transmission-2.73-bind-to-interface.patch2216
-rw-r--r--net-p2p/transmission/files/transmission-2.73-build-failure.patch23
-rw-r--r--net-p2p/transmission/metadata.xml1
-rw-r--r--net-p2p/transmission/transmission-2.73.ebuild5
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
new file mode 100644
index 0000000..ae0efca
--- /dev/null
+++ b/net-p2p/transmission/files/.transmission-2.73-bind-to-interface.patch.swp
Binary files differ
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