diff options
author | Martin v. Löwis <martin@v.loewis.de> | 2001-07-24 20:34:08 (GMT) |
---|---|---|
committer | Martin v. Löwis <martin@v.loewis.de> | 2001-07-24 20:34:08 (GMT) |
commit | a43c2f845e59b833b17e45994cd81c631c071236 (patch) | |
tree | 76fcd97361c26474054557e554fc548770431acf /Lib/ftplib.py | |
parent | d61e3eab449102834406b9026852e1db51de16bb (diff) | |
download | cpython-a43c2f845e59b833b17e45994cd81c631c071236.zip cpython-a43c2f845e59b833b17e45994cd81c631c071236.tar.gz cpython-a43c2f845e59b833b17e45994cd81c631c071236.tar.bz2 |
Patch #401196: Use getaddrinfo and AF_INET6 in TCP servers and clients.
Diffstat (limited to 'Lib/ftplib.py')
-rw-r--r-- | Lib/ftplib.py | 112 |
1 files changed, 90 insertions, 22 deletions
diff --git a/Lib/ftplib.py b/Lib/ftplib.py index 3263281..693d5a9 100644 --- a/Lib/ftplib.py +++ b/Lib/ftplib.py @@ -108,17 +108,29 @@ class FTP: self.connect(host) if user: self.login(user, passwd, acct) - def connect(self, host='', port=0): - '''Connect to host. Arguments are: - - host: hostname to connect to (string, default previous host) - - port: port to connect to (integer, default previous port)''' - if host: self.host = host - if port: self.port = port - self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - self.sock.connect((self.host, self.port)) - self.file = self.sock.makefile('rb') - self.welcome = self.getresp() - return self.welcome + def connect(self, host = '', port = 0): + '''Connect to host. Arguments are: + - host: hostname to connect to (string, default previous host) + - port: port to connect to (integer, default previous port)''' + if host: self.host = host + if port: self.port = port + self.passiveserver = 0 + for res in socket.getaddrinfo(self.host, self.port, 0, socket.SOCK_STREAM): + af, socktype, proto, canonname, sa = res + try: + self.sock = socket.socket(af, socktype, proto) + self.sock.connect(sa) + except socket.error, msg: + self.sock.close() + self.sock = None + continue + break + if not self.sock: + raise socket.error, msg + self.af = af + self.file = self.sock.makefile('rb') + self.welcome = self.getresp() + return self.welcome def getwelcome(self): '''Get the welcome message from the server. @@ -243,15 +255,48 @@ class FTP: cmd = 'PORT ' + ','.join(bytes) return self.voidcmd(cmd) + def sendeprt(self, host, port): + '''Send a EPRT command with the current host and the given port number.''' + af = 0 + if self.af == socket.AF_INET: + af = 1 + if self.af == socket.AF_INET6: + af = 2 + if af == 0: + raise error_proto, 'unsupported address family' + fields = ['', `af`, host, `port`, ''] + cmd = 'EPRT ' + string.joinfields(fields, '|') + return self.voidcmd(cmd) + def makeport(self): - '''Create a new socket and send a PORT command for it.''' - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - sock.bind(('', 0)) - sock.listen(1) - dummyhost, port = sock.getsockname() # Get proper port - host, dummyport = self.sock.getsockname() # Get proper host - resp = self.sendport(host, port) - return sock + '''Create a new socket and send a PORT command for it.''' + for res in socket.getaddrinfo(None, 0, self.af, socket.SOCK_STREAM, 0, socket.AI_PASSIVE): + af, socktype, proto, canonname, sa = res + try: + sock = socket.socket(af, socktype, proto) + sock.bind(sa) + except socket.error, msg: + sock.close() + sock = None + continue + break + if not sock: + raise socket.error, msg + sock.listen(1) + port = sock.getsockname()[1] # Get proper port + host = self.sock.getsockname()[0] # Get proper host + if self.af == socket.AF_INET: + resp = self.sendport(host, port) + else: + resp = self.sendeprt(host, port) + return sock + + def makepasv(self): + if self.af == socket.AF_INET: + host, port = parse227(self.sendcmd('PASV')) + else: + host, port = parse229(self.sendcmd('EPSV'), self.sock.getpeername()) + return host, port def ntransfercmd(self, cmd, rest=None): """Initiate a transfer over the data connection. @@ -270,9 +315,10 @@ class FTP: """ size = None if self.passiveserver: - host, port = parse227(self.sendcmd('PASV')) - conn=socket.socket(socket.AF_INET, socket.SOCK_STREAM) - conn.connect((host, port)) + host, port = self.makepasv() + af, socktype, proto, canon, sa = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM)[0] + conn = socket.socket(af, socktype, proto) + conn.connect(sa) if rest is not None: self.sendcmd("REST %s" % rest) resp = self.sendcmd(cmd) @@ -523,6 +569,28 @@ def parse227(resp): return host, port +def parse229(resp, peer): + '''Parse the '229' response for a EPSV request. + Raises error_proto if it does not contain '(|||port|)' + Return ('host.addr.as.numbers', port#) tuple.''' + + if resp[:3] <> '229': + raise error_reply, resp + left = string.find(resp, '(') + if left < 0: raise error_proto, resp + right = string.find(resp, ')', left + 1) + if right < 0: + raise error_proto, resp # should contain '(|||port|)' + if resp[left + 1] <> resp[right - 1]: + raise error_proto, resp + parts = string.split(resp[left + 1:right], resp[left+1]) + if len(parts) <> 5: + raise error_proto, resp + host = peer[0] + port = string.atoi(parts[3]) + return host, port + + def parse257(resp): '''Parse the '257' response for a MKD or PWD request. This is a response to a MKD or PWD request: a directory name. |