@@ -7,6 +7,7 @@ var debug = require('debug')('bittorrent-tracker:udp-tracker')
77var dgram = require ( 'dgram' )
88var inherits = require ( 'inherits' )
99var randombytes = require ( 'randombytes' )
10+ var Socks = require ( 'socks' )
1011var url = require ( 'url' )
1112
1213var common = require ( '../common' )
@@ -63,8 +64,27 @@ UDPTracker.prototype._request = function (opts) {
6364 var self = this
6465 if ( ! opts ) opts = { }
6566 var parsedUrl = url . parse ( self . announceUrl )
67+ if ( ! parsedUrl . port ) {
68+ parsedUrl . port = 80
69+ }
70+ var timeout
71+ var socket
6672 var transactionId = genTransactionId ( )
67- var socket = dgram . createSocket ( 'udp4' )
73+ if ( self . client . _socksProxyOpts ) {
74+ // UDP requests uses the associate command
75+ self . client . _socksProxyOpts . command = 'associate'
76+ if ( ! self . client . _socksProxyOpts . target ) {
77+ // This should contain client IP and port but can be set to 0 if we don't have this information
78+ self . client . _socksProxyOpts . target = {
79+ host : '0.0.0.0' ,
80+ port : 0
81+ }
82+ }
83+
84+ Socks . createConnection ( self . client . _socksProxyOpts , onGotSocket )
85+ } else {
86+ onGotSocket ( null , dgram . createSocket ( 'udp4' ) )
87+ }
6888
6989 var cleanup = function ( ) {
7090 if ( ! socket ) return
@@ -81,23 +101,29 @@ UDPTracker.prototype._request = function (opts) {
81101 }
82102 self . cleanupFns . push ( cleanup )
83103
84- // does not matter if `stopped` event arrives, so supress errors & cleanup after timeout
85- var ms = opts . event === 'stopped' ? TIMEOUT / 10 : TIMEOUT
86- var timeout = setTimeout ( function ( ) {
87- timeout = null
88- if ( opts . event === 'stopped' ) cleanup ( )
89- else onError ( new Error ( 'tracker request timed out (' + opts . event + ')' ) )
90- } , ms )
91- if ( timeout . unref ) timeout . unref ( )
104+ function onGotSocket ( err , s , info ) {
105+ if ( err ) return onError ( err )
92106
93- send ( Buffer . concat ( [
94- common . CONNECTION_ID ,
95- common . toUInt32 ( common . ACTIONS . CONNECT ) ,
96- transactionId
97- ] ) )
107+ socket = s
98108
99- socket . on ( 'error' , onError )
100- socket . on ( 'message' , onSocketMessage )
109+ // does not matter if `stopped` event arrives, so supress errors & cleanup after timeout
110+ var ms = opts . event === 'stopped' ? TIMEOUT / 10 : TIMEOUT
111+ timeout = setTimeout ( function ( ) {
112+ timeout = null
113+ if ( opts . event === 'stopped' ) cleanup ( )
114+ else onError ( new Error ( 'tracker request timed out (' + opts . event + ')' ) )
115+ } , ms )
116+ if ( timeout . unref ) timeout . unref ( )
117+
118+ send ( Buffer . concat ( [
119+ common . CONNECTION_ID ,
120+ common . toUInt32 ( common . ACTIONS . CONNECT ) ,
121+ transactionId
122+ ] ) , info )
123+
124+ socket . on ( 'error' , onError )
125+ socket . on ( 'message' , onSocketMessage )
126+ }
101127
102128 function onSocketMessage ( msg ) {
103129 if ( self . destroyed ) return
@@ -180,11 +206,13 @@ UDPTracker.prototype._request = function (opts) {
180206 self . client . emit ( 'warning' , err )
181207 }
182208
183- function send ( message ) {
184- if ( ! parsedUrl . port ) {
185- parsedUrl . port = 80
209+ function send ( message , info ) {
210+ if ( info ) {
211+ var pack = Socks . createUDPFrame ( { host : parsedUrl . hostname , port : parsedUrl . port } , message )
212+ socket . send ( pack , 0 , pack . length , info . port , info . host )
213+ } else {
214+ socket . send ( message , 0 , message . length , parsedUrl . port , parsedUrl . hostname )
186215 }
187- socket . send ( message , 0 , message . length , parsedUrl . port , parsedUrl . hostname )
188216 }
189217
190218 function announce ( connectionId , opts ) {
0 commit comments