001/* 002 * Version 0.70 01/04/2002 003 * 004 * Visit my url for update: http://www.geocities.com/beapetrovicova/ 005 * 006 * jFtp was developed by Bea Petrovicova <beapetrovicova@yahoo.com>. 007 * The design and implementation of jFtp are available for royalty-free 008 * adoption and use. This software is provided 'as is' without any 009 * guarantees. Copyright is retained by Bea Petrovicova. Redistribution 010 * of any part of jFtp or any derivative works must include this notice. 011 * 012 */ 013package cz.dhl.ftp; 014 015import java.io.FileNotFoundException; 016import java.io.IOException; 017import java.io.InputStream; 018import java.io.OutputStream; 019import java.net.InetAddress; 020import java.net.ServerSocket; 021import java.net.Socket; 022import java.net.SocketException; 023import java.net.UnknownHostException; 024import java.util.StringTokenizer; 025import java.util.NoSuchElementException; 026 027final class FtpDataSocket 028{ private ServerSocket dataserver = null; 029 private Socket data = null; 030 031 FtpContext context = null; 032 private FtpControlSocket control = null; 033 034 FtpDataSocket(Ftp client) throws IOException 035 { if(client.isConnected()) 036 { this.control = client.control; 037 this.context = client.getContext(); 038 } else { throw new IOException("Data: CreateSocket, No Connection!"); } 039 } 040 041 /** @return Connect string. 042 * Using format: 'h1,h2,h3,h4,p1,p2'; */ 043 String getConnect(String reply) throws NumberFormatException 044 { if(reply==null) 045 throw new NumberFormatException 046 ("Null Reply!\n"); 047 048 int begin = reply.indexOf('('); 049 int end = reply.indexOf(')'); 050 if(begin!=-1 && end !=-1 && begin < end) 051 return reply.substring(begin+1,end); 052 else throw new NumberFormatException 053 ("Invalid Reply!\n"+reply); } 054 055 /** @param connect Remote hostport number string.<BR> 056 * Expected format: 'h1,h2,h3,h4,p1,p2'<BR> 057 * h1..h4 - IP address; p1,p2 - port number; 058 * @return IP address<BR> 059 Using format: 'h1.h2.h3.h4' */ 060 String getConnectAddress(String connect) throws NumberFormatException 061 { int s4=-1; 062 for(int i=0;i<4;i++) 063 if((s4=connect.indexOf(',',s4+1))==-1) 064 throw new NumberFormatException 065 ("Misformated Reply! " +i+":"+s4 +" " +connect); 066 return connect.substring(0,s4).replace(',','.'); } 067 068 /** @param connect Remote hostport number string.<BR> 069 * Expected format: 'h1,h2,h3,h4,p1,p2'<BR> 070 * h1..h4 - IP address; p1,p2 - port number; 071 * @return Port number. */ 072 int getConnectPort(String connect) 073 throws NumberFormatException, NoSuchElementException 074 { int s4=-1; 075 for(int i=0;i<4;i++) 076 if((s4=connect.indexOf(',',s4+1))==-1) 077 throw new NumberFormatException 078 ("Misformated Reply! " +i+":"+s4 +" " +connect); 079 StringTokenizer tokenizer = new StringTokenizer(connect.substring(s4+1),","); 080 return Integer.parseInt(tokenizer.nextToken())*256+ 081 Integer.parseInt(tokenizer.nextToken()); } 082 083 084 void openPassiveDataSocket(String commandline, char type) throws IOException 085 { if(control.isConnected()) 086 { try 087 { 088 control.executeCommand("TYPE " + type); 089 control.executeCommand("PASV"); 090 String connect = getConnect(control.replyOfCommand()); 091 String address = getConnectAddress(connect); 092 int port = getConnectPort(connect); 093 data = new Socket(address, port); 094 data.setSoTimeout(60000); 095 if(!control.executeCommand(commandline)) 096 throw new IOException(control.replyOfCommand()); 097 } 098 catch(NoSuchElementException e) 099 { throw new IOException("Data: OpenSocket, Invalid Format!\n"+e); } 100 catch(NumberFormatException e) 101 { throw new IOException("Data: OpenSocket, Invalid Format!\n"+e); } 102 catch(SocketException e) 103 { throw new IOException("Data: OpenSocket, Socket Error!\n"+e); } 104 catch(IOException e) 105 { throw new IOException("Data: OpenSocket, IO Error!\n"+e); } 106 catch(Exception e) 107 { throw new IOException("Data: OpenSocket, Permission Denied?\n"+e); } 108 } else { throw new IOException("Data: OpenSocket, No Connection!"); } 109 } 110 111 /** 112 * @return Local hostport number string, 113 * Using format: 'h1,h2,h3,h4,p1,p2'<BR> 114 * h1..h4 - IP address; p1,p2 - port number; */ 115 String getConnect() throws UnknownHostException 116 { short port = (short) dataserver.getLocalPort(); 117 return ((InetAddress.getLocalHost()).getHostAddress()).replace('.',',') 118 + "," + port/256 + "," + port%256; } 119 120 void openActiveDataSocket(String commandline, char type) throws IOException 121 { if(control.isConnected()) 122 { try 123 { 124 control.executeCommand("TYPE " + type); 125 dataserver = new ServerSocket(0); 126 dataserver.setSoTimeout(20000); 127 control.executeCommand("PORT " + getConnect()); 128 synchronized(control) 129 { control.writeCommand(commandline); 130 data=dataserver.accept(); 131 data.setSoTimeout(60000); 132 if(!control.completeCommand(FtpInterpret.getReplies(commandline))) 133 throw new IOException(control.replyOfCommand()); } 134 } 135 catch(SocketException e) 136 { throw new IOException("Data: OpenSocket, Socket Error!\n"+e); } 137 catch(IOException e) 138 { throw new IOException("Data: OpenSocket, IO Error!\n"+e); } 139 catch(Exception e) 140 { throw new IOException("Data: OpenSocket, Permission Denied!\n"+e); } 141 } else { throw new IOException("Data: OpenSocket, No Connection!"); } 142 } 143 144 void openDataSocket(String commandline, char type) throws IOException 145 { if(context.getActiveSocketMode()) 146 openActiveDataSocket(commandline,type); 147 else openPassiveDataSocket(commandline,type); } 148 149 InputStream getInputStream(String commandline, char type) throws IOException 150 { if(data==null) 151 openDataSocket(commandline,type); 152 return data.getInputStream(); } 153 154 OutputStream getOutputStream(String commandline, char type) throws IOException 155 { if(data==null) 156 openDataSocket(commandline,type); 157 return data.getOutputStream(); } 158 159 void close() throws IOException 160 { try { if(data!=null) data.close(); } finally 161 { data=null; 162 if(control.isConnected()) 163 { if(!control.completeCommand(FtpInterpret.getReplies("data-done"))) 164 { control.executeCommand("ABOR"); 165 throw new IOException("Data: CloseSocket, Transfer Aborted!"); } 166 } else { throw new IOException("Data: CloseSocket, No Connection!"); } 167 try { if(dataserver!=null) dataserver.close(); } finally 168 { dataserver=null; } 169 } 170 } 171}