Many bugfixes and improvements

This commit is contained in:
Ziver Koc 2011-06-24 23:20:59 +00:00
parent c3e3bbf787
commit 363e0c6cfc
52 changed files with 2021 additions and 982 deletions

View file

@ -1,134 +0,0 @@
package zutil.net;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.util.ArrayList;
import zutil.ProgressListener;
import zutil.io.MultiPrintStream;
import zutil.io.file.FileUtil;
/**
* This class connects to a update server and updates a path
* with the servers
*
* @author Ziver
*
*/
public class UpdateClient{
private ArrayList<FileHash> clientFileList;
private Socket socket;
private String path;
private ProgressListener progress;
private int speed;
private long totalReceived;
/**
* Creates a UpdateClient
*
* @param address Address to the UpdateServer
* @param port The port on the server
* @param path Path to the files to update
* @throws Exception
*/
public UpdateClient(String address, int port, String path) throws Exception{
clientFileList = UpdateServer.getFileList(path);
socket = new Socket(address, port);
this.path = path;
}
public void setProgressListener(ProgressListener p){
progress = p;
}
/**
* Updates the files
*
* @throws Exception
*/
public void update() throws Exception{
ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream());
ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
// send client file list
out.writeObject(clientFileList);
out.flush();
// receive file updates
FileHash fileInfo = (FileHash)in.readObject();
File tmpPath = FileUtil.find(path);
while(!fileInfo.path.isEmpty()){
MultiPrintStream.out.println("Updating: "+path+fileInfo.path);
// reading new file data
File file = new File(tmpPath.getAbsolutePath()+fileInfo.path);
File tmpFile = File.createTempFile(file.getName(), ".tmp", tmpPath);
tmpFile.getParentFile().mkdirs();
tmpFile.deleteOnExit();
FileOutputStream fileOut = new FileOutputStream(tmpFile);
byte[] buffer = new byte[socket.getReceiveBufferSize()];
int bytesReceived = 0;
totalReceived = 0;
long time = System.currentTimeMillis();
long timeTotalRecived = 0;
while((bytesReceived = in.read(buffer)) > 0) {
fileOut.write(buffer, 0, bytesReceived);
if(time+1000 < System.currentTimeMillis()){
time = System.currentTimeMillis();
speed = (int)(totalReceived - timeTotalRecived);
timeTotalRecived = totalReceived;
}
totalReceived += bytesReceived;
if(progress != null) progress.progressUpdate(this, fileInfo, (double)totalReceived/fileInfo.size*100);
}
fileOut.close();
speed = 0;
// delete old file and replace whit new
file.delete();
if(!tmpFile.renameTo(file)){
throw new Exception("Cannot update file: "+file.getAbsolutePath());
}
// read new message
fileInfo = (FileHash)in.readObject();
}
MultiPrintStream.out.println("Update Done!!");
}
/**
* Returns the speed of the transfer
*
* @return The speed in bytes/s
*/
public int speed(){
return speed;
}
/**
* Returns the total amount of data received for the
* current file
*
* @return The speed in bytes/s
*/
public long totalReceived(){
return totalReceived;
}
/**
* Closes the connection
*
* @throws IOException
*/
public void close() throws IOException{
socket.close();
}
}

View file

