001: /**
002: * $Id: FullFtpClient.java,v 1.20 2005/11/30 11:26:33 ss150821 Exp $
003: * Copyright 2002 Sun Microsystems, Inc. All
004: * rights reserved. Use of this product is subject
005: * to license terms. Federal Acquisitions:
006: * Commercial Software -- Government Users
007: * Subject to Standard License Terms and
008: * Conditions.
009: *
010: * Sun, Sun Microsystems, the Sun logo, and Sun ONE
011: * are trademarks or registered trademarks of Sun Microsystems,
012: * Inc. in the United States and other countries.
013: */package com.sun.portal.netfile.servlet.java1;
014:
015: import java.io.IOException;
016: import com.sun.portal.log.common.PortalLogger;
017: import java.io.FileNotFoundException;
018: import java.io.OutputStreamWriter;
019: import java.io.BufferedInputStream;
020:
021: import java.util.Enumeration;
022: import java.util.Vector;
023: import java.util.StringTokenizer;
024: import java.util.logging.*;
025: import java.net.*;
026:
027: import sun.net.TransferProtocolClient;
028: import sun.net.TelnetInputStream;
029: import sun.net.TelnetOutputStream;
030:
031: public class FullFtpClient extends TransferProtocolClient {
032:
033: private String machineName = null;
034: private static final String HOST_NOT_FOUND = "Server Address could not be resolved";
035: private static final String HOST_NO_MATCH = "Server IP Address does not match an network address of iPS";
036:
037: public static final int FTP_PORT = 21;
038:
039: static int FTP_SUCCESS = 1;
040: static int FTP_TRY_AGAIN = 2;
041: static int FTP_ERROR = 3;
042:
043: /* socket for data transfer */
044: private Socket sock = null;
045: private boolean replyPending = false;
046: private boolean binaryMode = true;
047:
048: /* user name for login */
049: String user = null;
050: /* password for login */
051: String password = null;
052:
053: /* last command issued */
054: String command;
055:
056: /* The last reply code from the ftp daemon. */
057: int lastReplyCode;
058:
059: /* Welcome message from the server, if any. */
060: public String welcomeMsg;
061:
062: /* Machine encoding to use with the server */
063: public String machine_encoding = "UTF8";
064: /* OutputStreamWriter to server */
065: OutputStreamWriter opsw_server;
066:
067: private static Logger logger = PortalLogger
068: .getLogger(FullFtpClient.class);
069:
070: public FullFtpClient(String host, String machine_encoding)
071: throws IOException {
072: this (host, FTP_PORT, machine_encoding);
073: }
074:
075: private void setDebug() {
076: }
077:
078: /* Create an uninitialized FullFTP client. */
079: public FullFtpClient(String host, int port, String machine_encoding)
080: throws IOException {
081: super ();
082: setDebug();
083: this .machine_encoding = machine_encoding;
084: openServerOnPort(host, port);
085: }
086:
087: /* Move up one directory in the ftp file system */
088: public void cdup() throws IOException {
089: issueCommandCheck("CDUP");
090: }
091:
092: /* Create a new directory named s in the ftp file system */
093: public void mkdir(String s) throws IOException {
094: issueCommandCheck("MKD " + s);
095: }
096:
097: /* Delete the specified directory from the ftp file system */
098: public void rmdir(String s) throws IOException {
099: issueCommandCheck("RMD " + s);
100: }
101:
102: /* Delete the file s from the ftp file system */
103: public void delete(String s) throws IOException {
104: issueCommandCheck("DELE " + s);
105: }
106:
107: /* Rename the file */
108: public void rename(String old_name, String new_name)
109: throws IOException {
110: issueCommandCheck("RNFR " + old_name);
111: issueCommandCheck("RNTO " + new_name);
112: }
113:
114: /* Get the name of the present working directory on the ftp file system */
115: public String pwd() throws IOException {
116: issueCommandCheck("PWD");
117: StringBuffer result = new StringBuffer();
118: for (Enumeration e = serverResponse.elements(); e
119: .hasMoreElements();) {
120: result.append((String) e.nextElement());
121: }
122: return result.toString();
123:
124: }
125:
126: //over riding the base class to fix the multihomed portal server
127: protected Socket openDataConnection(String s) throws IOException {
128: //these two defined in the super class( but not available here) hence defineing again
129: int FTP_ERROR = 3;
130: int numOtherNames = 0;
131: Socket dataSocket = null;
132: ServerSocket dataServerSock = null;
133: InetAddress theAddress = null;
134: int foundFlag = 0;
135: byte abyte0[] = null;
136: String interfaceIP_touse = null;
137: String ftpServerName = null;
138: Vector ipaddresses = null;
139: java.net.InetAddress otherName = null;
140:
141: ftpServerName = (String) this .getMachineToAccess();
142:
143: if (ftpServerName != null) {
144: try {
145: interfaceIP_touse = (String) NetFileServlet
146: .getInterface(ftpServerName);
147: } catch (NullPointerException npe) {
148: // logger.info("Interface to use for " + ftpServerName +" not cached. Interface determination started.");
149: Object[] params0 = { ftpServerName,
150: " not cached. Interface determination started." };
151: logger.log(Level.INFO, "PSSRNF_CSPNSJ1067", params0);
152: }
153: /*
154: * Interface to use with the given server name not available
155: * So call findInterface to determine interface to use with this given server name
156: */
157: if (interfaceIP_touse != null) {
158: dataSocket = this .openCachedDataConnection(s,
159: interfaceIP_touse);
160: return dataSocket;
161: }
162: }
163:
164: ipaddresses = NetFileServlet.getInterfaceIPs();
165: if (ipaddresses == null) {
166: IOException ftpprotocolexception1 = new IOException(
167: "NO INTERFACES");
168: throw ftpprotocolexception1;
169: }
170:
171: /*
172: * Get the interfaceIP to be used.
173: * If the name of the FTP Server matches including the subnet with the interface's IP,
174: * then call openCachedDataConnection with that interface's IP.
175: *
176: * If Name of the FTP Server cannot be resolved, then go ahead and try on all interfaces sequentially.
177: *
178: * If IP of the FTP Server does not match upto and including the subnet, then once again go ahead
179: * and try on all interfaces sequentially.
180: *
181: * In sequential access, the best case could be that FTP Server is reached on first interface and
182: * the worst case, the FTP Server is reached through the last interface(timeout likely).
183: */
184: interfaceIP_touse = this .findInterface(ftpServerName,
185: ipaddresses);
186: if (interfaceIP_touse.equalsIgnoreCase(HOST_NO_MATCH)) {
187: numOtherNames = ipaddresses.size();
188: } else if (interfaceIP_touse.equalsIgnoreCase(HOST_NOT_FOUND)) {
189: numOtherNames = ipaddresses.size();
190: } else {
191: numOtherNames = 1;
192: dataSocket = this .openCachedDataConnection(s,
193: interfaceIP_touse);
194: /*
195: * For future use, set the name of server as key and the interface IP to use as value.
196: */
197: NetFileServlet.setInterface(ftpServerName,
198: interfaceIP_touse);
199: return dataSocket;
200: }
201:
202: do {
203: otherName = java.net.InetAddress
204: .getByName((String) ipaddresses
205: .get(numOtherNames - 1));
206: theAddress = otherName;
207: abyte0 = theAddress.getAddress();
208: boolean boundFlag = false;
209: /*
210: * Keep Trying till you bind the socket on a port.
211: * unlikely that the socket will never find a port to bind on to - hence the loop till bound.
212: */
213: while (!boundFlag) {
214: try {
215: dataServerSock = new ServerSocket(0, 1, theAddress);
216: foundFlag = 1;
217: boundFlag = true;
218: } catch (java.net.BindException be) {
219: // logger.info("Could not bind on HostAddress " + theAddress.getHostAddress() + ". Address is " + theAddress.getAddress());
220: Object[] params1 = { theAddress.getHostAddress(),
221: ". Address is ", theAddress.getAddress() };
222: logger
223: .log(Level.INFO, "PSSRNF_CSPNSJ1068",
224: params1);
225: foundFlag = 0;
226: }
227: }
228:
229: String s1 = "PORT ";
230: /*
231: * PORT h1,h2,h3,h4,p1,p2
232: * First the Host, then the Port
233: */
234: for (int i = 0; i < abyte0.length; i++)
235: s1 = s1 + (abyte0[i] & 0xff) + ",";
236: s1 = s1 + (dataServerSock.getLocalPort() >>> 8 & 0xff)
237: + "," + (dataServerSock.getLocalPort() & 0xff);
238:
239: //throwing IOException instead of FtpProtocolException as that is not public
240: if (issueCommand(s1) == FTP_ERROR) {
241: IOException ftpprotocolexception = new IOException(
242: "PORT");
243: if (dataServerSock != null)
244: dataServerSock.close();
245: foundFlag = FTP_ERROR;
246: throw ftpprotocolexception;
247: }
248: if (issueCommand(s) == FTP_ERROR) {
249: // logger.info("Data Command sent. Output data from FTP Server not received.");
250: logger.info("PSSRNF_CSPNSJ1069");
251: /*
252: * The FTP Server could not reach the data socket and port on which we are listening.
253: * So try and listen on another IP and port for output.
254: */
255: numOtherNames--;
256: foundFlag = 0;
257: if ((numOtherNames == 0) && (foundFlag != 1)) {
258: IOException ftpprotocolexception = new IOException(
259: "HOST");
260: // logger.info(ftpprotocolexception.getMessage());
261: logger.info("PSSRNF_CSPNSJ1070");
262: if (dataServerSock != null)
263: dataServerSock.close();
264: }
265: } else {
266: /*
267: * Data is to be received. So accept it and close the data socket.
268: * Also set the foundFlag to 1
269: */
270: dataSocket = dataServerSock.accept();
271: dataServerSock.close();
272: /*
273: * For future use, set the name of server as key and the interface IP to use as value.
274: */
275: NetFileServlet.setInterface((String) this
276: .getMachineToAccess(), (String) ipaddresses
277: .get(numOtherNames - 1));
278: foundFlag = 1;
279: }
280: } while ((foundFlag == 0) && (numOtherNames != 0));
281: return dataSocket;
282: }
283:
284: protected Socket openCachedDataConnection(String s,
285: String interface_touse) throws IOException {
286: int FTP_ERROR = 3;
287: boolean boundFlag = false;
288: java.net.ServerSocket dataServerSock = null;
289: Socket dataSocket = null;
290: byte[] abyte0 = null;
291:
292: java.net.InetAddress theAddress = java.net.InetAddress
293: .getByName(interface_touse);
294: abyte0 = theAddress.getAddress();
295: /*
296: * Keep Trying till you bind the socket on a port.
297: * unlikely that the socket will never find a port to bind on to - hence the loop till bound.
298: */
299: while (!boundFlag) {
300: try {
301: dataServerSock = new ServerSocket(0, 1, theAddress);
302: boundFlag = true;
303: } catch (java.net.BindException be) {
304: // logger.info("Could not bind on HostAddress " + theAddress.getHostAddress() + ". Address is " + theAddress.getAddress());
305: Object[] params4 = { theAddress.getHostAddress(),
306: ". Address is ", theAddress.getAddress() };
307: logger.log(Level.INFO, "PSSRNF_CSPNSJ1071", params4);
308: }
309: }
310:
311: String s1 = "PORT ";
312: /*
313: * PORT h1,h2,h3,h4,p1,p2
314: * First the Host, then the Port
315: */
316: for (int i = 0; i < abyte0.length; i++)
317: s1 = s1 + (abyte0[i] & 0xff) + ",";
318: s1 = s1 + (dataServerSock.getLocalPort() >>> 8 & 0xff) + ","
319: + (dataServerSock.getLocalPort() & 0xff);
320:
321: if (issueCommand(s1) == FTP_ERROR) {
322: // logger.info("Port Command Failed");
323: logger.info("PSSRNF_CSPNSJ1072");
324: IOException ftpprotocolexception = new IOException("PORT");
325: if (dataServerSock != null)
326: dataServerSock.close();
327: throw ftpprotocolexception;
328: }
329: if (issueCommand(s) == FTP_ERROR) {
330: // logger.info("Data Command sent. Output data from FTP Server not received.");
331: logger.info("PSSRNF_CSPNSJ1073");
332: /*
333: * The FTP Server could not reach the data socket and port on which we are listening.
334: * So try and listen on another interface IP and port for output.
335: */
336: IOException ftpprotocolexception = new IOException("HOST");
337: if (dataServerSock != null)
338: dataServerSock.close();
339: throw ftpprotocolexception;
340: } else {
341: /*
342: * Data is to be received. So accept it and close the data socket.
343: * Also set the foundFlag to 1
344: */
345: dataSocket = dataServerSock.accept();
346: dataServerSock.close();
347: }
348: return dataSocket;
349: }
350:
351: public void setMachineToAccess(String machName) {
352: machineName = machName;
353: }
354:
355: public Object getMachineToAccess() {
356: return machineName;
357: }
358:
359: /*
360: * Determines an interface on which the given FTP Server can be reached
361: * If the FTP Server name cannot be resolved by any of its names,
362: * then HOST_NOT_FOUND is returned.
363: * The first address that matches the network address of any of the interfaces is used
364: */
365: protected String findInterface(String nameOfServer,
366: Vector interfaceIPs) {
367: InetAddress[] inetAddr = null;
368: try {
369: inetAddr = InetAddress.getAllByName(nameOfServer);
370: } catch (java.net.UnknownHostException uhe) {
371: // logger.log(Level.SEVERE, "Unknown host",uhe);
372: logger.log(Level.SEVERE, "PSSRNF_CSPNSJ1074");
373: return HOST_NOT_FOUND;
374: }
375: if (inetAddr == null)
376: return HOST_NOT_FOUND;
377: for (int interfacesCount = 0; interfacesCount < (interfaceIPs
378: .size() - 1); interfacesCount++) {
379: for (int serversCount = inetAddr.length; serversCount > 0; serversCount--) {
380: String serverIPAddr = inetAddr[serversCount - 1]
381: .getHostAddress();
382: String interfaceIPAddr = (String) interfaceIPs
383: .get(interfacesCount);
384: if (serverIPAddr.substring(0,
385: serverIPAddr.lastIndexOf("."))
386: .equalsIgnoreCase(
387: interfaceIPAddr.substring(0,
388: interfaceIPAddr
389: .lastIndexOf(".")))) {
390: return interfaceIPAddr;
391: }
392: }
393: }
394: return HOST_NO_MATCH;
395: }
396:
397: /*
398: * Additions to make FullFtpClient self-sufficient
399: */
400: /*
401: * issue the QUIT command to the FTP server and close the connection.
402: */
403: public void quit() throws IOException {
404: if (serverIsOpen()) {
405: issueCommand("QUIT");
406: this .closeServer();
407: }
408: }
409:
410: protected int issueCommand(String cmd) throws IOException {
411: command = cmd;
412:
413: int reply;
414:
415: if (replyPending) {
416: if (readReply() == FTP_ERROR)
417: System.out.print("Error reading FTP pending reply\n");
418: }
419: replyPending = false;
420: do {
421: sendServer(cmd + "\r\n");
422: reply = readReply();
423: } while (reply == FTP_TRY_AGAIN);
424: return reply;
425: }
426:
427: /*
428: protected int issueCommand(String s) throws IOException {
429: int i;
430: byte bytes[] = null;
431: bytes = s.getBytes(machine_encoding);
432: // logger.info("Machine encoding="+machine_encoding);
433: Object[] params8 = {machine_encoding};
434: logger.log( Level.INFO , "PSSRNF_CSPNSJ1075" , params8 );
435:
436: do {
437: //serverOutput.write(bytes, 0, bytes.length);
438: serverOutput.print(new String(bytes,machine_encoding)+"\r\n");
439: i = readReply();
440: } while(i == 2);
441: return i;
442:
443: }
444: */
445: protected void issueCommandCheck(String cmd) throws IOException {
446: if (issueCommand(cmd) != FTP_SUCCESS)
447: throw new IOException(cmd);
448: }
449:
450: protected int readReply() throws IOException {
451: lastReplyCode = readServerResponse();
452:
453: switch (lastReplyCode / 100) {
454: case 1:
455: replyPending = true;
456:
457: case 2:
458: case 3:
459: return FTP_SUCCESS;
460:
461: case 5:
462: if (lastReplyCode == 530) {
463: if (user == null) {
464: throw new IOException("Not logged in");
465: }
466: return FTP_ERROR;
467: }
468: if (lastReplyCode == 550) {
469: throw new FileNotFoundException(command + ": "
470: + getResponseString());
471: }
472: if (lastReplyCode == 553) {
473: throw new FileNotFoundException(command + ": "
474: + getResponseString());
475: }
476: }
477:
478: /* this statement is not reached */
479: return FTP_ERROR;
480: }
481:
482: /* public methods */
483:
484: /* open a FTP connection to host <i>host</i>. */
485: public void openServer(String host) throws IOException {
486: int port = FTP_PORT;
487:
488: openServer(host, port);
489: }
490:
491: /*
492: * login user to a host with username <i>user</i> and password
493: * <i>password</i>
494: */
495: public void login(String user, String password) throws IOException {
496:
497: if (!serverIsOpen())
498: throw new IOException("not connected to host");
499: this .user = user;
500: this .password = password;
501: if (issueCommand("USER " + user) == FTP_ERROR) {
502: this .closeServer();
503: throw new IOException("user");
504: }
505: if (password != null
506: && issueCommand("PASS " + password) == FTP_ERROR) {
507: this .closeServer();
508: throw new IOException("password");
509: }
510: String l;
511: for (int i = 0; i < serverResponse.size(); i++) {
512: l = (String) serverResponse.elementAt(i);
513: if (l != null) {
514: if (l.charAt(3) != '-') {
515: break;
516: }
517: // get rid of the "230-" prefix
518: l = l.substring(4);
519: if (welcomeMsg == null) {
520: welcomeMsg = l;
521: } else {
522: welcomeMsg += l;
523: }
524: }
525: }
526: }
527:
528: /* GET a file from the FTP server */
529: public TelnetInputStream get(String filename) throws IOException {
530: try {
531: sock = openDataConnection("RETR " + filename);
532: } catch (FileNotFoundException fileException) {
533: StringTokenizer t = new StringTokenizer(filename, "/");
534: String pathElement = null;
535:
536: while (t.hasMoreElements()) {
537: pathElement = t.nextToken();
538:
539: if (!t.hasMoreElements()) {
540: /* This is the file component. Look it up now. */
541: break;
542: }
543: try {
544: cd(pathElement);
545: } catch (IOException e) {
546: /* Giving up. */
547: throw fileException;
548: }
549: }
550: if (pathElement != null) {
551: sock = openDataConnection("RETR " + pathElement);
552: } else {
553: throw fileException;
554: }
555: }
556:
557: return new TelnetInputStream(sock.getInputStream(), binaryMode);
558: }
559:
560: /* PUT a file to the FTP server */
561: public TelnetOutputStream put(String filename) throws IOException {
562: sock = openDataConnection("STOR " + filename);
563:
564: return new TelnetOutputStream(sock.getOutputStream(),
565: binaryMode);
566: }
567:
568: /* APPEND to a file on the FTP server */
569: public TelnetOutputStream append(String filename)
570: throws IOException {
571: sock = openDataConnection("APPE " + filename);
572:
573: return new TelnetOutputStream(sock.getOutputStream(),
574: binaryMode);
575: }
576:
577: /* LIST files on a remote FTP server */
578: public TelnetInputStream list() throws IOException {
579: sock = openDataConnection("LIST");
580:
581: return new TelnetInputStream(sock.getInputStream(), binaryMode);
582: }
583:
584: /* CD to a specific directory on a remote FTP server */
585: public void cd(String remoteDirectory) throws IOException {
586: issueCommandCheck("CWD " + remoteDirectory);
587: }
588:
589: /* Set transfer type to 'I' */
590: public void binary() throws IOException {
591: issueCommandCheck("TYPE I");
592: binaryMode = true;
593: }
594:
595: /* Set transfer type to 'A' */
596: public void ascii() throws IOException {
597: issueCommandCheck("TYPE A");
598: binaryMode = false;
599: }
600:
601: /*
602: * Bug 4452946
603: */
604: public sun.net.TelnetInputStream nlist() throws java.io.IOException {
605: java.net.Socket s = openDataConnection("NLST -a");
606:
607: return new sun.net.TelnetInputStream(s.getInputStream(), false);
608: }
609:
610: public sun.net.TelnetInputStream list(boolean list_al)
611: throws java.io.IOException {
612: java.net.Socket s = openDataConnection("LIST -al");
613:
614: return new sun.net.TelnetInputStream(s.getInputStream(), false);
615: }
616:
617: public sun.net.TelnetInputStream list(String filename)
618: throws java.io.IOException {
619: java.net.Socket s = openDataConnection("LIST -al " + filename);
620:
621: return new sun.net.TelnetInputStream(s.getInputStream(), false);
622: }
623:
624: /* open a FTP connection to host <i>host</i> on port <i>port</i>. */
625: public void openServerOnPort(String host, int port)
626: throws IOException {
627: // logger.info("Host="+host+",port="+port);
628: Object[] params9 = { host, ",port=", new Integer(port) };
629: logger.log(Level.INFO, "PSSRNF_CSPNSJ1076", params9);
630: this .openServer(host, port);
631: if (readReply() == FTP_ERROR)
632: throw new IOException("Welcome message");
633: }
634:
635: public void openServer(String server, int port) throws IOException,
636: UnknownHostException {
637: try {
638: if (serverSocket != null) {
639: quit();
640: }
641: serverSocket = doConnect(server, port);
642: //serverOutput = new PrintStream(new BufferedOutputStream(serverSocket.getOutputStream()),
643: //true);
644: opsw_server = new OutputStreamWriter(serverSocket
645: .getOutputStream(), machine_encoding);
646: serverInput = new BufferedInputStream(serverSocket
647: .getInputStream());
648:
649: } catch (Exception e) {
650: // logger.log(Level.SEVERE, "Exception in opening connection to FTP server",e);
651: logger.log(Level.SEVERE, "PSSRNF_CSPNSJ1077");
652: if (e instanceof IOException) {
653: throw (IOException) e;
654: }
655: if (e instanceof UnknownHostException) {
656: throw (UnknownHostException) e;
657: }
658: }
659: }
660:
661: public void closeDataConnection() {
662: try {
663: if (sock != null)
664: sock.close();
665: } catch (Exception e) {
666: }
667: sock = null;
668: }
669:
670: public void closeServer() throws IOException {
671: if (!serverIsOpen()) {
672: return;
673: }
674: opsw_server.close();
675: serverSocket.close();
676: serverInput.close();
677:
678: closeDataConnection();
679:
680: serverSocket = null;
681: serverInput = null;
682: //serverOutput = null;
683: opsw_server = null;
684: }
685:
686: /* Sends command <i>cmd</i> to the server. */
687: public void sendServer(String cmd) {
688: try {
689: opsw_server.write(cmd);
690: opsw_server.flush();
691: } catch (Exception e) {
692: // logger.log(Level.SEVERE, "Exception in sending command to the server",e);
693: logger.log(Level.SEVERE, "PSSRNF_CSPNSJ1078");
694: }
695:
696: }
697: }
|