diff --git a/src/zutil/math/parser/MathParser.java b/src/zutil/math/parser/MathParser.java index fa4a8bc..052c9ef 100644 --- a/src/zutil/math/parser/MathParser.java +++ b/src/zutil/math/parser/MathParser.java @@ -151,16 +151,11 @@ class MathNumber extends Math{ abstract class MathOperation extends Math{ Math math1; Math math2; - int priority; public abstract double exec(); } class MathAddition extends MathOperation{ - public MathAddition(){ - priority = 1; - } - public double exec() { return math1.exec() + math2.exec(); } @@ -171,10 +166,6 @@ class MathAddition extends MathOperation{ } class MathSubtraction extends MathOperation{ - public MathSubtraction(){ - priority = 1; - } - public double exec() { return math1.exec() - math2.exec(); } @@ -185,10 +176,6 @@ class MathSubtraction extends MathOperation{ } class MathMultiplication extends MathOperation{ - public MathMultiplication(){ - priority = 2; - } - public double exec() { return math1.exec() * math2.exec(); } @@ -199,10 +186,6 @@ class MathMultiplication extends MathOperation{ } class MathDivision extends MathOperation{ - public MathDivision(){ - priority = 2; - } - public double exec() { return math1.exec() / math2.exec(); } @@ -213,10 +196,6 @@ class MathDivision extends MathOperation{ } class MathModulus extends MathOperation{ - public MathModulus(){ - priority = 2; - } - public double exec() { return math1.exec() % math2.exec(); } @@ -227,10 +206,6 @@ class MathModulus extends MathOperation{ } class MathPow extends MathOperation{ - public MathPow(){ - priority = 3; - } - public double exec() { double ret = 1; double tmp1 = math1.exec(); diff --git a/src/zutil/network/http/HTTPHeaderParser.java b/src/zutil/network/http/HTTPHeaderParser.java index 1aaaf7f..f4b6cbe 100644 --- a/src/zutil/network/http/HTTPHeaderParser.java +++ b/src/zutil/network/http/HTTPHeaderParser.java @@ -12,17 +12,18 @@ public class HTTPHeaderParser { private static final Pattern equalPattern = Pattern.compile("="); private static final Pattern andPattern = Pattern.compile("&"); private static final Pattern semiColonPattern = Pattern.compile(";"); - + // HTTP info private String type; private String url; private HashMap url_attr; private float version; + private int httpCode; // params private HashMap attributes; private HashMap cookies; - + /** * Parses the HTTP header information from the stream * @@ -33,7 +34,7 @@ public class HTTPHeaderParser { url_attr = new HashMap(); attributes = new HashMap(); cookies = new HashMap(); - + String tmp = null; if( (tmp=in.readLine()) != null && !tmp.isEmpty() ){ parseStartLine( tmp ); @@ -43,7 +44,7 @@ public class HTTPHeaderParser { } parseCookies(); } - + /** * Parses the HTTP header information from an String * @@ -53,7 +54,7 @@ public class HTTPHeaderParser { url_attr = new HashMap(); attributes = new HashMap(); cookies = new HashMap(); - + Scanner sc = new Scanner(in); sc.useDelimiter("\n"); String tmp = null; @@ -65,7 +66,7 @@ public class HTTPHeaderParser { } parseCookies(); } - + /** * Parses the first header line and ads the values to * the map and returns the file name and path @@ -75,21 +76,29 @@ public class HTTPHeaderParser { * @return The path and file name as a String */ protected void parseStartLine(String line){ - type = (line.substring(0, line.indexOf(" "))).trim(); - version = Float.parseFloat( line.substring(line.lastIndexOf("HTTP/")+5 , line.length()).trim() ); - line = (line.substring(type.length()+1, line.lastIndexOf("HTTP/"))).trim(); - - // parse URL and attributes - if(line.indexOf('?') > -1){ - url = line.substring(0, line.indexOf('?')); - line = line.substring(line.indexOf('?')+1, line.length()); - parseUrlAttributes(line, url_attr); + // Server Response + if( line.startsWith("HTTP/") ){ + version = Float.parseFloat( line.substring( 5 , 8) ); + httpCode = Integer.parseInt( line.substring( 9, 12 )); } + // Client Request else{ - url = line; + type = (line.substring(0, line.indexOf(" "))).trim(); + version = Float.parseFloat( line.substring(line.lastIndexOf("HTTP/")+5 , line.length()).trim() ); + line = (line.substring(type.length()+1, line.lastIndexOf("HTTP/"))).trim(); + + // parse URL and attributes + if(line.indexOf('?') > -1){ + url = line.substring(0, line.indexOf('?')); + line = line.substring(line.indexOf('?')+1, line.length()); + parseUrlAttributes(line, url_attr); + } + else{ + url = line; + } } } - + /** * Parses a String with variables from a get or post * that was sent from a client and puts the data into a HashMap @@ -120,7 +129,7 @@ public class HTTPHeaderParser { data[0].trim().toUpperCase(), // Key (data.length>1 ? data[1] : "").trim()); //Value } - + /** * Parses the attribute "Cookie" and returns a HashMap * with the values @@ -152,6 +161,12 @@ public class HTTPHeaderParser { public float getHTTPVersion(){ return version; } + /** + * @return the HTTP Return Code from a Server + */ + public float getHTTPCode(){ + return httpCode; + } /** * @return the URL that the client sent the server */ @@ -179,8 +194,8 @@ public class HTTPHeaderParser { public String getCookie(String name){ return cookies.get( name ); } - - + + /** * @return athe parsed cookies */ @@ -199,39 +214,39 @@ public class HTTPHeaderParser { public HashMap getAttributes(){ return attributes; } - - + + public String toString(){ StringBuffer tmp = new StringBuffer(); - tmp.append("\nType: "); + tmp.append("Type: "); tmp.append(type); tmp.append("\nHTTP Version: HTTP/"); tmp.append(version); - + tmp.append("\nURL: "); tmp.append(url); - + for( String key : url_attr.keySet() ){ tmp.append("\nURL Attr: "); tmp.append(key); tmp.append("="); tmp.append( url_attr.get(key) ); } - + for( String key : attributes.keySet() ){ tmp.append("\nHTTP Attr: "); tmp.append(key); tmp.append("="); tmp.append( attributes.get(key) ); } - + for( String key : cookies.keySet() ){ tmp.append("\nCookie: "); tmp.append(key); tmp.append("="); tmp.append( cookies.get(key) ); } - + return tmp.toString(); } } diff --git a/src/zutil/network/ssdp/SSDPClient.java b/src/zutil/network/ssdp/SSDPClient.java new file mode 100644 index 0000000..f7732c8 --- /dev/null +++ b/src/zutil/network/ssdp/SSDPClient.java @@ -0,0 +1,189 @@ +package zutil.network.ssdp; + +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.InetAddress; +import java.util.HashMap; +import java.util.LinkedList; + +import zutil.MultiPrintStream; +import zutil.network.http.HTTPHeaderParser; +import zutil.network.http.HttpPrintStream; +import zutil.network.threaded.ThreadedUDPNetwork; +import zutil.network.threaded.ThreadedUDPNetworkThread; +import zutil.wrapper.StringOutputStream; + +/** + * An SSDP client class that will request + * service information. + * + * @author Ziver + */ +public class SSDPClient extends ThreadedUDPNetwork implements ThreadedUDPNetworkThread{ + // Contains all the received services + private HashMap> services_st; + private HashMap services_usn; + + + public static void main(String[] args) throws IOException{ + SSDPClient ssdp = new SSDPClient(); + ssdp.requestService("upnp:rootdevice"); + ssdp.start(); + + for(int i=0; true ;++i){ + while( i==ssdp.getServicesCount("upnp:rootdevice") ){ try{Thread.sleep(100);}catch(Exception e){} } + MultiPrintStream.out.println( "************************" ); + MultiPrintStream.out.println( ssdp.getServices("upnp:rootdevice").get(i) ); + } + } + + /** + * Creates new instance of this class. An UDP + * listening socket at the SSDP port. + * + * @throws IOException + */ + public SSDPClient() throws IOException{ + super( null ); + super.setThread( this ); + + services_st = new HashMap>(); + services_usn = new HashMap(); + } + + /** + * Sends an request for an service + * + * @param st is the SearchTarget of the service + * + * ***** REQUEST: + * M-SEARCH * HTTP/1.1 + * Host: 239.255.255.250:reservedSSDPport + * Man: "ssdp:discover" + * ST: ge:fridge + * MX: 3 + * + */ + public void requestService(String st){ + try { + services_st.put( st, new LinkedList() ); + + // Generate an SSDP discover message + StringOutputStream msg = new StringOutputStream(); + HttpPrintStream http = new HttpPrintStream( msg, HttpPrintStream.HTTPMessageType.REQUEST ); + http.setRequestType("M-SEARCH"); + http.setRequestURL("*"); + http.setHeader("Host", SSDPServer.SSDP_MULTICAST_ADDR+":"+SSDPServer.SSDP_PORT ); + http.setHeader("ST", st ); + http.setHeader("Man", "\"ssdp:discover\"" ); + http.setHeader("MX", "3" ); + + http.close(); + //MultiPrintStream.out.println("***** REQUEST: \n"+msg); + byte[] data = msg.toString().getBytes(); + DatagramPacket packet = new DatagramPacket( + data, data.length, + InetAddress.getByName( SSDPServer.SSDP_MULTICAST_ADDR ), + SSDPServer.SSDP_PORT ); + super.send( packet ); + + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * Returns a list of received services by + * the given search target. + * + * @param st is the search target + * @return a list of received services + */ + public LinkedList getServices(String st){ + return services_st.get( st ); + } + + /** + * Returns the amount of services in the search target + * + * @param st is the search target + * @return the amount of services + */ + public int getServicesCount(String st){ + if( services_st.containsKey( st ) ){ + return services_st.get( st ).size(); + } + return 0; + } + + /** + * Returns a service with the given USN. + * + * @param usn is the unique identifier for the service + * @return an service, null if there is no such service + */ + public SSDPServiceInfo getService(String usn){ + return services_usn.get( usn ); + } + + /** + * Clears all the received information of the services + */ + public void clearServices(){ + services_usn.clear(); + services_st.clear(); + } + + /** + * Waits for responses + * + * ***** RESPONSE; + * HTTP/1.1 200 OK + * Ext: + * Cache-Control: no-cache="Ext", max-age = 5000 + * ST: ge:fridge + * USN: uuid:abcdefgh-7dec-11d0-a765-00a0c91e6bf6 + * Location: http://localhost:80 + */ + public void receivedPacket(DatagramPacket packet, ThreadedUDPNetwork network) { + HTTPHeaderParser header = new HTTPHeaderParser( new String( packet.getData() ) ); + //MultiPrintStream.out.println("*********** Recived\n"+header); + + String usn = header.getHTTPAttribute("USN"); + String st = header.getHTTPAttribute("ST"); + SSDPServiceInfo service; + // Get existing service + if( services_usn.containsKey( usn )){ + service = services_usn.get( usn ); + } + // Add new service + else{ + service = new SSDPServiceInfo(); + services_usn.put( usn, service); + if( !services_st.containsKey(st) ) + services_st.put( st, new LinkedList() ); + services_st.get( header.getHTTPAttribute("ST") ).add( service ); + } + + service.setLocation( header.getHTTPAttribute("LOCATION") ); + service.setST( st ); + service.setUSN( usn ); + service.setExpirationTime( + System.currentTimeMillis() + + 1000 * getCacheTime(header.getHTTPAttribute("Cache-Control")) ); + //MultiPrintStream.out.println("*********** Recived\n"+service); + } + + private long getCacheTime(String cache_control){ + long ret = 0; + String[] tmp = cache_control.split(","); + for( String element : tmp ){ + element = element.replaceAll("\\s", "").toLowerCase(); + if( element.startsWith("max-age=") ){ + ret = Long.parseLong( element.substring( "max-age=".length() ) ); + } + } + return ret; + } + +} diff --git a/src/zutil/network/SSDPServer.java b/src/zutil/network/ssdp/SSDPServer.java similarity index 80% rename from src/zutil/network/SSDPServer.java rename to src/zutil/network/ssdp/SSDPServer.java index 442d68d..45b948f 100644 --- a/src/zutil/network/SSDPServer.java +++ b/src/zutil/network/ssdp/SSDPServer.java @@ -1,4 +1,4 @@ -package zutil.network; +package zutil.network.ssdp; import java.io.IOException; import java.net.DatagramPacket; @@ -6,7 +6,6 @@ import java.net.InetAddress; import java.util.HashMap; import java.util.Timer; import java.util.TimerTask; -import java.util.UUID; import zutil.MultiPrintStream; import zutil.network.http.HTTPHeaderParser; @@ -49,25 +48,25 @@ public class SSDPServer extends ThreadedUDPNetwork implements ThreadedUDPNetwork // instance specific values private int cache_time; private NotifyTimer notifyTimer = null; - /** HashMap that contains services as < SearchTargetName, Location > */ - private HashMap services; - /** A Map of all the used USN:s */ - private HashMap usn_map; + /** HashMap that contains services as < SearchTargetName, SSDPServiceInfo > */ + private HashMap services; public static void main(String[] args) throws IOException{ SSDPServer ssdp = new SSDPServer(); - ssdp.addService("upnp:rootdevice", "nowhere"); + SSDPServiceInfo service = new SSDPServiceInfo(); + service.setLocation("nowhere"); + service.setST("upnp:rootdevice"); + ssdp.addService(service); ssdp.start(); MultiPrintStream.out.println("SSDP Server running"); } public SSDPServer() throws IOException{ - super( null, SSDP_PORT, SSDP_MULTICAST_ADDR ); + super( null, SSDP_MULTICAST_ADDR, SSDP_PORT ); super.setThread( this ); - services = new HashMap(); - usn_map = new HashMap(); + services = new HashMap(); setChacheTime( DEFAULT_CACHE_TIME ); enableNotify( true ); @@ -79,8 +78,8 @@ public class SSDPServer extends ThreadedUDPNetwork implements ThreadedUDPNetwork * @param searchTarget is the ST value in SSDP * @param location is the location of the service */ - public void addService(String searchTarget, String location){ - services.put( searchTarget, location ); + public void addService(SSDPServiceInfo service){ + services.put( service.getSearchTarget(), service ); } /** * Remove a service from being announced. This function will @@ -134,7 +133,6 @@ public class SSDPServer extends ThreadedUDPNetwork implements ThreadedUDPNetwork * * ***** REQUEST: * M-SEARCH * HTTP/1.1 - * S: uuid:ijklmnop-7dec-11d0-a765-00a0c91e6bf6 * Host: 239.255.255.250:reservedSSDPport * Man: "ssdp:discover" * ST: ge:fridge @@ -142,12 +140,11 @@ public class SSDPServer extends ThreadedUDPNetwork implements ThreadedUDPNetwork * * ***** RESPONSE; * HTTP/1.1 200 OK - * S: uuid:ijklmnop-7dec-11d0-a765-00a0c91e6bf6 * Ext: * Cache-Control: no-cache="Ext", max-age = 5000 * ST: ge:fridge * USN: uuid:abcdefgh-7dec-11d0-a765-00a0c91e6bf6 - * AL: + * Location: http://localhost:80 * */ public void receivedPacket(DatagramPacket packet, ThreadedUDPNetwork network) { @@ -155,7 +152,7 @@ public class SSDPServer extends ThreadedUDPNetwork implements ThreadedUDPNetwork String msg = new String( packet.getData() ); HTTPHeaderParser header = new HTTPHeaderParser( msg ); - MultiPrintStream.out.println(header); + //MultiPrintStream.out.println("**** Received:\n"+header); // ******* Respond // Check that the message is an ssdp discovery message @@ -172,13 +169,13 @@ public class SSDPServer extends ThreadedUDPNetwork implements ThreadedUDPNetwork http.setStatusCode(200); http.setHeader("Server", SERVER_INFO ); http.setHeader("ST", st ); - http.setHeader("Location", services.get(st) ); + http.setHeader("Location", services.get(st).getLocation() ); http.setHeader("EXT", "" ); http.setHeader("Cache-Control", "max-age = "+cache_time ); - http.setHeader("USN", getUSN(st) ); + http.setHeader("USN", services.get(st).getUSN() ); http.close(); - MultiPrintStream.out.println("\n"+response); + //MultiPrintStream.out.println("********** Response:\n"+response); byte[] data = response.toString().getBytes(); packet = new DatagramPacket( data, data.length, @@ -225,7 +222,7 @@ public class SSDPServer extends ThreadedUDPNetwork implements ThreadedUDPNetwork * NT: blenderassociation:blender * NTS: ssdp:alive * USN: someunique:idscheme3 - * AL: + * Location: http://localhost:80 * Cache-Control: max-age = 7393 */ public void sendNotify(String searchTarget){ @@ -239,12 +236,12 @@ public class SSDPServer extends ThreadedUDPNetwork implements ThreadedUDPNetwork http.setHeader("Host", SSDP_MULTICAST_ADDR+":"+SSDP_PORT ); http.setHeader("NT", searchTarget ); http.setHeader("NTS", "ssdp:alive" ); - http.setHeader("Location", services.get(searchTarget) ); + http.setHeader("Location", services.get(searchTarget).getLocation() ); http.setHeader("Cache-Control", "max-age = "+cache_time ); - http.setHeader("USN", getUSN(searchTarget) ); + http.setHeader("USN", services.get(searchTarget).getUSN() ); http.close(); - MultiPrintStream.out.println("\n"+msg); + //MultiPrintStream.out.println("******** Notification:\n"+msg); byte[] data = msg.toString().getBytes(); DatagramPacket packet = new DatagramPacket( data, data.length, @@ -290,10 +287,10 @@ public class SSDPServer extends ThreadedUDPNetwork implements ThreadedUDPNetwork http.setHeader("Host", SSDP_MULTICAST_ADDR+":"+SSDP_PORT ); http.setHeader("NT", searchTarget ); http.setHeader("NTS", "ssdp:byebye" ); - http.setHeader("USN", getUSN(searchTarget) ); + http.setHeader("USN", services.get(searchTarget).getUSN() ); http.close(); - MultiPrintStream.out.println("\n"+msg); + //MultiPrintStream.out.println("******** ByeBye:\n"+msg); byte[] data = msg.toString().getBytes(); DatagramPacket packet = new DatagramPacket( data, data.length, @@ -305,19 +302,4 @@ public class SSDPServer extends ThreadedUDPNetwork implements ThreadedUDPNetwork e.printStackTrace(); } } - - /** - * Generates an unique USN for the service - * - * @param searchTarget is the service ST name - * @return an unique string that corresponds to the service - */ - public String getUSN(String searchTarget){ - if( !usn_map.containsKey( searchTarget ) ){ - String usn = "uuid:" + UUID.nameUUIDFromBytes( (searchTarget+services.get(searchTarget)).getBytes() ); - usn_map.put( searchTarget, usn ); - return usn; - } - return usn_map.get( searchTarget ); - } } diff --git a/src/zutil/network/ssdp/SSDPServiceInfo.java b/src/zutil/network/ssdp/SSDPServiceInfo.java new file mode 100644 index 0000000..ab25b1d --- /dev/null +++ b/src/zutil/network/ssdp/SSDPServiceInfo.java @@ -0,0 +1,89 @@ +package zutil.network.ssdp; + +import java.util.Date; +import java.util.UUID; + +/** + * This class contains information about a service from + * or through the SSDP protocol + * + * @author Ziver + */ +public class SSDPServiceInfo { + private String location; + private String st; + private String usn; + private long expiration_time; + + /** + * @param l is the value to set the Location variable + */ + public void setLocation(String l) { + location = l; + } + + /** + * @param st is the value to set the SearchTarget variable + */ + public void setST(String st) { + this.st = st; + } + + /** + * @param usn is the value to set the USN variable + */ + protected void setUSN(String usn) { + this.usn = usn; + } + + /** + * @param time sets the expiration time of values in this object + */ + protected void setExpirationTime(long time) { + expiration_time = time; + } + + /** + * @return The URL to the Service, e.g. "http://192.168.0.1:80/index.html" + */ + public String getLocation(){ + return location; + } + + /** + * @return the Search Target, e.g. "upnp:rootdevice" + */ + public String getSearchTarget(){ + return st; + } + + /** + * @return the expiration time for the values in this object + */ + public long getExpirationTime(){ + return expiration_time; + } + + /** + * @return the USN value, e.g. "uuid:abcdefgh-7dec-11d0-a765-00a0c91e6bf6 " + */ + public String getUSN(){ + if( usn==null ) + usn = genUSN(); + return usn; + } + + /** + * Generates an unique USN for the service + * + * @param searchTarget is the service ST name + * @return an unique string that corresponds to the service + */ + private String genUSN(){ + return "uuid:" + UUID.nameUUIDFromBytes( (st+location).getBytes() ) +"::"+st; + } + + public String toString(){ + return "USN: "+usn+"\nLocation: "+location+"\nST: "+st+"\nExpiration-Time: "+new Date(expiration_time); + } +} diff --git a/src/zutil/network/threaded/ThreadedUDPNetwork.java b/src/zutil/network/threaded/ThreadedUDPNetwork.java index cbaefb7..db7f644 100644 --- a/src/zutil/network/threaded/ThreadedUDPNetwork.java +++ b/src/zutil/network/threaded/ThreadedUDPNetwork.java @@ -28,9 +28,22 @@ public class ThreadedUDPNetwork extends Thread{ protected DatagramSocket socket; protected ThreadedUDPNetworkThread thread = null; + /** + * Creates a new unicast Clien instance of the class + * + * @param thread is the class that will handle incoming packets + * @throws SocketException + */ + public ThreadedUDPNetwork(ThreadedUDPNetworkThread thread) throws SocketException{ + this.type = UDPType.UNICAST; + this.port = -1; + setThread( thread ); + + socket = new DatagramSocket(); + } /** - * Creates a new unicast instance of the sever + * Creates a new unicast Server instance of the class * * @param thread is the class that will handle incoming packets * @param port is the port that the server should listen to @@ -45,14 +58,14 @@ public class ThreadedUDPNetwork extends Thread{ } /** - * Creates a new multicast instance of the sever + * Creates a new multicast Server instance of the class * * @param thread is the class that will handle incoming packets * @param port is the port that the server should listen to * @param multicast_addr is the multicast address that the server will listen on * @throws IOException */ - public ThreadedUDPNetwork(ThreadedUDPNetworkThread thread, int port, String multicast_addr ) throws IOException{ + public ThreadedUDPNetwork(ThreadedUDPNetworkThread thread, String multicast_addr, int port ) throws IOException{ this.type = UDPType.MULTICAST; this.port = port; setThread( thread );