@ -1,166 +0,0 @@
package zutil.net;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.URISyntaxException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
import zutil.Hasher;
import zutil.io.MultiPrintStream;
import zutil.io.file.FileUtil;
public class UpdateServer extends Thread{
private ArrayList<FileHash> fileList;
private ServerSocket server;
private boolean close;
private String path;
/**
* Creates a UpdateServer Thread
*
* @param path The path to sync the clients with
* @throws IOException
* @throws URISyntaxException
* @throws NoSuchAlgorithmException
*/
public UpdateServer(int port, String path) throws Exception{
fileList = getFileList(path);
server = new ServerSocket(port);
close = false;
this.path = path;
this.start();
MultiPrintStream.out.println("Update Server Online!!!");
}
public void run(){
while (!close){
try {
new UpdateServerThread(server.accept()).start();
MultiPrintStream.out.println("Update Server: Client Connected!!!");
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* Handles all the connecting clients
*
* @author Ziver
*/
class UpdateServerThread extends Thread{
private ObjectOutputStream out;
private ObjectInputStream in;
private Socket client;
/**
* Creates a UpdateServerThread
* @param client The socket to the client
* @throws IOException
*/
public UpdateServerThread(Socket c) throws IOException {
client = c;
out = new ObjectOutputStream(client.getOutputStream());
in = new ObjectInputStream(client.getInputStream());
}
@SuppressWarnings("unchecked")
public void run(){
try {
// receive the clients filelist
ArrayList<FileHash> clientFileList = (ArrayList<FileHash>)in.readObject();
File tmpPath = FileUtil.find(path);
for(FileHash file : fileList){
if(!clientFileList.contains(file)){
// send new file to client
out.writeObject(file);
out.flush();
// send file data
FileInputStream input = new FileInputStream(tmpPath.getAbsolutePath()+file.path);
byte[] nextBytes = new byte[client.getSendBufferSize()];
int bytesRead = 0;
while((bytesRead = input.read(nextBytes)) > 0){
out.write(nextBytes,0,bytesRead);
}
}
}
// send update done message
out.writeObject(new FileHash("","",0));
out.flush();
out.close();
in.close();
client.close();
} catch (Exception e) {
MultiPrintStream.out.println("Update Server: Client Error!!! "+e.getMessage());
} finally {
MultiPrintStream.out.println("Update Server: Client Update Done!!!");
}
}
}
/**
* Returns a ArrayList with all the files in the specified folder and there
* MD5 hashes
*
* @param path The path to search
* @return A ArrayList with all the files in the path
* @throws URISyntaxException
* @throws NoSuchAlgorithmException
* @throws IOException
*/
public static ArrayList<FileHash> getFileList(String path) throws Exception{
ArrayList<FileHash> fileHash = new ArrayList<FileHash>();
List<File> files = FileUtil.search(FileUtil.find(path));
for(File file : files){
fileHash.add(new FileHash(
FileUtil.relativePath(file, path),
Hasher.hash(file, "MD5"),
file.length()));
}
return fileHash;
}
}
/**
* This class is used to store the files
* and there hashes
*
* @author Ziver
*/
class FileHash implements Serializable{
private static final long serialVersionUID = 1L;
public String path;
public String hash;
public long size;
public FileHash(String p, String h, long s){
path = p;
hash = h;
size = s;
}
public boolean equals(Object comp){
FileHash tmp = (FileHash)comp;
return path.equals(tmp.path) && hash.equals(tmp.hash);
}
public String toString(){
return path;
}
}

View file

@ -1,232 +0,0 @@
/*
* Zupdater.java
*
* Created on den 27 juli 2008, 23:32
*/
package zutil.net;
import java.awt.Dimension;
import zutil.ProgressListener;
import zutil.StringUtil;
/**
*
* @author Ziver
*/
public class Zupdater extends javax.swing.JFrame implements ProgressListener{
private static final long serialVersionUID = 1L;
/** Creates new form Zupdater */
public Zupdater() {
super("Zupdater");
initComponents();
centerScreen();
setVisible(true);
}
public void centerScreen(){
Dimension screen = getToolkit().getScreenSize();
this.setBounds(
(screen.width-getWidth())/2,
(screen.height-getHeight())/2,
getWidth(),
getHeight() );
}
public void progressUpdate(Object source, Object info, double percent) {
if(info instanceof FileHash){
FileHash fileHash = (FileHash) info;
fileLabel.setText(fileHash.toString());
fileProgressBar.setValue((int)percent);
percentLabel.setText((int)percent+"%");
speedLabel.setText(StringUtil.formatBytesToString(((UpdateClient)source).speed())+"/s");
transferedLabel.setText(StringUtil.formatBytesToString(((UpdateClient)source).totalReceived())+
" / "+StringUtil.formatBytesToString(fileHash.size));
}
}
/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {
jSeparator1 = new javax.swing.JSeparator();
cancelButton = new javax.swing.JButton();
jPanel1 = new javax.swing.JPanel();
jLabel1 = new javax.swing.JLabel();
totalProgressBar = new javax.swing.JProgressBar();
jLabel2 = new javax.swing.JLabel();
fileProgressBar = new javax.swing.JProgressBar();
fileLabel = new javax.swing.JLabel();
totalProgressLabel = new javax.swing.JLabel();
speedLabel = new javax.swing.JLabel();
percentLabel = new javax.swing.JLabel();
transferedLabel = new javax.swing.JLabel();
etaLabel = new javax.swing.JLabel();
jLabel3 = new javax.swing.JLabel();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
cancelButton.setText("Cancel");
cancelButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
cancel();
}
});
jPanel1.setBorder(javax.swing.BorderFactory.createTitledBorder("Update"));
jLabel1.setFont(new java.awt.Font("Tahoma", 1, 11));
jLabel1.setText("Total Progress:");
totalProgressBar.setIndeterminate(true);
jLabel2.setFont(new java.awt.Font("Tahoma", 1, 11));
jLabel2.setText("File: ");
fileLabel.setFont(new java.awt.Font("Tahoma", 0, 11));
fileLabel.setText("file");
totalProgressLabel.setFont(new java.awt.Font("Tahoma", 0, 11));
totalProgressLabel.setText("totalProgress");
speedLabel.setFont(new java.awt.Font("Tahoma", 1, 11));
speedLabel.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
speedLabel.setText("speed");
percentLabel.setFont(new java.awt.Font("Tahoma", 1, 11));
percentLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
percentLabel.setText("0%");
transferedLabel.setFont(new java.awt.Font("Tahoma", 2, 11));
transferedLabel.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
transferedLabel.setText("transfer");
etaLabel.setFont(new java.awt.Font("Tahoma", 0, 11));
etaLabel.setHorizontalAlignment(javax.swing.SwingConstants.LEFT);
etaLabel.setText("eta");
jLabel3.setFont(new java.awt.Font("Tahoma", 1, 11));
jLabel3.setText("ETA:");
javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
jPanel1.setLayout(jPanel1Layout);
jPanel1Layout.setHorizontalGroup(
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel1Layout.createSequentialGroup()
.addContainerGap()
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel1Layout.createSequentialGroup()
.addComponent(jLabel1)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(totalProgressLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 464, Short.MAX_VALUE))
.addComponent(totalProgressBar, javax.swing.GroupLayout.DEFAULT_SIZE, 555, Short.MAX_VALUE)
.addComponent(fileProgressBar, javax.swing.GroupLayout.DEFAULT_SIZE, 555, Short.MAX_VALUE)
.addGroup(jPanel1Layout.createSequentialGroup()
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jLabel2)
.addComponent(jLabel3))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel1Layout.createSequentialGroup()
.addComponent(etaLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 175, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(percentLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 130, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(transferedLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 207, Short.MAX_VALUE))
.addGroup(jPanel1Layout.createSequentialGroup()
.addComponent(fileLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 399, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(speedLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 119, Short.MAX_VALUE)))))
.addContainerGap())
);
jPanel1Layout.setVerticalGroup(
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel1Layout.createSequentialGroup()
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(jLabel1)
.addComponent(totalProgressLabel))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(totalProgressBar, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(jLabel2)
.addComponent(fileLabel)
.addComponent(speedLabel))
.addGap(6, 6, 6)
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(jLabel3)
.addComponent(etaLabel)
.addComponent(transferedLabel)
.addComponent(percentLabel))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(fileProgressBar, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jSeparator1, javax.swing.GroupLayout.DEFAULT_SIZE, 587, Short.MAX_VALUE)
.addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(cancelButton, javax.swing.GroupLayout.Alignment.TRAILING))
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(cancelButton)
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
pack();
}// </editor-fold>
public void cancel(){
System.exit(0);
}
/**
* @param args the command line arguments
*/
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new Zupdater().setVisible(true);
}
});
}
// Variables declaration - do not modify
private javax.swing.JButton cancelButton;
private javax.swing.JLabel etaLabel;
private javax.swing.JLabel fileLabel;
private javax.swing.JProgressBar fileProgressBar;
private javax.swing.JLabel jLabel1;
private javax.swing.JLabel jLabel2;
private javax.swing.JLabel jLabel3;
private javax.swing.JPanel jPanel1;
private javax.swing.JSeparator jSeparator1;
private javax.swing.JLabel percentLabel;
private javax.swing.JLabel speedLabel;
private javax.swing.JProgressBar totalProgressBar;
private javax.swing.JLabel totalProgressLabel;
private javax.swing.JLabel transferedLabel;
// End of variables declaration
}

View file

@ -0,0 +1,98 @@
package zutil.net.http;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.URL;
import java.util.HashMap;
import zutil.net.http.HttpPrintStream.HttpMessageType;
/**
* This class connects to a HTTP server and
* parses the result
*
* @author Ziver
*/
public class HttpClient {
public static enum HttpRequestType{
GET, POST
}
private HttpURL url;
private HttpRequestType type;
private HashMap<String,String> headers;
private HashMap<String,String> cookies;
public static HttpClient POST(){
return new HttpClient( HttpRequestType.POST );
}
public static HttpClient GET(){
return new HttpClient( HttpRequestType.GET );
}
private HttpClient(HttpRequestType type){
this.type = type;
headers = new HashMap<String,String>();
cookies = new HashMap<String,String>();
}
public void setURL( URL url){
this.url = new HttpURL( url );
}
/**
* Adds a parameter to the request
*/
public void setParameter( String key, String value ){
url.setParameter(key, value);
}
/**
* Adds a cookie to the request
*/
public void setCookie( String key, String value ){
cookies.put(key, value);
}
/**
* Adds a header value to the request
*/
public void setHeader( String key, String value ){
headers.put(key, value);
}
public HttpHeaderParser send() throws IOException{
Socket conn = new Socket( url.getHost(), url.getPort());
// Request
HttpPrintStream request = new HttpPrintStream( conn.getOutputStream(), HttpMessageType.REQUEST );
request.setRequestType( type.toString() );
request.setRequestURL( url.getHttpURL() );
request.setHeaders( headers );
request.setCookies( cookies );
if( type == HttpRequestType.POST ){
String data = url.getParameterString();
request.setHeader("Content-Length", data);
request.println();
request.print( data );
}
else
request.println("");
request.flush();
// Response
BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
HttpHeaderParser response = new HttpHeaderParser( in );
conn.close();
return response;
}
}

View file

