Source Code Cross Referenced for FTPControlSocket.java in  » Net » edtftpj » com » enterprisedt » net » ftp » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Net » edtftpj » com.enterprisedt.net.ftp 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /**
0002:         *
0003:         *  edtFTPj
0004:         *
0005:         *  Copyright (C) 2000-2003 Enterprise Distributed Technologies Ltd
0006:         *
0007:         *  www.enterprisedt.com
0008:         *
0009:         *  This library is free software; you can redistribute it and/or
0010:         *  modify it under the terms of the GNU Lesser General Public
0011:         *  License as published by the Free Software Foundation; either
0012:         *  version 2.1 of the License, or (at your option) any later version.
0013:         *
0014:         *  This library is distributed in the hope that it will be useful,
0015:         *  but WITHOUT ANY WARRANTY; without even the implied warranty of
0016:         *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0017:         *  Lesser General Public License for more details.
0018:         *
0019:         *  You should have received a copy of the GNU Lesser General Public
0020:         *  License along with this library; if not, write to the Free Software
0021:         *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
0022:         *
0023:         *  Bug fixes, suggestions and comments should be should posted on 
0024:         *  http://www.enterprisedt.com/forums/index.php
0025:         *
0026:         *  Change Log:
0027:         *
0028:         *        $Log: FTPControlSocket.java,v $
0029:         *        Revision 1.40  2007-11-13 07:14:04  bruceb
0030:         *        ListenOnAllInterfaces
0031:         *
0032:         *        Revision 1.39  2007-11-07 23:53:14  bruceb
0033:         *        refactoring for FXP
0034:         *
0035:         *        Revision 1.38  2007-10-23 07:20:42  bruceb
0036:         *        fixed doco spelling mistake
0037:         *
0038:         *        Revision 1.37  2007/02/07 23:03:10  bruceb
0039:         *        added close()
0040:         *
0041:         *        Revision 1.36  2007/02/04 23:03:30  bruceb
0042:         *        extra codes and extra debug
0043:         *
0044:         *        Revision 1.35  2007/01/10 02:36:53  bruceb
0045:         *        sendPORTCommand takes a port number now
0046:         *
0047:         *        Revision 1.34  2006/10/27 15:43:23  bruceb
0048:         *        added connect with timeout
0049:         *
0050:         *        Revision 1.33  2006/10/17 10:28:15  bruceb
0051:         *        refactored to get sendPORTCommand()
0052:         *
0053:         *        Revision 1.32  2006/10/11 08:51:44  hans
0054:         *        made cvsId final
0055:         *
0056:         *        Revision 1.31  2006/08/25 20:40:54  hans
0057:         *        Fixed documentation.
0058:         *
0059:         *        Revision 1.30  2006/07/27 14:11:00  bruceb
0060:         *        IPV6 changes (for subclass)
0061:         *
0062:         *        Revision 1.29  2006/05/23 00:17:42  bruceb
0063:         *        apply timeout to active data socket
0064:         *
0065:         *        Revision 1.28  2006/03/09 21:44:24  bruceb
0066:         *        made PASV parsing cleaner
0067:         *
0068:         *        Revision 1.27  2006/02/16 19:47:57  hans
0069:         *        Changed comment
0070:         *
0071:         *        Revision 1.26  2006/02/09 09:00:44  bruceb
0072:         *        fix to allow for missing end bracket re PASV response
0073:         *
0074:         *        Revision 1.25  2005/09/21 08:38:53  bruceb
0075:         *        allow 230 to be initial server response
0076:         *
0077:         *        Revision 1.24  2005/09/02 21:02:44  bruceb
0078:         *        bug fix in readreply
0079:         *
0080:         *        Revision 1.23  2005/08/26 17:48:26  bruceb
0081:         *        passive ip address setting
0082:         *
0083:         *        Revision 1.22  2005/08/04 22:08:42  hans
0084:         *        Remember encoding so that it can be reused when initStreams is called in places other than the constructor
0085:         *
0086:         *        Revision 1.21  2005/06/10 15:43:59  bruceb
0087:         *        message length check
0088:         *
0089:         *        Revision 1.20  2005/06/03 11:26:25  bruceb
0090:         *        comment change
0091:         *
0092:         *        Revision 1.21  2005/05/15 20:44:15  bruceb
0093:         *        removed debug
0094:         *
0095:         *        Revision 1.20  2005/05/15 19:46:28  bruceb
0096:         *        changes for testing setActivePortRange + STOR accepting 350 nonstrict
0097:         *
0098:         *        Revision 1.19  2005/03/26 12:35:45  bruceb
0099:         *        allow for blank lines in server replies
0100:         *
0101:         *        Revision 1.18  2004/11/19 08:28:10  bruceb
0102:         *        added setPORTIP()
0103:         *
0104:         *        Revision 1.17  2004/10/18 15:56:46  bruceb
0105:         *        set encoding for sock, remove sendCommandOld etc
0106:         *
0107:         *        Revision 1.16  2004/09/18 09:33:47  bruceb
0108:         *        1.1.8 tweaks
0109:         *
0110:         *        Revision 1.15  2004/08/31 10:46:59  bruceb
0111:         *        restructured reply code
0112:         *
0113:         *        Revision 1.14  2004/07/23 23:29:57  bruceb
0114:         *        sendcommand public again
0115:         *
0116:         *        Revision 1.13  2004/07/23 08:30:40  bruceb
0117:         *        restructured re non-strict replies
0118:         *
0119:         *        Revision 1.12  2004/05/22 16:52:57  bruceb
0120:         *        message listener
0121:         *
0122:         *        Revision 1.11  2004/05/01 17:05:15  bruceb
0123:         *        Logger stuff added
0124:         *
0125:         *        Revision 1.10  2004/03/23 20:25:47  bruceb
0126:         *        added US-ASCII to control stream constructor
0127:         *
0128:         *        Revision 1.9  2003/11/15 11:23:55  bruceb
0129:         *        changes required for ssl subclasses
0130:         *
0131:         *        Revision 1.6  2003/05/31 14:53:44  bruceb
0132:         *        1.2.2 changes
0133:         *
0134:         *        Revision 1.5  2003/01/29 22:46:08  bruceb
0135:         *        minor changes
0136:         *
0137:         *        Revision 1.4  2002/11/19 22:01:25  bruceb
0138:         *        changes for 1.2
0139:         *
0140:         *        Revision 1.3  2001/10/09 20:53:46  bruceb
0141:         *        Active mode changes
0142:         *
0143:         *        Revision 1.1  2001/10/05 14:42:04  bruceb
0144:         *        moved from old project
0145:         *
0146:         *
0147:         */package com.enterprisedt.net.ftp;
0148:
0149:        import java.io.BufferedReader;
0150:        import java.io.IOException;
0151:        import java.io.InputStream;
0152:        import java.io.InputStreamReader;
0153:        import java.io.OutputStream;
0154:        import java.io.OutputStreamWriter;
0155:        import java.io.Writer;
0156:        import java.net.InetAddress;
0157:        import java.net.ServerSocket;
0158:        import java.net.Socket;
0159:        import java.util.Vector;
0160:
0161:        import com.enterprisedt.util.debug.Logger;
0162:
0163:        /**
0164:         *  Supports client-side FTP operations
0165:         *
0166:         *  @author         Bruce Blackshaw
0167:         *  @version        $Revision: 1.40 $
0168:         *
0169:         */
0170:        public class FTPControlSocket {
0171:
0172:            /**
0173:             *  Revision control id
0174:             */
0175:            public static final String cvsId = "@(#)$Id: FTPControlSocket.java,v 1.40 2007-11-13 07:14:04 bruceb Exp $";
0176:
0177:            /**
0178:             *   Standard FTP end of line sequence
0179:             */
0180:            static final String EOL = "\r\n";
0181:
0182:            /**
0183:             *   The default and standard control port number for FTP
0184:             */
0185:            public static final int CONTROL_PORT = 21;
0186:
0187:            /**
0188:             *   Used to flag messages
0189:             */
0190:            private static final String DEBUG_ARROW = "---> ";
0191:
0192:            /**
0193:             *   Start of password message
0194:             */
0195:            private static final String PASSWORD_MESSAGE = DEBUG_ARROW + "PASS";
0196:
0197:            /**
0198:             * Logging object
0199:             */
0200:            private static Logger log = Logger.getLogger("FTPControlSocket");
0201:
0202:            /**
0203:             * Use strict return codes if true
0204:             */
0205:            private boolean strictReturnCodes = true;
0206:
0207:            /**
0208:             * Listen to all interfaces in active mode
0209:             */
0210:            protected boolean listenOnAllInterfaces = true;
0211:
0212:            /**
0213:             *  The underlying socket.
0214:             */
0215:            protected Socket controlSock = null;
0216:
0217:            /**
0218:             *  The write that writes to the control socket
0219:             */
0220:            protected Writer writer = null;
0221:
0222:            /**
0223:             *  The reader that reads control data from the
0224:             *  control socket
0225:             */
0226:            protected BufferedReader reader = null;
0227:
0228:            /**
0229:             * Message listener
0230:             */
0231:            private FTPMessageListener messageListener = null;
0232:
0233:            /**
0234:             * IP address we force PORT to send - useful with certain
0235:             * NAT configurations
0236:             */
0237:            protected String forcedActiveIP;
0238:
0239:            /**
0240:             * Lowest port in active mode port range
0241:             */
0242:            private int lowPort = -1;
0243:
0244:            /**
0245:             * Highest port in active mode port range
0246:             */
0247:            private int highPort = -1;
0248:
0249:            /**
0250:             * Next port number to use. 0 indicates let Java decide
0251:             */
0252:            private int nextPort = 0;
0253:
0254:            /**
0255:             * Character encoding.
0256:             */
0257:            private String encoding;
0258:
0259:            /**
0260:             * The remote address to connect to
0261:             */
0262:            protected InetAddress remoteAddr;
0263:
0264:            /**
0265:             * If true, uses the original host IP if an internal IP address
0266:             * is returned by the server in PASV mode
0267:             */
0268:            protected boolean autoPassiveIPSubstitution = false;
0269:
0270:            /**
0271:             *   Constructor. Performs TCP connection and
0272:             *   sets up reader/writer. Allows different control
0273:             *   port to be used
0274:             *
0275:             *   @param   remoteAddr       Remote inet address
0276:             *   @param   controlPort      port for control stream
0277:             *   @param   timeout          the length of the timeout, in milliseconds
0278:             *   @param   encoding         character encoding used for data
0279:             *   @param   messageListener  listens for messages
0280:             */
0281:            protected FTPControlSocket(InetAddress remoteAddr, int controlPort,
0282:                    int timeout, String encoding,
0283:                    FTPMessageListener messageListener) throws IOException,
0284:                    FTPException {
0285:
0286:                this (remoteAddr, SocketUtils.createSocket(remoteAddr,
0287:                        controlPort, timeout), timeout, encoding,
0288:                        messageListener);
0289:            }
0290:
0291:            /**
0292:             * Constructs a new <code>FTPControlSocket</code> using the given
0293:             * <code>Socket</code> object.
0294:             * 
0295:             * @param remoteAddr       the remote address
0296:             * @param controlSock      Socket to be used. 
0297:             * @param timeout          Timeout to be used.
0298:             * @param encoding         character encoding used for data
0299:             * @param messageListener  listens for messages
0300:             * 
0301:             * @throws IOException Thrown if no connection response could be read from the server.
0302:             * @throws FTPException Thrown if the incorrect connection response was sent by the server.
0303:             */
0304:            protected FTPControlSocket(InetAddress remoteAddr,
0305:                    Socket controlSock, int timeout, String encoding,
0306:                    FTPMessageListener messageListener) throws IOException,
0307:                    FTPException {
0308:
0309:                this .remoteAddr = remoteAddr;
0310:                this .controlSock = controlSock;
0311:                this .messageListener = messageListener;
0312:                this .encoding = encoding;
0313:
0314:                setTimeout(timeout);
0315:                initStreams();
0316:                validateConnection();
0317:            }
0318:
0319:            /**
0320:             * Set automatic substitution of the remote host IP on if
0321:             * in passive mode
0322:             * 
0323:             * @param autoPassiveIPSubstitution true if set to on, false otherwise
0324:             */
0325:            protected void setAutoPassiveIPSubstitution(
0326:                    boolean autoPassiveIPSubstitution) {
0327:                this .autoPassiveIPSubstitution = autoPassiveIPSubstitution;
0328:            }
0329:
0330:            /**
0331:             *   Checks that the standard 220 reply is returned
0332:             *   following the initiated connection. Allow 230 as some
0333:             *   proxy servers return it
0334:             */
0335:            private void validateConnection() throws IOException, FTPException {
0336:
0337:                FTPReply reply = readReply();
0338:                String[] validCodes = { "220", "230" };
0339:                validateReply(reply, validCodes);
0340:            }
0341:
0342:            /**
0343:             *  Initialize the reader/writer streams for this connection.
0344:             */
0345:            protected void initStreams() throws IOException {
0346:
0347:                // input stream
0348:                InputStream is = controlSock.getInputStream();
0349:                reader = new BufferedReader(new InputStreamReader(is, encoding));
0350:
0351:                // output stream
0352:                OutputStream os = controlSock.getOutputStream();
0353:                writer = new OutputStreamWriter(os, encoding);
0354:            }
0355:
0356:            /**
0357:             *  Get the name of the remote host
0358:             *
0359:             *  @return  remote host name
0360:             */
0361:            String getRemoteHostName() {
0362:                InetAddress addr = controlSock.getInetAddress();
0363:                return addr.getHostName();
0364:            }
0365:
0366:            /**
0367:             * Set strict checking of FTP return codes. If strict 
0368:             * checking is on (the default) code must exactly match the expected 
0369:             * code. If strict checking is off, only the first digit must match.
0370:             * 
0371:             * @param strict    true for strict checking, false for loose checking
0372:             */
0373:            void setStrictReturnCodes(boolean strict) {
0374:                this .strictReturnCodes = strict;
0375:            }
0376:
0377:            /**
0378:             * Listen on all interfaces for active mode transfers (the default).
0379:             * 
0380:             * @param listenOnAll   true if listen on all interfaces, false to listen on the control interface
0381:             */
0382:            void setListenOnAllInterfaces(boolean listenOnAll) {
0383:                this .listenOnAllInterfaces = listenOnAll;
0384:            }
0385:
0386:            /**
0387:             * Are we listening on all interfaces in active mode, which is the default?
0388:             * 
0389:             * @return true if listening on all interfaces, false if listening just on the control interface
0390:             */
0391:            boolean getListenOnAllInterfaces() {
0392:                return listenOnAllInterfaces;
0393:            }
0394:
0395:            /**
0396:             *   Set the TCP timeout on the underlying control socket.
0397:             *
0398:             *   If a timeout is set, then any operation which
0399:             *   takes longer than the timeout value will be
0400:             *   killed with a java.io.InterruptedException.
0401:             *
0402:             *   @param millis The length of the timeout, in milliseconds
0403:             */
0404:            void setTimeout(int millis) throws IOException {
0405:
0406:                if (controlSock == null)
0407:                    throw new IllegalStateException(
0408:                            "Failed to set timeout - no control socket");
0409:
0410:                controlSock.setSoTimeout(millis);
0411:            }
0412:
0413:            /**
0414:             * Set a listener that handles all FTP messages
0415:             * 
0416:             * @param listener  message listener
0417:             */
0418:            void setMessageListener(FTPMessageListener listener) {
0419:                this .messageListener = listener;
0420:            }
0421:
0422:            /**
0423:             * Close the socket
0424:             * 
0425:             * @throws IOException
0426:             */
0427:            public void close() throws IOException {
0428:                controlSock.close();
0429:            }
0430:
0431:            /**
0432:             *  Quit this FTP session and clean up.
0433:             */
0434:            public void logout() throws IOException {
0435:
0436:                IOException ex = null;
0437:                try {
0438:                    writer.close();
0439:                } catch (IOException e) {
0440:                    ex = e;
0441:                }
0442:                try {
0443:                    reader.close();
0444:                } catch (IOException e) {
0445:                    ex = e;
0446:                }
0447:                try {
0448:                    controlSock.close();
0449:                } catch (IOException e) {
0450:                    ex = e;
0451:                }
0452:                if (ex != null)
0453:                    throw ex;
0454:            }
0455:
0456:            /**
0457:             *  Request a data socket be created on the
0458:             *  server, connect to it and return our
0459:             *  connected socket.
0460:             *
0461:             *  @param  active   if true, create in active mode, else
0462:             *                   in passive mode
0463:             *  @return  connected data socket
0464:             */
0465:            FTPDataSocket createDataSocket(FTPConnectMode connectMode)
0466:                    throws IOException, FTPException {
0467:
0468:                if (connectMode == FTPConnectMode.ACTIVE) {
0469:                    return createDataSocketActive();
0470:                } else { // PASV
0471:                    return createDataSocketPASV();
0472:                }
0473:            }
0474:
0475:            /**
0476:             *  Request a data socket be created on the Client
0477:             *  client on any free port, do not connect it to yet.
0478:             *
0479:             *  @return  not connected data socket
0480:             */
0481:            FTPDataSocket createDataSocketActive() throws IOException,
0482:                    FTPException {
0483:
0484:                // use the next port in list (or 0 by default, indicating any port number)
0485:                FTPDataSocket socket = newActiveDataSocket(nextPort);
0486:
0487:                // increment port number to use to next in range, or else recycle
0488:                // from lowPort again
0489:                if (lowPort >= 0 && highPort >= 0) {
0490:                    if (nextPort < highPort)
0491:                        nextPort++;
0492:                    else
0493:                        nextPort = lowPort;
0494:                }
0495:
0496:                short port = (short) socket.getLocalPort();
0497:                sendPORTCommand(port);
0498:
0499:                return socket;
0500:            }
0501:
0502:            /**
0503:             * Send the PORT command to the server
0504:             * 
0505:             * @param socket           data socket
0506:             * @throws IOException
0507:             * @throws FTPException
0508:             */
0509:            void sendPORTCommand(short port) throws IOException, FTPException {
0510:
0511:                // get the local address to which the control socket is bound.
0512:                InetAddress localhost = controlSock.getLocalAddress();
0513:
0514:                // send the PORT command to the server
0515:                setDataPort(localhost, port);
0516:            }
0517:
0518:            /**
0519:             *  Helper method to convert a byte into an unsigned short value
0520:             *
0521:             *  @param  value   value to convert
0522:             *  @return  the byte value as an unsigned short
0523:             */
0524:            private short toUnsignedShort(byte value) {
0525:                return (value < 0) ? (short) (value + 256) : (short) value;
0526:            }
0527:
0528:            /**
0529:             *  Convert a short into a byte array
0530:             *
0531:             *  @param  value   value to convert
0532:             *  @return  a byte array
0533:             */
0534:            protected byte[] toByteArray(short value) {
0535:
0536:                byte[] bytes = new byte[2];
0537:                bytes[0] = (byte) (value >> 8); // bits 1- 8
0538:                bytes[1] = (byte) (value & 0x00FF); // bits 9-16
0539:                return bytes;
0540:            }
0541:
0542:            /**
0543:             * We can force PORT to send a fixed IP address, which can be useful with certain
0544:             * NAT configurations. Must be connected to the remote host to call this method.
0545:             * 
0546:             * @param forcedActiveIP     IP address to force
0547:             */
0548:            void setActivePortIPAddress(String forcedActiveIP) {
0549:                this .forcedActiveIP = forcedActiveIP;
0550:            }
0551:
0552:            /**
0553:             * Set the port number range for active mode
0554:             * 
0555:             * @param lowest        lowest port number in range
0556:             * @param highest       highest port number in range
0557:             */
0558:            public void setActivePortRange(int lowest, int highest) {
0559:                this .lowPort = lowest;
0560:                this .highPort = highest;
0561:                this .nextPort = lowPort;
0562:            }
0563:
0564:            /**
0565:             * Gets the IP address bytes from an IPV4 address that is
0566:             * a string
0567:             * 
0568:             * @param IPAddress   ip address such as 192.168.10.0
0569:             * @return
0570:             * @throws FTPException
0571:             */
0572:            private byte[] getIPAddressBytes(String IPAddress)
0573:                    throws FTPException {
0574:
0575:                byte ipbytes[] = new byte[4];
0576:                int len = IPAddress.length();
0577:                int partCount = 0;
0578:                StringBuffer buf = new StringBuffer();
0579:
0580:                // loop thru and examine each char
0581:                for (int i = 0; i < len && partCount <= 4; i++) {
0582:
0583:                    char ch = IPAddress.charAt(i);
0584:                    if (Character.isDigit(ch))
0585:                        buf.append(ch);
0586:                    else if (ch != '.') {
0587:                        throw new FTPException(
0588:                                "Incorrectly formatted IP address: "
0589:                                        + IPAddress);
0590:                    }
0591:
0592:                    // get the part
0593:                    if (ch == '.' || i + 1 == len) { // at end or at separator
0594:                        try {
0595:                            ipbytes[partCount++] = (byte) Integer.parseInt(buf
0596:                                    .toString());
0597:                            buf.setLength(0);
0598:                        } catch (NumberFormatException ex) {
0599:                            throw new FTPException(
0600:                                    "Incorrectly formatted IP address: "
0601:                                            + IPAddress);
0602:                        }
0603:                    }
0604:                }
0605:                return ipbytes;
0606:            }
0607:
0608:            /**
0609:             *  Sets the data port on the server, that is, sends a PORT
0610:             *  command.
0611:             *
0612:             *  @param  host    the local host the server will connect to
0613:             *  @param  portNo  the port number to connect to
0614:             */
0615:            protected void setDataPort(InetAddress host, short portNo)
0616:                    throws IOException, FTPException {
0617:
0618:                byte[] hostBytes = host.getAddress();
0619:                byte[] portBytes = toByteArray(portNo);
0620:
0621:                if (forcedActiveIP != null) {
0622:                    log.info("Forcing use of fixed IP for PORT command");
0623:                    hostBytes = getIPAddressBytes(forcedActiveIP);
0624:                }
0625:
0626:                // assemble the PORT command
0627:                String cmd = new StringBuffer("PORT ").append(
0628:                        toUnsignedShort(hostBytes[0])).append(",").append(
0629:                        toUnsignedShort(hostBytes[1])).append(",").append(
0630:                        toUnsignedShort(hostBytes[2])).append(",").append(
0631:                        toUnsignedShort(hostBytes[3])).append(",").append(
0632:                        toUnsignedShort(portBytes[0])).append(",").append(
0633:                        toUnsignedShort(portBytes[1])).toString();
0634:
0635:                // send command and check reply
0636:                // CoreFTP returns 250 incorrectly
0637:                FTPReply reply = sendCommand(cmd);
0638:                String[] validCodes = { "200", "250" };
0639:                validateReply(reply, validCodes);
0640:            }
0641:
0642:            /**
0643:             *  Request a data socket be created on the
0644:             *  server, connect to it and return our
0645:             *  connected socket.
0646:             *
0647:             *  @return  connected data socket
0648:             */
0649:            protected FTPDataSocket createDataSocketPASV() throws IOException,
0650:                    FTPException {
0651:
0652:                // PASSIVE command - tells the server to listen for
0653:                // a connection attempt rather than initiating it
0654:                FTPReply replyObj = sendCommand("PASV");
0655:                validateReply(replyObj, "227");
0656:                String reply = replyObj.getReplyText();
0657:
0658:                int[] parts = getPASVParts(reply);
0659:
0660:                // assemble the IP address
0661:                // we try connecting, so we don't bother checking digits etc
0662:                String ipAddress = parts[0] + "." + parts[1] + "." + parts[2]
0663:                        + "." + parts[3];
0664:
0665:                // assemble the port number
0666:                int port = (parts[4] << 8) + parts[5];
0667:
0668:                String hostIP = ipAddress;
0669:                if (autoPassiveIPSubstitution) {
0670:                    hostIP = remoteAddr.getHostAddress();
0671:                    StringBuffer msg = new StringBuffer(
0672:                            "Substituting server supplied IP (");
0673:                    msg.append(ipAddress).append(") with remote host IP (")
0674:                            .append(hostIP).append(")");
0675:                    log.debug(msg.toString());
0676:                }
0677:
0678:                // create the socket
0679:                return newPassiveDataSocket(hostIP, port);
0680:            }
0681:
0682:            /**
0683:             * Get the parts that make up the PASV reply
0684:             * 
0685:             * @param reply  reply string
0686:             * @return
0687:             * @throws FTPException
0688:             */
0689:            int[] getPASVParts(String reply) throws FTPException {
0690:
0691:                // The reply to PASV is in the form:
0692:                // 227 Entering Passive Mode (h1,h2,h3,h4,p1,p2).
0693:                // where h1..h4 are the IP address to connect and
0694:                // p1,p2 the port number
0695:                // Example:
0696:                // 227 Entering Passive Mode (128,3,122,1,15,87).
0697:                // NOTE: PASV command in IBM/Mainframe returns the string
0698:                // 227 Entering Passive Mode 128,3,122,1,15,87 (missing 
0699:                // brackets)
0700:
0701:                // extract the IP data string from between the brackets
0702:                int startIP = reply.indexOf('(');
0703:                int endIP = reply.indexOf(')');
0704:
0705:                // if didn't find start bracket, figure out where it should have been
0706:                if (startIP < 0) {
0707:                    startIP = 0;
0708:                    while (startIP < reply.length()
0709:                            && !Character.isDigit(reply.charAt(startIP)))
0710:                        startIP++;
0711:                    startIP--; // go back so this is where the '(' should be
0712:                }
0713:
0714:                // if didn't find end bracket, set to end of reply
0715:                if (endIP < 0) {
0716:                    endIP = reply.length() - 1;
0717:                    while (endIP > 0 && !Character.isDigit(reply.charAt(endIP)))
0718:                        endIP--;
0719:                    endIP++; // go forward so this is where the ')' should be
0720:                    if (endIP >= reply.length())
0721:                        reply += ")";
0722:                }
0723:
0724:                String ipData = reply.substring(startIP + 1, endIP).trim();
0725:                int parts[] = new int[6];
0726:
0727:                int len = ipData.length();
0728:                int partCount = 0;
0729:                StringBuffer buf = new StringBuffer();
0730:
0731:                // loop thru and examine each char
0732:                for (int i = 0; i < len && partCount <= 6; i++) {
0733:
0734:                    char ch = ipData.charAt(i);
0735:                    if (Character.isDigit(ch))
0736:                        buf.append(ch);
0737:                    else if (ch != ',' && ch != ' ') {
0738:                        throw new FTPException("Malformed PASV reply: " + reply);
0739:                    }
0740:
0741:                    // get the part
0742:                    if (ch == ',' || i + 1 == len) { // at end or at separator
0743:                        try {
0744:                            parts[partCount++] = Integer.parseInt(buf
0745:                                    .toString());
0746:                            buf.setLength(0);
0747:                        } catch (NumberFormatException ex) {
0748:                            throw new FTPException("Malformed PASV reply: "
0749:                                    + reply);
0750:                        }
0751:                    }
0752:                }
0753:                return parts;
0754:            }
0755:
0756:            /**
0757:             * Constructs a new <code>FTPDataSocket</code> object (client mode) and connect
0758:             * to the given remote host and port number.
0759:             * 
0760:             * @param remoteHost Remote host to connect to.
0761:             * @param port Remote port to connect to.
0762:             * @return A new <code>FTPDataSocket</code> object (client mode) which is
0763:             * connected to the given server.
0764:             * @throws IOException Thrown if no TCP/IP connection could be made. 
0765:             */
0766:            protected FTPDataSocket newPassiveDataSocket(String remoteHost,
0767:                    int port) throws IOException {
0768:
0769:                return new FTPPassiveDataSocket(new Socket(remoteHost, port));
0770:            }
0771:
0772:            /**
0773:             * Constructs a new <code>FTPDataSocket</code> object (server mode) which will
0774:             * listen on the given port number.
0775:             * 
0776:             * @param port Remote port to listen on.
0777:             * @return A new <code>FTPDataSocket</code> object (server mode) which is
0778:             *         configured to listen on the given port.
0779:             * @throws IOException Thrown if an error occurred when creating the socket. 
0780:             */
0781:            protected FTPDataSocket newActiveDataSocket(int port)
0782:                    throws IOException {
0783:
0784:                // ensure server sock gets the timeout
0785:                ServerSocket sock = listenOnAllInterfaces ? new ServerSocket(
0786:                        port) : new ServerSocket(port, 0, controlSock
0787:                        .getLocalAddress());
0788:                log.debug("ListenOnAllInterfaces=" + listenOnAllInterfaces);
0789:                sock.setSoTimeout(controlSock.getSoTimeout());
0790:                return new FTPActiveDataSocket(sock);
0791:            }
0792:
0793:            /**
0794:             *  Send a command to the FTP server and
0795:             *  return the server's reply as a structured
0796:             *  reply object
0797:             * 
0798:             *  @param command   command to send
0799:             *
0800:             *  @return  reply to the supplied command
0801:             */
0802:            public FTPReply sendCommand(String command) throws IOException {
0803:
0804:                writeCommand(command);
0805:
0806:                // and read the result
0807:                return readReply();
0808:            }
0809:
0810:            /**
0811:             *  Send a command to the FTP server. Don't
0812:             *  read the reply
0813:             *
0814:             *  @param command   command to send
0815:             */
0816:            void writeCommand(String command) throws IOException {
0817:
0818:                log(DEBUG_ARROW + command, true);
0819:
0820:                // send it
0821:                writer.write(command + EOL);
0822:                writer.flush();
0823:            }
0824:
0825:            /**
0826:             *  Read the FTP server's reply to a previously
0827:             *  issued command. RFC 959 states that a reply
0828:             *  consists of the 3 digit code followed by text.
0829:             *  The 3 digit code is followed by a hyphen if it
0830:             *  is a multiline response, and the last line starts
0831:             *  with the same 3 digit code.
0832:             *
0833:             *  @return  structured reply object
0834:             */
0835:            FTPReply readReply() throws IOException {
0836:
0837:                String line = reader.readLine();
0838:                while (line != null && line.length() == 0)
0839:                    line = reader.readLine();
0840:
0841:                if (line == null)
0842:                    throw new IOException("Unexpected null reply received");
0843:
0844:                log(line, false);
0845:
0846:                if (line.length() < 3)
0847:                    throw new IOException("Short reply received");
0848:
0849:                String replyCode = line.substring(0, 3);
0850:                StringBuffer reply = new StringBuffer("");
0851:                if (line.length() > 3)
0852:                    reply.append(line.substring(4));
0853:
0854:                Vector dataLines = null;
0855:
0856:                // check for multiline response and build up
0857:                // the reply
0858:                if (line.charAt(3) == '-') {
0859:                    dataLines = new Vector();
0860:                    boolean complete = false;
0861:                    while (!complete) {
0862:                        line = reader.readLine();
0863:                        if (line == null)
0864:                            throw new IOException(
0865:                                    "Unexpected null reply received");
0866:
0867:                        if (line.length() == 0)
0868:                            continue;
0869:
0870:                        log(line, false);
0871:
0872:                        if (line.length() > 3
0873:                                && line.substring(0, 3).equals(replyCode)
0874:                                && line.charAt(3) == ' ') {
0875:                            reply.append(line.substring(3));
0876:                            complete = true;
0877:                        } else { // not the last line
0878:                            reply.append(" ").append(line);
0879:                            dataLines.addElement(line);
0880:                        }
0881:                    } // end while
0882:                } // end if
0883:
0884:                if (dataLines != null) {
0885:                    String[] data = new String[dataLines.size()];
0886:                    dataLines.copyInto(data);
0887:                    return new FTPReply(replyCode, reply.toString(), data);
0888:                } else {
0889:                    return new FTPReply(replyCode, reply.toString());
0890:                }
0891:            }
0892:
0893:            /**
0894:             *  Validate the response the host has supplied against the
0895:             *  expected reply. If we get an unexpected reply we throw an
0896:             *  exception, setting the message to that returned by the
0897:             *  FTP server
0898:             *
0899:             *  @param   reply              the entire reply string we received
0900:             *  @param   expectedReplyCode  the reply we expected to receive
0901:             *
0902:             */
0903:            FTPReply validateReply(String reply, String expectedReplyCode)
0904:                    throws FTPException {
0905:
0906:                FTPReply replyObj = new FTPReply(reply);
0907:
0908:                if (validateReplyCode(replyObj, expectedReplyCode))
0909:                    return replyObj;
0910:
0911:                // if unexpected reply, throw an exception
0912:                throw new FTPException(replyObj);
0913:            }
0914:
0915:            /**
0916:             *  Validate the response the host has supplied against the
0917:             *  expected reply. If we get an unexpected reply we throw an
0918:             *  exception, setting the message to that returned by the
0919:             *  FTP server
0920:             *
0921:             *  @param   reply               the entire reply string we received
0922:             *  @param   expectedReplyCodes  array of expected replies
0923:             *  @return  an object encapsulating the server's reply
0924:             *
0925:             */
0926:            public FTPReply validateReply(String reply,
0927:                    String[] expectedReplyCodes) throws IOException,
0928:                    FTPException {
0929:
0930:                FTPReply replyObj = new FTPReply(reply);
0931:                return validateReply(replyObj, expectedReplyCodes);
0932:            }
0933:
0934:            /**
0935:             *  Validate the response the host has supplied against the
0936:             *  expected reply. If we get an unexpected reply we throw an
0937:             *  exception, setting the message to that returned by the
0938:             *  FTP server
0939:             *
0940:             *  @param   reply               reply object
0941:             *  @param   expectedReplyCodes  array of expected replies
0942:             *  @return  reply object
0943:             *
0944:             */
0945:            public FTPReply validateReply(FTPReply reply,
0946:                    String[] expectedReplyCodes) throws FTPException {
0947:
0948:                for (int i = 0; i < expectedReplyCodes.length; i++)
0949:                    if (validateReplyCode(reply, expectedReplyCodes[i]))
0950:                        return reply;
0951:
0952:                // got this far, not recognised
0953:                StringBuffer buf = new StringBuffer("[");
0954:                for (int i = 0; i < expectedReplyCodes.length; i++) {
0955:                    buf.append(expectedReplyCodes[i]);
0956:                    if (i + 1 < expectedReplyCodes.length)
0957:                        buf.append(",");
0958:                }
0959:                buf.append("]");
0960:                log.info("Expected reply codes = " + buf.toString());
0961:                throw new FTPException(reply);
0962:            }
0963:
0964:            /**
0965:             *  Validate the response the host has supplied against the
0966:             *  expected reply. If we get an unexpected reply we throw an
0967:             *  exception, setting the message to that returned by the
0968:             *  FTP server
0969:             *
0970:             *  @param   reply               reply object
0971:             *  @param   expectedReplyCode   expected reply
0972:             *  @return  reply object
0973:             *
0974:             */
0975:            public FTPReply validateReply(FTPReply reply,
0976:                    String expectedReplyCode) throws FTPException {
0977:
0978:                if (validateReplyCode(reply, expectedReplyCode))
0979:                    return reply;
0980:
0981:                // got this far, not recognised
0982:                log.info("Expected reply code = [" + expectedReplyCode + "]");
0983:                throw new FTPException(reply);
0984:            }
0985:
0986:            /**
0987:             * Validate reply object
0988:             * 
0989:             * @param reply                reference to reply object
0990:             * @param expectedReplyCode    expect reply code
0991:             * @return true if valid, false if invalid
0992:             */
0993:            private boolean validateReplyCode(FTPReply reply,
0994:                    String expectedReplyCode) {
0995:
0996:                String replyCode = reply.getReplyCode();
0997:                if (strictReturnCodes) {
0998:                    if (replyCode.equals(expectedReplyCode))
0999:                        return true;
1000:                    else
1001:                        return false;
1002:                } else { // non-strict - match first char
1003:                    if (replyCode.charAt(0) == expectedReplyCode.charAt(0))
1004:                        return true;
1005:                    else
1006:                        return false;
1007:                }
1008:            }
1009:
1010:            /**
1011:             *  Log a message, checking for passwords
1012:             * 
1013:             *  @param msg	message to log
1014:             *  @param reply  true if a response, false otherwise
1015:             */
1016:            void log(String msg, boolean command) {
1017:                if (msg.startsWith(PASSWORD_MESSAGE))
1018:                    msg = PASSWORD_MESSAGE + " ********";
1019:                log.debug(msg);
1020:                if (messageListener != null)
1021:                    if (command)
1022:                        messageListener.logCommand(msg);
1023:                    else
1024:                        messageListener.logReply(msg);
1025:
1026:            }
1027:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.