@@ -108,17 +108,29 @@ def __init__(self, host='', user='', passwd='', acct=''):
108108 self .connect (host )
109109 if user : self .login (user , passwd , acct )
110110
111- def connect (self , host = '' , port = 0 ):
112- '''Connect to host. Arguments are:
113- - host: hostname to connect to (string, default previous host)
114- - port: port to connect to (integer, default previous port)'''
115- if host : self .host = host
116- if port : self .port = port
117- self .sock = socket .socket (socket .AF_INET , socket .SOCK_STREAM )
118- self .sock .connect ((self .host , self .port ))
119- self .file = self .sock .makefile ('rb' )
120- self .welcome = self .getresp ()
121- return self .welcome
111+ def connect (self , host = '' , port = 0 ):
112+ '''Connect to host. Arguments are:
113+ - host: hostname to connect to (string, default previous host)
114+ - port: port to connect to (integer, default previous port)'''
115+ if host : self .host = host
116+ if port : self .port = port
117+ self .passiveserver = 0
118+ for res in socket .getaddrinfo (self .host , self .port , 0 , socket .SOCK_STREAM ):
119+ af , socktype , proto , canonname , sa = res
120+ try :
121+ self .sock = socket .socket (af , socktype , proto )
122+ self .sock .connect (sa )
123+ except socket .error , msg :
124+ self .sock .close ()
125+ self .sock = None
126+ continue
127+ break
128+ if not self .sock :
129+ raise socket .error , msg
130+ self .af = af
131+ self .file = self .sock .makefile ('rb' )
132+ self .welcome = self .getresp ()
133+ return self .welcome
122134
123135 def getwelcome (self ):
124136 '''Get the welcome message from the server.
@@ -243,15 +255,48 @@ def sendport(self, host, port):
243255 cmd = 'PORT ' + ',' .join (bytes )
244256 return self .voidcmd (cmd )
245257
258+ def sendeprt (self , host , port ):
259+ '''Send a EPRT command with the current host and the given port number.'''
260+ af = 0
261+ if self .af == socket .AF_INET :
262+ af = 1
263+ if self .af == socket .AF_INET6 :
264+ af = 2
265+ if af == 0 :
266+ raise error_proto , 'unsupported address family'
267+ fields = ['' , `af` , host , `port` , '' ]
268+ cmd = 'EPRT ' + string .joinfields (fields , '|' )
269+ return self .voidcmd (cmd )
270+
246271 def makeport (self ):
247- '''Create a new socket and send a PORT command for it.'''
248- sock = socket .socket (socket .AF_INET , socket .SOCK_STREAM )
249- sock .bind (('' , 0 ))
250- sock .listen (1 )
251- dummyhost , port = sock .getsockname () # Get proper port
252- host , dummyport = self .sock .getsockname () # Get proper host
253- resp = self .sendport (host , port )
254- return sock
272+ '''Create a new socket and send a PORT command for it.'''
273+ for res in socket .getaddrinfo (None , 0 , self .af , socket .SOCK_STREAM , 0 , socket .AI_PASSIVE ):
274+ af , socktype , proto , canonname , sa = res
275+ try :
276+ sock = socket .socket (af , socktype , proto )
277+ sock .bind (sa )
278+ except socket .error , msg :
279+ sock .close ()
280+ sock = None
281+ continue
282+ break
283+ if not sock :
284+ raise socket .error , msg
285+ sock .listen (1 )
286+ port = sock .getsockname ()[1 ] # Get proper port
287+ host = self .sock .getsockname ()[0 ] # Get proper host
288+ if self .af == socket .AF_INET :
289+ resp = self .sendport (host , port )
290+ else :
291+ resp = self .sendeprt (host , port )
292+ return sock
293+
294+ def makepasv (self ):
295+ if self .af == socket .AF_INET :
296+ host , port = parse227 (self .sendcmd ('PASV' ))
297+ else :
298+ host , port = parse229 (self .sendcmd ('EPSV' ), self .sock .getpeername ())
299+ return host , port
255300
256301 def ntransfercmd (self , cmd , rest = None ):
257302 """Initiate a transfer over the data connection.
@@ -270,9 +315,10 @@ def ntransfercmd(self, cmd, rest=None):
270315 """
271316 size = None
272317 if self .passiveserver :
273- host , port = parse227 (self .sendcmd ('PASV' ))
274- conn = socket .socket (socket .AF_INET , socket .SOCK_STREAM )
275- conn .connect ((host , port ))
318+ host , port = self .makepasv ()
319+ af , socktype , proto , canon , sa = socket .getaddrinfo (host , port , 0 , socket .SOCK_STREAM )[0 ]
320+ conn = socket .socket (af , socktype , proto )
321+ conn .connect (sa )
276322 if rest is not None :
277323 self .sendcmd ("REST %s" % rest )
278324 resp = self .sendcmd (cmd )
@@ -523,6 +569,28 @@ def parse227(resp):
523569 return host , port
524570
525571
572+ def parse229 (resp , peer ):
573+ '''Parse the '229' response for a EPSV request.
574+ Raises error_proto if it does not contain '(|||port|)'
575+ Return ('host.addr.as.numbers', port#) tuple.'''
576+
577+ if resp [:3 ] <> '229' :
578+ raise error_reply , resp
579+ left = string .find (resp , '(' )
580+ if left < 0 : raise error_proto , resp
581+ right = string .find (resp , ')' , left + 1 )
582+ if right < 0 :
583+ raise error_proto , resp # should contain '(|||port|)'
584+ if resp [left + 1 ] <> resp [right - 1 ]:
585+ raise error_proto , resp
586+ parts = string .split (resp [left + 1 :right ], resp [left + 1 ])
587+ if len (parts ) <> 5 :
588+ raise error_proto , resp
589+ host = peer [0 ]
590+ port = string .atoi (parts [3 ])
591+ return host , port
592+
593+
526594def parse257 (resp ):
527595 '''Parse the '257' response for a MKD or PWD request.
528596 This is a response to a MKD or PWD request: a directory name.
0 commit comments