@ -6,7 +6,7 @@ import java.util.HashMap;
import java.util.Scanner;
import java.util.regex.Pattern;
public class HTTPHeaderParser {
public class HttpHeaderParser {
// Some Cached regex's
private static final Pattern colonPattern = Pattern.compile(":");
private static final Pattern equalPattern = Pattern.compile("=");
@ -30,7 +30,7 @@ public class HTTPHeaderParser {
* @param in is the stream
* @throws IOException
*/
public HTTPHeaderParser(BufferedReader in) throws IOException{
public HttpHeaderParser(BufferedReader in) throws IOException{
url_attr = new HashMap<String, String>();
headers = new HashMap<String, String>();
cookies = new HashMap<String, String>();
@ -50,7 +50,7 @@ public class HTTPHeaderParser {
*
* @param in is the string
*/
public HTTPHeaderParser(String in){
public HttpHeaderParser(String in){
url_attr = new HashMap<String, String>();
headers = new HashMap<String, String>();
cookies = new HashMap<String, String>();
@ -92,7 +92,7 @@ public class HTTPHeaderParser {
if(index > -1){
url = line.substring(0, index );
line = line.substring( index+1, line.length());
parseUrlAttributes(line, url_attr);
parseURLParameters(line, url_attr);
}
else{
url = line;
@ -108,9 +108,9 @@ public class HTTPHeaderParser {
*
* @param attributes is the String containing all the attributes
*/
public static HashMap<String, String> parseUrlAttributes( String attributes ){
public static HashMap<String, String> parseURLParameters( String attributes ){
HashMap<String, String> map = new HashMap<String, String>();
parseUrlAttributes(attributes, map);
parseURLParameters(attributes, map);
return map;
}
@ -121,7 +121,7 @@ public class HTTPHeaderParser {
* @param attributes is the String containing all the attributes
* @param map is the HashMap to put all the values into
*/
public static void parseUrlAttributes(String attributes, HashMap<String, String> map){
public static void parseURLParameters(String attributes, HashMap<String, String> map){
String[] tmp;
// get the variables
String[] data = andPattern.split( attributes );

View file

@ -13,13 +13,13 @@ import java.util.HashMap;
*/
public class HttpPrintStream extends PrintStream{
// Defines the type of message
public enum HTTPMessageType{
public enum HttpMessageType{
REQUEST,
RESPONSE
}
// This defines the type of message that will be generated
private HTTPMessageType message_type;
private HttpMessageType message_type;
// The status code of the message, ONLY for response
private Integer res_status_code;
// The request type of the message ONLY for request
@ -27,9 +27,9 @@ public class HttpPrintStream extends PrintStream{
// The requesting url ONLY for request
private String req_url;
// An Map of all the header values
private HashMap<String, String> header;
private HashMap<String, String> headers;
// An Map of all the cookies
private HashMap<String, String> cookie;
private HashMap<String, String> cookies;
// The buffered header
private StringBuffer buffer;
// If the header buffering is enabled
@ -42,7 +42,7 @@ public class HttpPrintStream extends PrintStream{
* @param out is the OutputStream to send the message
*/
public HttpPrintStream(OutputStream out) {
this( out, HTTPMessageType.RESPONSE );
this( out, HttpMessageType.RESPONSE );
}
/**
* Creates an new instance of HttpPrintStream with
@ -51,13 +51,13 @@ public class HttpPrintStream extends PrintStream{
* @param out is the OutputStream to send the message
* @param type is the type of message
*/
public HttpPrintStream(OutputStream out, HTTPMessageType type) {
public HttpPrintStream(OutputStream out, HttpMessageType type) {
super(out);
this.message_type = type;
res_status_code = 0;
header = new HashMap<String, String>();
cookie = new HashMap<String, String>();
headers = new HashMap<String, String>();
cookies = new HashMap<String, String>();
buffer = new StringBuffer();
buffer_enabled = false;
}
@ -84,9 +84,9 @@ public class HttpPrintStream extends PrintStream{
* @throws Exception Throws exception if the header has already been sent
*/
public void setCookie(String key, String value) throws RuntimeException{
if(cookie == null)
if(cookies == null)
throw new RuntimeException("Header already sent!!!");
cookie.put(key, value);
cookies.put(key, value);
}
/**
@ -97,9 +97,9 @@ public class HttpPrintStream extends PrintStream{
* @throws Exception Throws exception if the header has already been sent
*/
public void setHeader(String key, String value) throws RuntimeException{
if(header == null)
if(headers == null)
throw new RuntimeException("Header already sent!!!");
header.put(key, value);
headers.put(key, value);
}
/**
@ -111,7 +111,7 @@ public class HttpPrintStream extends PrintStream{
public void setStatusCode(int code) throws RuntimeException{
if( res_status_code == null )
throw new RuntimeException("Header already sent!!!");
if( message_type != HTTPMessageType.RESPONSE )
if( message_type != HttpMessageType.RESPONSE )
throw new RuntimeException("Status Code is only available in HTTP RESPONSE!!!");
res_status_code = code;
}
@ -125,7 +125,7 @@ public class HttpPrintStream extends PrintStream{
public void setRequestType(String req_type) throws RuntimeException{
if( req_type == null )
throw new RuntimeException("Header already sent!!!");
if( message_type != HTTPMessageType.REQUEST )
if( message_type != HttpMessageType.REQUEST )
throw new RuntimeException("Request Message Type is only available in HTTP REQUEST!!!");
this.req_type = req_type;
}
@ -138,11 +138,18 @@ public class HttpPrintStream extends PrintStream{
public void setRequestURL(String req_url) throws RuntimeException{
if( req_url == null )
throw new RuntimeException("Header already sent!!!");
if( message_type != HTTPMessageType.REQUEST )
if( message_type != HttpMessageType.REQUEST )
throw new RuntimeException("Request URL is only available in HTTP REQUEST!!!");
this.req_url = req_url;
}
protected void setHeaders( HashMap<String,String> map ){
headers = map;
}
protected void setCookies( HashMap<String,String> map ){
cookies = map;
}
/**
* Prints with a new line
*/
@ -166,40 +173,40 @@ public class HttpPrintStream extends PrintStream{
}
else{
if(res_status_code != null){
if( message_type==HTTPMessageType.REQUEST )
super.print(req_type+" "+req_url+" HTTP/1.1");
if( message_type==HttpMessageType.REQUEST )
super.print(req_type+" "+req_url+" HTTP/1.0");
else
super.print("HTTP/1.1 "+res_status_code+" "+getStatusString(res_status_code));
super.print("HTTP/1.0 "+res_status_code+" "+getStatusString(res_status_code));
super.println();
res_status_code = null;
req_type = null;
req_url = null;
}
if(header != null){
for(String key : header.keySet()){
super.print(key+": "+header.get(key));
if(headers != null){
for(String key : headers.keySet()){
super.print(key+": "+headers.get(key));
super.println();
}
header = null;
headers = null;
}
if(cookie != null){
if( !cookie.isEmpty() ){
if( message_type==HTTPMessageType.REQUEST ){
if(cookies != null){
if( !cookies.isEmpty() ){
if( message_type==HttpMessageType.REQUEST ){
super.print("Cookie: ");
for(String key : cookie.keySet()){
super.print(key+"="+cookie.get(key)+"; ");
for(String key : cookies.keySet()){
super.print(key+"="+cookies.get(key)+"; ");
}
super.println();
}
else{
for(String key : cookie.keySet()){
super.print("Set-Cookie: "+key+"="+cookie.get(key)+";");
for(String key : cookies.keySet()){
super.print("Set-Cookie: "+key+"="+cookies.get(key)+";");
super.println();
}
}
}
super.println();
cookie = null;
cookies = null;
}
super.print(s);
}
@ -215,7 +222,7 @@ public class HttpPrintStream extends PrintStream{
buffer.delete(0, buffer.length());
buffer_enabled = true;
}
else if(res_status_code != null || header != null || cookie != null){
else if(res_status_code != null || headers != null || cookies != null){
printOrBuffer("");
}
super.flush();

View file

@ -151,7 +151,7 @@ public class HttpServer extends ThreadedTCPNetworkServer{
try {
logger.finer("Reciving Http Request!!!");
HTTPHeaderParser parser = new HTTPHeaderParser(in);
HttpHeaderParser parser = new HttpHeaderParser(in);
logger.finest(parser.toString());
client_info = parser.getHeaders();
request = parser.getURLAttributes();
@ -173,7 +173,7 @@ public class HttpServer extends ThreadedTCPNetworkServer{
tmp = parser.getHeader("Content-Type");
if( tmp.contains("application/x-www-form-urlencoded") ){
// get the variables
HTTPHeaderParser.parseUrlAttributes( tmpb.toString(), request );
HttpHeaderParser.parseURLParameters( tmpb.toString(), request );
}
else if( tmp.contains("application/soap+xml" ) ||
tmp.contains("text/xml") ||

View file

@ -0,0 +1,139 @@
package zutil.net.http;
import java.net.URL;
import java.util.HashMap;
/**
* Handles URLs in the HTTP protocol
*
* @author Ziver
*/
public class HttpURL {
public static final String PROTOCOL_SEPARATOR = "://";
public static final String PORT_SEPARATOR = ":";
public static final String PATH_SEPARATOR = "/";
public static final String PARAMETER_SEPARATOR = "?";
public static final String ANCHOR_SEPARATOR = "#";
private String protocol = "";
private String host = "127.0.0.1";
private int port = -1;
private String path;
private String anchor;
private HashMap<String,String> parameters = new HashMap<String,String>();
public HttpURL(){}
public HttpURL( URL url ){
this.setProtocol( url.getProtocol() );
this.setHost( url.getHost() );
this.setPort( url.getPort() );
this.setPath( url.getPath() );
}
public String getProtocol( ){
return protocol;
}
public String getHost( ){
return host;
}
public int getPort( ){
return port;
}
public String getPath( ){
return path;
}
public String getAnchor( ){
return anchor;
}
public void setProtocol( String prot ){
this.protocol = prot;
}
public void setHost( String host ){
this.host = host;
}
public void setPort( int port ){
this.port = port;
}
public void setPath( String path ){
if( path.length() >= 1 && !path.startsWith(PATH_SEPARATOR))
path = PATH_SEPARATOR + path;
this.path = path;
}
public void setAnchor( String anch ){
this.anchor = anch;
}
public void setParameter( String key, String value ){
this.parameters.put(key, value);
}
protected void setParameters( HashMap<String,String> pars ){
this.parameters = pars;
}
/**
* Generates the parameter string in a URL.
*
* e.g.
* "key=value&key2=value&..."
*/
public String getParameterString(){
StringBuilder param = new StringBuilder();
for(String key : parameters.keySet()){
param.append(key);
param.append('=');
param.append( parameters.get(key) );
param.append('&');
}
if( param.length() > 0 )
param.deleteCharAt( param.length()-1 );
return param.toString();
}
/**
* Generates a path that are used in the HTTP header
*/
public String getHttpURL(){
StringBuilder url = new StringBuilder();
url.append( path );
if( !parameters.isEmpty() )
url.append( PARAMETER_SEPARATOR ).append( getParameterString() );
return url.toString();
}
/**
* Generates a full URL
*/
public String getURL(){
return toString();
}
/**
* Generates the whole URL
*/
public String toString(){
StringBuilder url = new StringBuilder();
url.append( protocol );
url.append( PROTOCOL_SEPARATOR );
url.append( host );
if( port > 0 )
url.append( PORT_SEPARATOR ).append( port );
if( path != null )
url.append( path );
else
url.append( PATH_SEPARATOR );
if( !parameters.isEmpty() )
url.append( PARAMETER_SEPARATOR ).append( getParameterString() );
if( anchor != null )
url.append( ANCHOR_SEPARATOR ).append( anchor );
return url.toString();
}
}

View file

@ -13,7 +13,7 @@ import java.util.List;
import javax.servlet.http.HttpServletRequest;
import zutil.ProgressListener;
import zutil.net.http.HTTPHeaderParser;
import zutil.net.http.HttpHeaderParser;
/**
* Parses a multipart/form-data http request,
@ -35,11 +35,11 @@ public class MultipartParser {
private BufferedReader in;
/** This is the listener that will listen on the progress */
private ProgressListener<MultipartField> listener;
private ProgressListener<MultipartParser,MultipartField> listener;
public MultipartParser(BufferedReader in, HTTPHeaderParser header){
public MultipartParser(BufferedReader in, HttpHeaderParser header){
this.in = in;
String cotype = header.getHeader("Content-type");
@ -69,7 +69,7 @@ public class MultipartParser {
/**
* @param listener is the listener that will be called for progress
*/
public void setListener(ProgressListener<MultipartField> listener){
public void setListener(ProgressListener<MultipartParser,MultipartField> listener){
this.listener = listener;
}

View file

@ -10,7 +10,7 @@ import java.util.logging.Logger;
import zutil.io.StringOutputStream;
import zutil.log.LogUtil;
import zutil.net.http.HTTPHeaderParser;
import zutil.net.http.HttpHeaderParser;
import zutil.net.http.HttpPrintStream;
import zutil.net.threaded.ThreadedUDPNetwork;
import zutil.net.threaded.ThreadedUDPNetworkThread;
@ -75,7 +75,7 @@ public class SSDPClient extends ThreadedUDPNetwork implements ThreadedUDPNetwork
// Generate an SSDP discover message
StringOutputStream msg = new StringOutputStream();
HttpPrintStream http = new HttpPrintStream( msg, HttpPrintStream.HTTPMessageType.REQUEST );
HttpPrintStream http = new HttpPrintStream( msg, HttpPrintStream.HttpMessageType.REQUEST );
http.setRequestType("M-SEARCH");
http.setRequestURL("*");
http.setHeader("Host", SSDPServer.SSDP_MULTICAST_ADDR+":"+SSDPServer.SSDP_PORT );
@ -150,7 +150,7 @@ public class SSDPClient extends ThreadedUDPNetwork implements ThreadedUDPNetwork
* Location: http://localhost:80
*/
public void receivedPacket(DatagramPacket packet, ThreadedUDPNetwork network) {
HTTPHeaderParser header = new HTTPHeaderParser( new String( packet.getData() ) );
HttpHeaderParser header = new HttpHeaderParser( new String( packet.getData() ) );
logger.log(Level.FINEST, "*********** Recived\n"+header);
String usn = header.getHeader("USN");

View file

@ -12,7 +12,7 @@ import java.util.logging.Logger;
import zutil.io.MultiPrintStream;
import zutil.io.StringOutputStream;
import zutil.log.LogUtil;
import zutil.net.http.HTTPHeaderParser;
import zutil.net.http.HttpHeaderParser;
import zutil.net.http.HttpPrintStream;
import zutil.net.threaded.ThreadedUDPNetworkThread;
import zutil.net.threaded.ThreadedUDPNetwork;
@ -155,7 +155,7 @@ public class SSDPServer extends ThreadedUDPNetwork implements ThreadedUDPNetwork
try {
String msg = new String( packet.getData() );
HTTPHeaderParser header = new HTTPHeaderParser( msg );
HttpHeaderParser header = new HttpHeaderParser( msg );
logger.log(Level.FINEST, "**** Received:\n"+header);
// ******* Respond
@ -233,7 +233,7 @@ public class SSDPServer extends ThreadedUDPNetwork implements ThreadedUDPNetwork
try {
// Generate the SSDP response
StringOutputStream msg = new StringOutputStream();
HttpPrintStream http = new HttpPrintStream( msg, HttpPrintStream.HTTPMessageType.REQUEST );
HttpPrintStream http = new HttpPrintStream( msg, HttpPrintStream.HttpMessageType.REQUEST );
http.setRequestType("NOTIFY");
http.setRequestURL("*");
http.setHeader("Server", SERVER_INFO );
@ -284,7 +284,7 @@ public class SSDPServer extends ThreadedUDPNetwork implements ThreadedUDPNetwork
try {
// Generate the SSDP response
StringOutputStream msg = new StringOutputStream();
HttpPrintStream http = new HttpPrintStream( msg, HttpPrintStream.HTTPMessageType.REQUEST );
HttpPrintStream http = new HttpPrintStream( msg, HttpPrintStream.HttpMessageType.REQUEST );
http.setRequestType("NOTIFY");
http.setRequestURL("*");
http.setHeader("Server", SERVER_INFO );

View file

@ -8,19 +8,22 @@ import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.cert.CertificateException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.net.ssl.SSLServerSocketFactory;
import zutil.io.MultiPrintStream;
import zutil.log.LogUtil;
/**
* A simple web server that handles both cookies and
* sessions for all the clients
* A simple network server that handles TCP communication
*
* @author Ziver
*/
public abstract class ThreadedTCPNetworkServer extends Thread{
public static final Logger logger = LogUtil.getLogger();
public final int port;
private File keyStore;
private String keyStorePass;
@ -28,7 +31,7 @@ public abstract class ThreadedTCPNetworkServer extends Thread{
/**
* Creates a new instance of the sever
*
* @param port The port that the server should listen to
* @param port The port that the server should listen to
*/
public ThreadedTCPNetworkServer(int port){
this(port, null, null);
@ -36,9 +39,9 @@ public abstract class ThreadedTCPNetworkServer extends Thread{
/**
* Creates a new instance of the sever
*
* @param port The port that the server should listen to
* @param sslCert If this is not null then the server will use SSL connection with this keyStore file path
* @param sslCert If this is not null then the server will use a SSL connection with the given certificate
* @param port The port that the server should listen to
* @param sslCert If this is not null then the server will use SSL connection with this keyStore file path
* @param sslCert If this is not null then the server will use a SSL connection with the given certificate
*/
public ThreadedTCPNetworkServer(int port, File keyStore, String keyStorePass){
this.port = port;
@ -64,18 +67,18 @@ public abstract class ThreadedTCPNetworkServer extends Thread{
if( t!=null )
new Thread( t ).start();
else{
MultiPrintStream.out.println("Unable to instantiate ThreadedTCPNetworkServerThread, closing connection!");
logger.severe("Unable to instantiate ThreadedTCPNetworkServerThread, closing connection!");
s.close();
}
}
} catch(Exception e) {
e.printStackTrace( MultiPrintStream.out );
logger.log(Level.SEVERE, null, e);
}
if( ss!=null ){
try{
ss.close();
}catch(IOException e){ e.printStackTrace( MultiPrintStream.out ); }
}catch(IOException e){ logger.log(Level.SEVERE, null, e); }
}
}
@ -84,17 +87,16 @@ public abstract class ThreadedTCPNetworkServer extends Thread{
* that will handle the newly made connection, if an null value is returned
* then the ThreadedTCPNetworkServer will close the new connection.
*
* @param s is an new connection to an host
* @return a new instance of an thread or null
* @param s is an new connection to an host
* @return a new instance of an thread or null
*/
protected abstract ThreadedTCPNetworkServerThread getThreadInstance( Socket s );
/**
* Initiates a SSLServerSocket
*
* @param port The port to listen to
* @return The SSLServerSocket
* @throws IOException
* @param port The port to listen to
* @return The SSLServerSocket
*/
private ServerSocket initSSL(int port) throws IOException{
SSLServerSocketFactory sslserversocketfactory =
@ -106,7 +108,7 @@ public abstract class ThreadedTCPNetworkServer extends Thread{
/**
* Registers the given cert file to the KeyStore
*
* @param certFile The cert file
* @param certFile The cert file
*/
protected void registerCertificate(File keyStore, String keyStorePass) throws CertificateException, IOException, KeyStoreException, NoSuchProviderException, NoSuchAlgorithmException{
System.setProperty("javax.net.ssl.keyStore", keyStore.getAbsolutePath());

View file

@ -1,7 +1,7 @@
package zutil.net.threaded;
/**
* The class that will handle the TCP connection will incclude
* The class that will handle the a TCP connection will include
* this interface
*
* @author Ziver

View file

@ -10,8 +10,7 @@ import java.net.SocketException;
/**
* A simple web server that handles both cookies and
* sessions for all the clients
* * A simple network server that handles UDP communication
*
* @author Ziver
*/

View file

@ -4,7 +4,7 @@ import java.net.DatagramPacket;
/**
* This interface is for processing received packets
* from the TNetworkUDPServer
* from the ThreadedUDPNetworkServer
*
* @author Ziver
*
@ -14,8 +14,8 @@ public interface ThreadedUDPNetworkThread extends Runnable{
/**
* Packet will be processed in this method
*
* @param packet is the received packet
* @param network is the network class that received the packet
* @param packet is the received packet
* @param network is the network class that received the packet
*/
public void receivedPacket(DatagramPacket packet, ThreadedUDPNetwork network);
}

View file

@ -1,102 +0,0 @@
package zutil.net.torrent;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import zutil.io.file.FileUtil;
public class Torrent {
// Name of the torrent
private String name;
// Comment
private String comment;
// Creation date as unix timestamp
private long date;
// Files in the torrent
private ArrayList<String> file_list;
// Size of of the full torrent (after download)
private long size;
// Signature of the software which created the torrent
private String created_by;
// tracker (the tracker the torrent has been received from)
private String main_tracker;
// List of known trackers for the torrent
private ArrayList<String> tracker_list;
private HashMap<String,Object> info_hash;
// Torrent is marked as 'private'.
private boolean is_private;
public Torrent(File torrent) throws IOException{
this(FileUtil.getFileContent( torrent ));
}
public Torrent(String data){
reset();
decode(data);
}
private void reset(){
// Reset
name = "";
comment = "";
date = 0;
file_list = new ArrayList<String>();
size = 0;
created_by = "";
main_tracker = "";
tracker_list = new ArrayList<String>();
info_hash = new HashMap<String,Object>();
is_private = false;
}
@SuppressWarnings("unchecked")
private void decode(String data){
HashMap<?,?> dataMap = (HashMap<?,?>)TorrentParser.decode(data);
name = (String)dataMap.get("name");
comment = (String)dataMap.get("comment");
date = (Long)dataMap.get("creation date");
file_list = new ArrayList<String>();
size = (Long)dataMap.get("length");
created_by = (String)dataMap.get("created by");
main_tracker = (String)dataMap.get("announce");
tracker_list = (ArrayList<String>)dataMap.get("announce-list");
info_hash = (HashMap<String, Object>)dataMap.get("info");
is_private = (((Integer)dataMap.get("private")) != 0);
}
// ************** GETTER **************
public String getName(){
return name;
}
public String getComments(){
return comment;
}
public long getDate(){
return date;
}
public ArrayList<String> getFileList(){
return file_list;
}
public long getSize(){
return size;
}
public String getAuthor(){
return created_by;
}
public String getMainTracker(){
return main_tracker;
}
public ArrayList<String> getTrackerList(){
return tracker_list;
}
public HashMap<String,Object> getInfoHash(){
return info_hash;
}
public boolean isPrivate(){
return is_private;
}
// ************************************
}

View file

@ -0,0 +1,32 @@
package zutil.net.torrent;
import zutil.Dumpable;
/**
* This class represents a File for download
*
* @author Ziver
*/
public class TorrentFile implements Dumpable{
private String filename;
private long length;
public TorrentFile(String filename, long length){
this.filename = filename;
this.length = length;
}
public String getFilename() {
return filename;
}
public void setFilename(String filename) {
this.filename = filename;
}
public long getLength() {
return length;
}
public void setLength(long length) {
this.length = length;
}
}

View file

@ -0,0 +1,165 @@
package zutil.net.torrent;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import zutil.io.MultiPrintStream;
import zutil.io.file.FileUtil;
import zutil.parser.BEncodedParser;
import zutil.parser.DataNode;
public class TorrentMetainfo {
/** Comment (optional) **/
private String comment;
/** Signature of the software which created the torrent (optional) **/
private String created_by;
/** Creation date as Unix timestamp (optional) **/
private long creation_date;
/** The main Tracker (the tracker the torrent has been received from) **/
private String announce;
/** List of known trackers for the torrent (optional) **/
private ArrayList<String> announce_list;
/** The encoding of the Strings (optional) **/
private String encoding;
/** Size of of the full torrent (after download) **/
private long size;
/** Number of bytes in each piece **/
private long piece_length;
/** String consisting of the concatenation of all 20-byte SHA1 hash values, one per piece **/
private ArrayList<String> piece_hashes;
/** Torrent is private. No other trackers allowed other then those listed. (optional) **/
private boolean is_private;
// Files in the torrent
private ArrayList<TorrentFile> file_list;
public TorrentMetainfo(File torrent) throws IOException{
this(FileUtil.getFileContent( torrent ));
}
public TorrentMetainfo(String data){
decode(data);
}
private void decode(String data){
DataNode metainfo = BEncodedParser.parse(data);
// Main values
announce = metainfo.getString("announce");
created_by = metainfo.getString("created by");
comment = metainfo.getString("comment");
encoding = metainfo.getString("encoding");
if( metainfo.get("creation date") != null )
creation_date = metainfo.getLong("creation date");
if( metainfo.get("announce-list") != null ){
DataNode tmp = metainfo.get("announce-list");
announce_list = new ArrayList<String>();
for( DataNode tracker : tmp )
announce_list.add( tracker.getString() );
}
// info data
DataNode info = metainfo.get("info");
String name = info.getString("name");
piece_length = info.getLong("piece length");
if( info.get("private") != null )
is_private = (info.getInt("private") != 0);
// Split the hashes
String hashes = info.getString("pieces");
piece_hashes = new ArrayList<String>();
for(int i=0; i<hashes.length() ;i++){
String hash = "";
for(; i%20!=0 ;i++)
hash += hashes.charAt(i);
piece_hashes.add(hash);
}
// File data
file_list = new ArrayList<TorrentFile>();
// Single-file torrent
if( info.get("files") == null ){
Long length = info.getLong("length");
file_list.add( new TorrentFile(name, length) );
}
// Multi-file torrent
else{
DataNode files = info.get("files");
for( DataNode file : files ){
String filename = "";
DataNode tmp = file.get("path");
// File in subdir
if( tmp.isList() ){
Iterator<DataNode> it = tmp.iterator();
while( it.hasNext() ){
filename += it.next().getString();
if(it.hasNext()) filename += File.separator;
}
}
// File in root dir
else
filename = tmp.getString();
Long length = file.getLong("length");
filename = name + File.separator + filename;
file_list.add( new TorrentFile(filename, length) );
}
}
}
public String getComment() {
return comment;
}
public String getCreated_by() {
return created_by;
}
public long getCreation_date() {
return creation_date;
}
public String getAnnounce() {
return announce;
}
public ArrayList<String> getAnnounce_list() {
return announce_list;
}
public String getEncoding() {
return encoding;
}
public long getSize() {
return size;
}
public long getPiece_length() {
return piece_length;
}
public ArrayList<String> getPiece_hashes() {
return piece_hashes;
}
public boolean isIs_private() {
return is_private;
}
public ArrayList<TorrentFile> getFile_list() {
return file_list;
}
/**
* Example use
*/
public static void main(String[] args){
try {
TorrentMetainfo tmp = new TorrentMetainfo(FileUtil.find("C:\\Users\\Ziver\\Desktop\\test.torrent"));
MultiPrintStream.out.dump(tmp);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}

View file

@ -1,122 +0,0 @@
package zutil.net.torrent;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.HashMap;
import java.util.LinkedList;
import zutil.io.MultiPrintStream;
import zutil.io.file.FileUtil;
/**
* http://wiki.theory.org/BitTorrentSpecification
* @author Ziver
*
*/
public class TorrentParser {
/**
* Example use
*/
public static void main(String[] args){
try {
String tmp = FileUtil.getFileContent(FileUtil.find("C:\\Users\\Ziver\\Desktop\\test.torrent"));
MultiPrintStream.out.dump(TorrentParser.decode(tmp));
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Returns the representation of the data in the BEncoded string
*
* @param data The data to be decoded
* @return
*/
public static Object decode(String data){
return decode_BEncoded(new StringBuffer(data));
}
/**
* Returns the representation of the data in the BEncoded string
*
* @param data The data to be decoded
* @param index The index in data to start from
* @return
*/
private static Object decode_BEncoded(StringBuffer data){
String tmp;
char c = ' ';
switch (data.charAt(0)) {
/**
* Integers are prefixed with an i and terminated by an e. For
* example, 123 would bEcode to i123e, -3272002 would bEncode to
* i-3272002e.
*/
case 'i':
//System.out.println("Found Integer at "+index);
data.deleteCharAt(0);
tmp = data.substring(0, data.indexOf("e"));
data.delete(0, tmp.length() + 1);
//System.out.println(tmp);
return new Long(tmp);
/**
* Lists are prefixed with a l and terminated by an e. The list
* should contain a series of bEncoded elements. For example, the
* list of strings ["Monduna", "Bit", "Torrents"] would bEncode to
* l7:Monduna3:Bit8:Torrentse. The list [1, "Monduna", 3, ["Sub", "List"]]
* would bEncode to li1e7:Mondunai3el3:Sub4:Listee
*/
case 'l':
//System.out.println("Found List at "+index);
data.deleteCharAt(0);
LinkedList<Object> list = new LinkedList<Object>();
c = data.charAt(0);
while(c != 'e'){
list.add(decode_BEncoded(data));
c = data.charAt(0);
}
data.deleteCharAt(0);
//MultiPrintStream.out.dump(list);
if(list.size() == 1) return list.poll();
else return list;
/**
* Dictionaries are prefixed with a d and terminated by an e. They
* are similar to list, except that items are in key value pairs. The
* dictionary {"key":"value", "Monduna":"com", "bit":"Torrents", "number":7}
* would bEncode to d3:key5:value7:Monduna3:com3:bit:8:Torrents6:numberi7ee
*/
case 'd':
//System.out.println("Found Dictionary at "+index);
data.deleteCharAt(0);
HashMap<Object,Object> map = new HashMap<Object,Object>();
c = data.charAt(0);
while(c != 'e'){
Object tmp2 = decode_BEncoded(data);
map.put(tmp2, decode_BEncoded(data));
c = data.charAt(0);
}
data.deleteCharAt(0);
//MultiPrintStream.out.dump(map);
return map;
/**
* Strings are prefixed with their length followed by a colon.
* For example, "Monduna" would bEncode to 7:Monduna and "BitTorrents"
* would bEncode to 11:BitTorrents.
*/
default:
//System.out.println("Found String at "+index);
tmp = data.substring(0, data.indexOf(":"));
int length = Integer.parseInt(tmp);
data.delete(0, tmp.length()+1);
String ret = data.substring(0, length);
data.delete(0, length);
//System.out.println(data.substring(i, i+length));
return ret;
}
}
}

View file

@ -0,0 +1,26 @@
package zutil.net.torrent;
import java.io.IOException;
import java.net.URL;
import zutil.net.http.HttpClient;
import zutil.net.http.HttpHeaderParser;
/**
* This tracker represents a tracker client
* that connects to a tracker
*
* @author Ziver
*/
public class TorrentTracker {
/** The address to the tracker **/
private URL trackerURL;
private void update() throws IOException {
HttpClient request = HttpClient.GET();
request.setURL( trackerURL );
HttpHeaderParser response = request.send();
}
}

View file

@ -0,0 +1,57 @@
package zutil.net.update;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import zutil.Hasher;
import zutil.io.file.FileUtil;
/**
* This class is used to store the files
* and there hashes
*
* @author Ziver
*/
public class FileInfo implements Serializable{
private static final long serialVersionUID = 1L;
private transient File file;
private String path;
private String hash;
private long size;
public FileInfo(String root, File file) throws IOException{
path = FileUtil.relativePath(file, root);
hash = Hasher.MD5(file);
size = file.length();
this.file = file;
}
public String getPath() {
return path;
}
public String getHash() {
return hash;
}
public long getSize() {
return size;
}
public File getFile(){
return file;
}
public boolean equals(Object comp){
if(comp instanceof FileInfo){
FileInfo tmp = (FileInfo)comp;
return path.equals(tmp.path) && hash.equals(tmp.hash);
}
return false;
}
public String toString(){
return path;
}
}

View file

@ -0,0 +1,82 @@
package zutil.net.update;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import zutil.io.file.FileUtil;
/**
* This class is used to store the files
* and there hashes
*
* @author Ziver
*/
class FileListMessage implements Serializable{
private static final long serialVersionUID = 1L;
private ArrayList<FileInfo> fileList;
private long totalSize;
private FileListMessage(){}
/**
* Returns a ArrayList of FileInfo object for all the files in the specified folder
*
* @param path is the path to scan
**/
public FileListMessage(String path) throws IOException{
fileList = new ArrayList<FileInfo>();
List<File> files = FileUtil.search(FileUtil.find(path));
long totalSize = 0;
for(File file : files){
FileInfo fileInfo = new FileInfo(path, file);
fileList.add( fileInfo );
totalSize += fileInfo.getSize();
}
this.totalSize = totalSize;
}
public long getTotalSize() {
return totalSize;
}
public ArrayList<FileInfo> getFileList(){
return fileList;
}
/**
* Compares the files and returns the files that differ from this file list
*
* @param comp is the file list to compare with
* @return
*/
public FileListMessage getDiff( FileListMessage comp){
FileListMessage diff = new FileListMessage();
long diffSize = 0;
diff.fileList = new ArrayList<FileInfo>();
for(FileInfo file : this.fileList){
if( !comp.fileList.contains( file)){
diff.fileList.add( file );
diffSize += file.getSize();
}
}
diff.totalSize = diffSize;
return diff;
}
public boolean equals(Object comp){
if(comp instanceof FileListMessage){
FileListMessage tmp = (FileListMessage)comp;
return fileList.equals(tmp.fileList) && totalSize == tmp.totalSize;
}
return false;
}
}

View file

@ -0,0 +1,154 @@
package zutil.net.update;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.util.logging.Level;
import java.util.logging.Logger;
import zutil.ProgressListener;
import zutil.io.file.FileUtil;
import zutil.log.LogUtil;
/**
* This class connects to a update server and updates a path
* with the servers
*
* @author Ziver
*
*/
public class UpdateClient{
public static final Logger logger = LogUtil.getLogger();
private String path;
private Socket socket;
private FileListMessage fileList;
private long speed;
private long totalReceived;
private long expectedSize;
private ProgressListener<UpdateClient,FileInfo> progress;
/**
* Creates a UpdateClient
*
* @param address Address to the UpdateServer
* @param port The port on the server
* @param path Path to the files to update
* @throws Exception
*/
public UpdateClient(String address, int port, String path) throws Exception{
fileList = new FileListMessage(path);
socket = new Socket(address, port);
this.path = path;
}
public void setProgressListener(ProgressListener<UpdateClient,FileInfo> p){
progress = p;
}
/**
* Updates the files
*/
public void update() throws IOException{
try{
ObjectOutputStream out = new ObjectOutputStream( socket.getOutputStream());
ObjectInputStream in = new ObjectInputStream ( socket.getInputStream() );
// send client file list
out.writeObject( fileList );
out.flush();
// get update list
FileListMessage updateList = (FileListMessage) in.readObject();
expectedSize = updateList.getTotalSize();
// receive file updates
File tmpPath = FileUtil.find(path);
totalReceived = 0;
for(FileInfo info : updateList.getFileList() ){
// reading new file data
File file = new File( tmpPath, info.getPath() );
logger.fine("Updating file: "+file);
if( !file.getParentFile().exists() && !file.getParentFile().mkdirs() ){
throw new IOException("Unable to create folder: "+file.getParentFile());
}
File tmpFile = File.createTempFile(file.getName(), ".tmp", tmpPath);
tmpFile.deleteOnExit();
FileOutputStream fileOut = new FileOutputStream(tmpFile);
byte[] buffer = new byte[socket.getReceiveBufferSize()];
long bytesReceived = 0;
int byteRead = 0;
long time = System.currentTimeMillis();
long timeTotalRecived = 0;
while( bytesReceived < info.getSize() ) {
byteRead = in.read(buffer);
fileOut.write(buffer, 0, byteRead);
bytesReceived += byteRead;
if(time+1000 < System.currentTimeMillis()){
time = System.currentTimeMillis();
speed = (int)(totalReceived - timeTotalRecived);
timeTotalRecived = totalReceived;
}
totalReceived += byteRead;
if(progress != null) progress.progressUpdate(this, info, ((double)totalReceived/updateList.getTotalSize())*100);
}
fileOut.close();
speed = 0;
// delete old file and replace whit new
file.delete();
if( !tmpFile.renameTo(file) ){
throw new IOException("Can not move downloaded file: "+tmpFile.getAbsolutePath()+" to: "+file);
}
}
}catch(ClassNotFoundException e){
logger.log(Level.SEVERE, null, e);
}
logger.info("Update done.");
}
/**
* Returns the speed of the transfer
*
* @return The speed in bytes/s
*/
public long getSpeed(){
return speed;
}
/**
* Returns the total amount of data received
*
* @return a long that represents bytes
*/
public long getTotalReceived(){
return totalReceived;
}
/**
* Returns the expected total amount of data that will be received
*
* @return a long that represents bytes
*/
public long getTotalSize(){
return expectedSize;
}
/**
* Closes the connection
*
* @throws IOException
*/
public void close() throws IOException{
socket.close();
}
}

View file

@ -0,0 +1,15 @@
package zutil.net.update;
import java.io.Serializable;
/**
* A class that contains configuration information
*
* @author Ziver
*/
class UpdateConfigMessage implements Serializable{
private static final long serialVersionUID = 1L;
protected String hashAlgorithm;
protected boolean compression;
}

View file

@ -0,0 +1,101 @@
package zutil.net.update;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.util.logging.Level;
import java.util.logging.Logger;
import zutil.io.MultiPrintStream;
import zutil.log.LogUtil;
import zutil.net.threaded.ThreadedTCPNetworkServer;
import zutil.net.threaded.ThreadedTCPNetworkServerThread;
public class UpdateServer extends ThreadedTCPNetworkServer{
public static final Logger logger = LogUtil.getLogger();
private FileListMessage fileList;
/**
* Creates a UpdateServer Thread
*
* @param path The path to sync the clients with
*/
public UpdateServer(int port, String path) throws Exception{
super(port);
fileList = new FileListMessage(path);
MultiPrintStream.out.dump(fileList);
this.start();
logger.info("Update Server Ready.");
}
@Override
protected ThreadedTCPNetworkServerThread getThreadInstance(Socket s) {
return new UpdateServerThread(s);
}
/**
* Handles all the connecting clients
*
* @author Ziver
*/
class UpdateServerThread implements ThreadedTCPNetworkServerThread{
private ObjectOutputStream out;
private ObjectInputStream in;
private Socket socket;
/**
* Creates a UpdateServerThread
*
* @param client is the socket to the client
*/
public UpdateServerThread(Socket c){
socket = c;
try {
out = new ObjectOutputStream( socket.getOutputStream());
in = new ObjectInputStream ( socket.getInputStream() );
} catch (IOException e) {
logger.log(Level.SEVERE, null, e);
}
}
public void run(){
try {
logger.info("Client["+socket.getInetAddress()+"] connectiong...");
// receive the clients file list
FileListMessage clientFileList = (FileListMessage)in.readObject();
MultiPrintStream.out.dump(clientFileList);
FileListMessage diff = fileList.getDiff( clientFileList );
MultiPrintStream.out.dump(diff);
out.writeObject( diff );
logger.info("Updating client["+socket.getInetAddress()+"]...");
for(FileInfo info : diff.getFileList()){
// send file data
FileInputStream input = new FileInputStream( info.getFile() );
byte[] nextBytes = new byte[ socket.getSendBufferSize() ];
int bytesRead = 0;
while((bytesRead = input.read(nextBytes)) > 0){
out.write(nextBytes,0,bytesRead);
}
out.flush();
input.close();
}
out.flush();
socket.close();
logger.info("Client["+socket.getInetAddress()+"] update done.");
} catch (Exception e) {
logger.log(Level.SEVERE, "Update error Client["+socket.getInetAddress()+"].", e);
} finally {
logger.info("Client["+socket.getInetAddress()+"] disconnected.");
}
}
}
}

View file

@ -0,0 +1,131 @@
package zutil.net.update;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.GroupLayout;
import javax.swing.GroupLayout.Alignment;
import javax.swing.JLabel;
import javax.swing.JProgressBar;
import javax.swing.LayoutStyle.ComponentPlacement;
import javax.swing.SwingConstants;
import javax.swing.JSeparator;
import javax.swing.JButton;
import zutil.ProgressListener;
import zutil.StringUtil;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.Dialog.ModalExclusionType;
public class Zupdater extends JFrame implements ProgressListener<UpdateClient, FileInfo>{
private static final long serialVersionUID = 1L;
private JPanel contentPane;
private JLabel lblSpeed;
private JLabel lblFile;
private JProgressBar progressBar;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Zupdater frame = new Zupdater();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public void progressUpdate(UpdateClient source, FileInfo info, double percent) {
lblFile.setText( info.getPath() );
progressBar.setValue( (int)percent );
progressBar.setString( StringUtil.formatBytesToString( source.getTotalReceived() ) +
" / "+StringUtil.formatBytesToString( source.getTotalSize() ));
lblSpeed.setText( StringUtil.formatBytesToString(((UpdateClient)source).getSpeed())+"/s" );
}
/**
* Create the frame.
*/
public Zupdater() {
setModalExclusionType(ModalExclusionType.APPLICATION_EXCLUDE);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setAlwaysOnTop(true);
setResizable(false);
setTitle("Updating...");
setBounds(100, 100, 537, 124);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
progressBar = new JProgressBar();
progressBar.setString("2.5 MB / 5 MB");
progressBar.setValue(50);
progressBar.setStringPainted(true);
progressBar.setToolTipText("");
lblFile = new JLabel("apa.zip");
lblSpeed = new JLabel("200 kb/s");
lblSpeed.setHorizontalAlignment(SwingConstants.RIGHT);
JSeparator separator = new JSeparator();
JButton btnCancel = new JButton("Cancel");
btnCancel.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
});
JLabel lblFile_1 = new JLabel("File:");
GroupLayout gl_contentPane = new GroupLayout(contentPane);
gl_contentPane.setHorizontalGroup(
gl_contentPane.createParallelGroup(Alignment.TRAILING)
.addGroup(gl_contentPane.createSequentialGroup()
.addGap(10)
.addComponent(progressBar, GroupLayout.DEFAULT_SIZE, 501, Short.MAX_VALUE)
.addGap(10))
.addComponent(separator, GroupLayout.DEFAULT_SIZE, 521, Short.MAX_VALUE)
.addGroup(gl_contentPane.createSequentialGroup()
.addContainerGap()
.addComponent(lblFile_1)
.addPreferredGap(ComponentPlacement.RELATED)
.addComponent(lblFile, GroupLayout.PREFERRED_SIZE, 331, GroupLayout.PREFERRED_SIZE)
.addGap(60)
.addComponent(lblSpeed, GroupLayout.DEFAULT_SIZE, 84, Short.MAX_VALUE)
.addContainerGap())
.addGroup(gl_contentPane.createSequentialGroup()
.addContainerGap()
.addComponent(btnCancel))
);
gl_contentPane.setVerticalGroup(
gl_contentPane.createParallelGroup(Alignment.LEADING)
.addGroup(gl_contentPane.createSequentialGroup()
.addGroup(gl_contentPane.createParallelGroup(Alignment.BASELINE)
.addComponent(lblSpeed)
.addComponent(lblFile)
.addComponent(lblFile_1))
.addPreferredGap(ComponentPlacement.RELATED)
.addComponent(progressBar, GroupLayout.PREFERRED_SIZE, 25, GroupLayout.PREFERRED_SIZE)
.addPreferredGap(ComponentPlacement.RELATED)
.addComponent(separator, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
.addPreferredGap(ComponentPlacement.RELATED)
.addComponent(btnCancel)
.addContainerGap(14, Short.MAX_VALUE))
);
contentPane.setLayout(gl_contentPane);
}
}