Cyberlink for Java v2.1 (2011-09-16) from SVN,

with extra parsers in xml/parsers removed.
Diverging from original v1.7 checkin in prep for merging.
This commit is contained in:
zzz
2012-05-25 17:47:18 +00:00
parent 312e6071d7
commit 14ac5ac03e
68 changed files with 5401 additions and 3491 deletions

View File

@@ -1,12 +1,21 @@
Copyright (C) 2003-2006 Satoshi Konno Copyright (c) 2003-2010, Satoshi Konno
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the name of the Cyber Garage nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@@ -30,7 +30,7 @@
package org.cybergarage.http; package org.cybergarage.http;
import java.net.*; import java.net.URL;
public class HTTP public class HTTP
{ {
@@ -45,6 +45,8 @@ public class HTTP
public static final String VERSION_11 = "1.1"; public static final String VERSION_11 = "1.1";
public static final String CRLF = "\r\n"; public static final String CRLF = "\r\n";
public static final byte CR = '\r';
public static final byte LF = '\n';
public static final String TAB = "\t"; public static final String TAB = "\t";
public static final String SOAP_ACTION = "SOAPACTION"; public static final String SOAP_ACTION = "SOAPACTION";
@@ -65,6 +67,7 @@ public class HTTP
public static final String CLOSE = "close"; public static final String CLOSE = "close";
public static final String KEEP_ALIVE = "Keep-Alive"; public static final String KEEP_ALIVE = "Keep-Alive";
public static final String CONTENT_TYPE = "Content-Type"; public static final String CONTENT_TYPE = "Content-Type";
public static final String CHARSET = "charset";
public static final String CONTENT_LENGTH = "Content-Length"; public static final String CONTENT_LENGTH = "Content-Length";
public static final String CONTENT_RANGE = "Content-Range"; public static final String CONTENT_RANGE = "Content-Range";
public static final String CONTENT_RANGE_BYTES = "bytes"; public static final String CONTENT_RANGE_BYTES = "bytes";

View File

@@ -18,12 +18,15 @@
package org.cybergarage.http; package org.cybergarage.http;
import java.io.*; import java.io.IOException;
import java.io.LineNumberReader;
import java.io.StringReader;
import org.cybergarage.util.*; import org.cybergarage.util.Debug;
public class HTTPHeader public class HTTPHeader
{ {
private static int MAX_LENGTH = 1024;
private String name; private String name;
private String value; private String value;
@@ -112,8 +115,9 @@ public class HTTPHeader
public final static String getValue(String data, String name) public final static String getValue(String data, String name)
{ {
/* Thanks for Stephan Mehlhase (2010-10-26) */
StringReader strReader = new StringReader(data); StringReader strReader = new StringReader(data);
LineNumberReader lineReader = new LineNumberReader(strReader); LineNumberReader lineReader = new LineNumberReader(strReader, Math.min(data.length(), MAX_LENGTH));
return getValue(lineReader, name); return getValue(lineReader, name);
} }

View File

@@ -59,17 +59,35 @@
* hasTransferEncoding(), setTransferEncoding(), getTransferEncoding(), isChunked(). * hasTransferEncoding(), setTransferEncoding(), getTransferEncoding(), isChunked().
* 03/02/05 * 03/02/05
* - Changed post() to suppot chunked stream. * - Changed post() to suppot chunked stream.
* 06/11/05
* - Added setHost().
* 07/07/05
* - Lee Peik Feng <pflee@users.sourceforge.net>
* - Andrey Ovchar <AOvchar@consultitnow.com>
* - Fixed set() to parse the chunk size as a hex string.
* 11/02/05
* - Changed set() to use BufferedInputStream instead of BufferedReader to
* get the content as a byte stream.
* 11/06/05
* - Added getCharSet().
* - Changed getContentString() to return the content string using the charset.
* *
*******************************************************************/ *******************************************************************/
package org.cybergarage.http; package org.cybergarage.http;
import java.io.*; import java.io.BufferedInputStream;
import java.util.*; import java.io.ByteArrayOutputStream;
import java.io.IOException;
import org.cybergarage.net.*; import java.io.InputStream;
import org.cybergarage.util.*; import java.io.InterruptedIOException;
import java.util.Calendar; import java.util.Calendar;
import java.util.StringTokenizer;
import java.util.Vector;
import org.cybergarage.net.HostInterface;
import org.cybergarage.util.Debug;
import org.cybergarage.util.StringUtil;
public class HTTPPacket public class HTTPPacket
{ {
@@ -129,12 +147,38 @@ public class HTTPPacket
// set // set
//////////////////////////////////////////////// ////////////////////////////////////////////////
private String readLine(BufferedInputStream in)
{
ByteArrayOutputStream lineBuf = new ByteArrayOutputStream();
byte readBuf[] = new byte[1];
try {
int readLen = in.read(readBuf);
while (0 < readLen) {
if (readBuf[0] == HTTP.LF)
break;
if (readBuf[0] != HTTP.CR)
lineBuf.write(readBuf[0]);
readLen = in.read(readBuf);
}
}
catch (InterruptedIOException e) {
//Ignoring warning because it's a way to break the HTTP connecttion
//TODO Create a new level of Logging and log the event
}
catch (IOException e) {
Debug.warning(e);
}
return lineBuf.toString();
}
protected boolean set(InputStream in, boolean onlyHeaders) protected boolean set(InputStream in, boolean onlyHeaders)
{ {
try { try {
BufferedReader reader = new BufferedReader(new InputStreamReader(in)); BufferedInputStream reader = new BufferedInputStream(in);
String firstLine = reader.readLine(); String firstLine = readLine(reader);
if (firstLine == null || firstLine.length() <= 0) if (firstLine == null || firstLine.length() <= 0)
return false; return false;
setFirstLine(firstLine); setFirstLine(firstLine);
@@ -148,15 +192,15 @@ public class HTTPPacket
//stream, so the code should check the presence of the actual //stream, so the code should check the presence of the actual
//response in the stream. //response in the stream.
//skip all header lines //skip all header lines
String headerLine = reader.readLine(); String headerLine = readLine(reader);
while ((headerLine != null) && (0 < headerLine.length()) ) { while ((headerLine != null) && (0 < headerLine.length()) ) {
HTTPHeader header = new HTTPHeader(headerLine); HTTPHeader header = new HTTPHeader(headerLine);
if (header.hasName() == true) if (header.hasName() == true)
setHeader(header); setHeader(header);
headerLine = reader.readLine(); headerLine = readLine(reader);
} }
//look forward another first line //look forward another first line
String actualFirstLine = reader.readLine(); String actualFirstLine = readLine(reader);
if ((actualFirstLine != null) && (0 < actualFirstLine.length()) ) { if ((actualFirstLine != null) && (0 < actualFirstLine.length()) ) {
//this is the actual first line //this is the actual first line
setFirstLine(actualFirstLine); setFirstLine(actualFirstLine);
@@ -165,12 +209,12 @@ public class HTTPPacket
} }
} }
String headerLine = reader.readLine(); String headerLine = readLine(reader);
while ((headerLine != null) && (0 < headerLine.length()) ) { while ((headerLine != null) && (0 < headerLine.length()) ) {
HTTPHeader header = new HTTPHeader(headerLine); HTTPHeader header = new HTTPHeader(headerLine);
if (header.hasName() == true) if (header.hasName() == true)
setHeader(header); setHeader(header);
headerLine = reader.readLine(); headerLine = readLine(reader);
} }
if (onlyHeaders == true) { if (onlyHeaders == true) {
@@ -183,19 +227,24 @@ public class HTTPPacket
long contentLen = 0; long contentLen = 0;
if (isChunkedRequest == true) { if (isChunkedRequest == true) {
try { try {
String chunkSizeLine = reader.readLine(); String chunkSizeLine = readLine(reader);
contentLen = Long.parseLong(new String(chunkSizeLine.getBytes(), 0, chunkSizeLine.length()-2)); // Thanks for Lee Peik Feng <pflee@users.sourceforge.net> (07/07/05)
//contentLen = Long.parseLong(new String(chunkSizeLine.getBytes(), 0, chunkSizeLine.length()-2), 16);
contentLen = (chunkSizeLine != null) ? Long.parseLong(chunkSizeLine.trim(), 16) : 0;
} }
catch (Exception e) {}; catch (Exception e) {};
} }
else else
contentLen = getContentLength(); contentLen = getContentLength();
StringBuilder contentBuf = new StringBuilder(); ByteArrayOutputStream contentBuf = new ByteArrayOutputStream();
while (0 < contentLen) { while (0 < contentLen) {
int chunkSize = HTTP.getChunkSize(); int chunkSize = HTTP.getChunkSize();
char readBuf[] = new char[chunkSize];
/* Thanks for Stephan Mehlhase (2010-10-26) */
byte readBuf[] = new byte[(int) (contentLen > chunkSize ? chunkSize : contentLen)];
long readCnt = 0; long readCnt = 0;
while (readCnt < contentLen) { while (readCnt < contentLen) {
try { try {
@@ -206,7 +255,7 @@ public class HTTPPacket
int readLen = reader.read(readBuf, 0, (int)bufReadLen); int readLen = reader.read(readBuf, 0, (int)bufReadLen);
if (readLen < 0) if (readLen < 0)
break; break;
contentBuf.append(new String(readBuf, 0, readLen)); contentBuf.write(readBuf, 0, readLen);
readCnt += readLen; readCnt += readLen;
} }
catch (Exception e) catch (Exception e)
@@ -226,8 +275,9 @@ public class HTTPPacket
} while (skipLen < HTTP.CRLF.length()); } while (skipLen < HTTP.CRLF.length());
// read next chunk size // read next chunk size
try { try {
String chunkSizeLine = reader.readLine(); String chunkSizeLine = readLine(reader);
contentLen = Long.parseLong(new String(chunkSizeLine.getBytes(), 0, chunkSizeLine.length()-2)); // Thanks for Lee Peik Feng <pflee@users.sourceforge.net> (07/07/05)
contentLen = Long.parseLong(new String(chunkSizeLine.getBytes(), 0, chunkSizeLine.length()-2), 16);
} }
catch (Exception e) { catch (Exception e) {
contentLen = 0; contentLen = 0;
@@ -237,9 +287,7 @@ public class HTTPPacket
contentLen = 0; contentLen = 0;
} }
// Thanks for Ralf G. R. Bergs (02/09/04) setContent(contentBuf.toByteArray(), false);
String contentStr = contentBuf.toString();
setContent(contentStr.getBytes(), false);
} }
catch (Exception e) { catch (Exception e) {
Debug.warning(e); Debug.warning(e);
@@ -464,7 +512,7 @@ public class HTTPPacket
public String getHeaderString() public String getHeaderString()
{ {
StringBuilder str = new StringBuilder(); StringBuffer str = new StringBuffer();
int nHeaders = getNHeaders(); int nHeaders = getNHeaders();
for (int n=0; n<nHeaders; n++) { for (int n=0; n<nHeaders; n++) {
@@ -510,6 +558,15 @@ public class HTTPPacket
public String getContentString() public String getContentString()
{ {
String charSet = getCharSet();
if (charSet == null || charSet.length() <= 0)
return new String(content);
try {
return new String(content, charSet);
}
catch (Exception e) {
Debug.warning(e);
}
return new String(content); return new String(content);
} }
@@ -553,6 +610,32 @@ public class HTTPPacket
return getHeaderValue(HTTP.CONTENT_TYPE); return getHeaderValue(HTTP.CONTENT_TYPE);
} }
////////////////////////////////////////////////
// Charset
////////////////////////////////////////////////
public String getCharSet()
{
String contentType = getContentType();
if (contentType == null)
return "";
contentType = contentType.toLowerCase();
int charSetIdx = contentType.indexOf(HTTP.CHARSET);
if (charSetIdx < 0)
return "";
int charSetEndIdx = charSetIdx + HTTP.CHARSET.length() + 1;
String charSet = new String(contentType.getBytes(), charSetEndIdx, (contentType.length() - charSetEndIdx));
if (charSet.length() < 0)
return "";
if (charSet.charAt(0) == '\"')
charSet = charSet.substring(1, (charSet.length() - 1));
if (charSet.length() < 0)
return "";
if (charSet.charAt((charSet.length()-1)) == '\"')
charSet = charSet.substring(0, (charSet.length() - 1));
return charSet;
}
//////////////////////////////////////////////// ////////////////////////////////////////////////
// ContentLength // ContentLength
//////////////////////////////////////////////// ////////////////////////////////////////////////
@@ -642,7 +725,7 @@ public class HTTPPacket
// Skip bytes // Skip bytes
if (strToken.hasMoreTokens() == false) if (strToken.hasMoreTokens() == false)
return range; return range;
strToken.nextToken(" "); String bytesStr = strToken.nextToken(" ");
// Get first-byte-pos // Get first-byte-pos
if (strToken.hasMoreTokens() == false) if (strToken.hasMoreTokens() == false)
return range; return range;
@@ -737,6 +820,14 @@ public class HTTPPacket
setHeader(HTTP.HOST, hostAddr + ":" + Integer.toString(port)); setHeader(HTTP.HOST, hostAddr + ":" + Integer.toString(port));
} }
public void setHost(String host)
{
String hostAddr = host;
if (HostInterface.isIPv6Address(host) == true)
hostAddr = "[" + host + "]";
setHeader(HTTP.HOST, hostAddr);
}
public String getHost() public String getHost()
{ {
return getHeaderValue(HTTP.HOST); return getHeaderValue(HTTP.HOST);

View File

@@ -44,15 +44,35 @@
* - Added to check the range of Content-Range request in post(). * - Added to check the range of Content-Range request in post().
* 03/02/05 * 03/02/05
* - Changed post() to suppot chunked stream. * - Changed post() to suppot chunked stream.
* 06/10/05
* - Changed post() to add a HOST headedr before the posting.
* 07/07/05
* - Lee Peik Feng <pflee@users.sourceforge.net>
* - Fixed post() to output the chunk size as a hex string.
* *
******************************************************************/ ******************************************************************/
package org.cybergarage.http; package org.cybergarage.http;
import java.io.*; import java.io.IOException;
import java.net.*; import java.io.InputStream;
import java.util.*; import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;
import java.net.SocketException;
import java.net.InetSocketAddress;
import java.util.StringTokenizer;
import org.cybergarage.util.Debug;
/**
*
* This class rappresnet an HTTP <b>request</b>, and act as HTTP client when it sends the request<br>
*
* @author Satoshi "skonno" Konno
* @author Stefano "Kismet" Lenzi
* @version 1.8
*
*/
public class HTTPRequest extends HTTPPacket public class HTTPRequest extends HTTPPacket
{ {
//////////////////////////////////////////////// ////////////////////////////////////////////////
@@ -61,6 +81,7 @@ public class HTTPRequest extends HTTPPacket
public HTTPRequest() public HTTPRequest()
{ {
setVersion(HTTP.VERSION_10);
} }
public HTTPRequest(InputStream in) public HTTPRequest(InputStream in)
@@ -296,7 +317,7 @@ public class HTTPRequest extends HTTPPacket
public String getHeader() public String getHeader()
{ {
StringBuilder str = new StringBuilder(); StringBuffer str = new StringBuffer();
str.append(getFirstLineString()); str.append(getFirstLineString());
@@ -370,6 +391,8 @@ public class HTTPRequest extends HTTPPacket
{ {
HTTPResponse httpRes = new HTTPResponse(); HTTPResponse httpRes = new HTTPResponse();
setHost(host);
setConnection((isKeepAlive == true) ? HTTP.KEEP_ALIVE : HTTP.CLOSE); setConnection((isKeepAlive == true) ? HTTP.KEEP_ALIVE : HTTP.CLOSE);
boolean isHeaderRequest = isHeadRequest(); boolean isHeaderRequest = isHeadRequest();
@@ -378,8 +401,11 @@ public class HTTPRequest extends HTTPPacket
InputStream in = null; InputStream in = null;
try { try {
if (postSocket == null) if (postSocket == null){
postSocket = new Socket(host, port); // Thanks for Hao Hu
postSocket = new Socket();
postSocket.connect(new InetSocketAddress(host, port), HTTPServer.DEFAULT_TIMEOUT);
}
out = postSocket.getOutputStream(); out = postSocket.getOutputStream();
PrintStream pout = new PrintStream(out); PrintStream pout = new PrintStream(out);
@@ -395,7 +421,8 @@ public class HTTPRequest extends HTTPPacket
if (0 < contentLength) { if (0 < contentLength) {
if (isChunkedRequest == true) { if (isChunkedRequest == true) {
String chunSizeBuf = Long.toString(contentLength); // Thanks for Lee Peik Feng <pflee@users.sourceforge.net> (07/07/05)
String chunSizeBuf = Long.toHexString(contentLength);
pout.print(chunSizeBuf); pout.print(chunSizeBuf);
pout.print(HTTP.CRLF); pout.print(HTTP.CRLF);
} }
@@ -413,9 +440,14 @@ public class HTTPRequest extends HTTPPacket
in = postSocket.getInputStream(); in = postSocket.getInputStream();
httpRes.set(in, isHeaderRequest); httpRes.set(in, isHeaderRequest);
} } catch (SocketException e) {
catch (Exception e) {
httpRes.setStatusCode(HTTPStatus.INTERNAL_SERVER_ERROR); httpRes.setStatusCode(HTTPStatus.INTERNAL_SERVER_ERROR);
Debug.warning(e);
} catch (IOException e) {
//Socket create but without connection
//TODO Blacklistening the device
httpRes.setStatusCode(HTTPStatus.INTERNAL_SERVER_ERROR);
Debug.warning(e);
} finally { } finally {
if (isKeepAlive == false) { if (isKeepAlive == false) {
try { try {
@@ -479,7 +511,7 @@ public class HTTPRequest extends HTTPPacket
public String toString() public String toString()
{ {
StringBuilder str = new StringBuilder(); StringBuffer str = new StringBuffer();
str.append(getHeader()); str.append(getHeader());
str.append(HTTP.CRLF); str.append(HTTP.CRLF);

View File

@@ -19,7 +19,7 @@
package org.cybergarage.http; package org.cybergarage.http;
import java.io.*; import java.io.InputStream;
public class HTTPResponse extends HTTPPacket public class HTTPResponse extends HTTPPacket
{ {
@@ -29,6 +29,7 @@ public class HTTPResponse extends HTTPPacket
public HTTPResponse() public HTTPResponse()
{ {
setVersion(HTTP.VERSION_11);
setContentType(HTML.CONTENT_TYPE); setContentType(HTML.CONTENT_TYPE);
setServer(HTTPServer.getName()); setServer(HTTPServer.getName());
setContent(""); setContent("");
@@ -84,7 +85,7 @@ public class HTTPResponse extends HTTPPacket
public String getHeader() public String getHeader()
{ {
StringBuilder str = new StringBuilder(); StringBuffer str = new StringBuffer();
str.append(getStatusLineString()); str.append(getStatusLineString());
str.append(getHeaderString()); str.append(getHeaderString());
@@ -98,7 +99,7 @@ public class HTTPResponse extends HTTPPacket
public String toString() public String toString()
{ {
StringBuilder str = new StringBuilder(); StringBuffer str = new StringBuffer();
str.append(getStatusLineString()); str.append(getStatusLineString());
str.append(getHeaderString()); str.append(getHeaderString());

View File

@@ -19,11 +19,26 @@
package org.cybergarage.http; package org.cybergarage.http;
import java.io.*; import java.io.IOException;
import java.net.*; import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import org.cybergarage.util.*; import org.cybergarage.util.Debug;
import org.cybergarage.util.ListenerList;
/**
*
* This class identifies an HTTP over TCP server<br>
* The server must be initialized iether by the {@link HTTPServer#open(InetAddress, int)} or the {@link HTTPServer#open(String, int)} method.<br>
* Optionally a set of {@link HTTPRequestListener} may be set<br>
* The server then can be started or stopped by the method {@link HTTPServer#start()} and {@link HTTPServer#stop()}
*
* @author Satoshi "skonno" Konno
* @author Stefano "Kismet" Lenzi
* @version 1.8
*
*/
public class HTTPServer implements Runnable public class HTTPServer implements Runnable
{ {
//////////////////////////////////////////////// ////////////////////////////////////////////////
@@ -35,6 +50,12 @@ public class HTTPServer implements Runnable
public final static int DEFAULT_PORT = 80; public final static int DEFAULT_PORT = 80;
/**
* Default timeout connection for HTTP comunication
* @since 1.8
*/
public final static int DEFAULT_TIMEOUT = DEFAULT_PORT * 1000;
public static String getName() public static String getName()
{ {
String osName = System.getProperty("os.name"); String osName = System.getProperty("os.name");
@@ -49,6 +70,7 @@ public class HTTPServer implements Runnable
public HTTPServer() public HTTPServer()
{ {
serverSock = null; serverSock = null;
} }
//////////////////////////////////////////////// ////////////////////////////////////////////////
@@ -58,6 +80,11 @@ public class HTTPServer implements Runnable
private ServerSocket serverSock = null; private ServerSocket serverSock = null;
private InetAddress bindAddr = null; private InetAddress bindAddr = null;
private int bindPort = 0; private int bindPort = 0;
/**
* Store the current TCP timeout value
* The variable should be accessed by getter and setter metho
*/
protected int timeout = DEFAULT_TIMEOUT;
public ServerSocket getServerSock() public ServerSocket getServerSock()
{ {
@@ -76,10 +103,40 @@ public class HTTPServer implements Runnable
return bindPort; return bindPort;
} }
//////////////////////////////////////////////// ////////////////////////////////////////////////
// open/close // open/close
//////////////////////////////////////////////// ////////////////////////////////////////////////
/**
* Get the current socket timeout
* @since 1.8
*/
public synchronized int getTimeout() {
return timeout;
}
/**
* Set the current socket timeout
* @param longout new timeout
* @since 1.8
*/
public synchronized void setTimeout(int timeout) {
this.timeout = timeout;
}
public boolean open(InetAddress addr,int port){
if (serverSock != null)
return true;
try {
serverSock = new ServerSocket(bindPort, 0, bindAddr);
}catch (IOException e) {
return false;
}
return true;
}
public boolean open(String addr, int port) public boolean open(String addr, int port)
{ {
if (serverSock != null) if (serverSock != null)
@@ -88,7 +145,6 @@ public class HTTPServer implements Runnable
bindAddr = InetAddress.getByName(addr); bindAddr = InetAddress.getByName(addr);
bindPort = port; bindPort = port;
serverSock = new ServerSocket(bindPort, 0, bindAddr); serverSock = new ServerSocket(bindPort, 0, bindAddr);
serverSock.setSoTimeout(10*1000);
} }
catch (IOException e) { catch (IOException e) {
return false; return false;
@@ -119,7 +175,7 @@ public class HTTPServer implements Runnable
return null; return null;
try { try {
Socket sock = serverSock.accept(); Socket sock = serverSock.accept();
sock.setSoTimeout(HTTP.DEFAULT_PORT * 1000); sock.setSoTimeout(getTimeout());
return sock; return sock;
} }
catch (Exception e) { catch (Exception e) {
@@ -189,9 +245,10 @@ public class HTTPServer implements Runnable
} }
} }
public boolean start() public boolean start(){
{ StringBuffer name = new StringBuffer("Cyber.HTTPServer/");
httpServerThread = new Thread(this, "UPnP-HTTPServer"); name.append(serverSock.getLocalSocketAddress());
httpServerThread = new Thread(this,name.toString());
httpServerThread.start(); httpServerThread.start();
return true; return true;
} }

View File

@@ -10,14 +10,18 @@
* *
* 05/08/03 * 05/08/03
* - first revision. * - first revision.
* 24/03/06
* - Stefano Lenzi:added debug information as request by Stephen More
* *
******************************************************************/ ******************************************************************/
package org.cybergarage.http; package org.cybergarage.http;
import java.util.*; import java.net.InetAddress;
import java.util.Vector;
import org.cybergarage.net.*; import org.cybergarage.net.HostInterface;
import org.cybergarage.upnp.Device;
public class HTTPServerList extends Vector public class HTTPServerList extends Vector
{ {
@@ -25,10 +29,15 @@ public class HTTPServerList extends Vector
// Constructor // Constructor
//////////////////////////////////////////////// ////////////////////////////////////////////////
private static final long serialVersionUID = 2379889735659369065L; private InetAddress[] binds = null;
private int port = Device.HTTP_DEFAULT_PORT;
public HTTPServerList() public HTTPServerList() {
{ }
public HTTPServerList(InetAddress[] list, int port) {
this.binds = list;
this.port = port;
} }
//////////////////////////////////////////////// ////////////////////////////////////////////////
@@ -62,20 +71,40 @@ public class HTTPServerList extends Vector
} }
} }
public boolean open(int port) public int open(){
{ InetAddress[] binds=this.binds;
String[] bindAddresses;
if(binds!=null){
bindAddresses = new String[binds.length];
for (int i = 0; i < binds.length; i++) {
bindAddresses[i] = binds[i].getHostAddress();
}
}else{
int nHostAddrs = HostInterface.getNHostAddresses(); int nHostAddrs = HostInterface.getNHostAddresses();
bindAddresses = new String[nHostAddrs];
for (int n=0; n<nHostAddrs; n++) { for (int n=0; n<nHostAddrs; n++) {
String bindAddr = HostInterface.getHostAddress(n); bindAddresses[n] = HostInterface.getHostAddress(n);
}
}
int j=0;
for (int i = 0; i < bindAddresses.length; i++) {
HTTPServer httpServer = new HTTPServer(); HTTPServer httpServer = new HTTPServer();
if (httpServer.open(bindAddr, port) == false) { if((bindAddresses[i]==null) || (httpServer.open(bindAddresses[i], port) == false)) {
close(); close();
clear(); clear();
return false; }else{
}
add(httpServer); add(httpServer);
j++;
} }
return true; }
return j;
}
public boolean open(int port)
{
this.port=port;
return open()!=0;
} }
//////////////////////////////////////////////// ////////////////////////////////////////////////

View File

@@ -15,7 +15,7 @@
package org.cybergarage.http; package org.cybergarage.http;
import java.net.*; import java.net.Socket;
public class HTTPServerThread extends Thread public class HTTPServerThread extends Thread
{ {
@@ -28,9 +28,9 @@ public class HTTPServerThread extends Thread
public HTTPServerThread(HTTPServer httpServer, Socket sock) public HTTPServerThread(HTTPServer httpServer, Socket sock)
{ {
super("Cyber.HTTPServerThread");
this.httpServer = httpServer; this.httpServer = httpServer;
this.sock = sock; this.sock = sock;
this.setDaemon(true);
} }
//////////////////////////////////////////////// ////////////////////////////////////////////////

View File

@@ -17,14 +17,20 @@
* - Added a isOnlyHeader to post(). * - Added a isOnlyHeader to post().
* 03/02/05 * 03/02/05
* - Changed post() to suppot chunked stream. * - Changed post() to suppot chunked stream.
* 06/10/05
* - Changed post() to add a Date headedr to the HTTPResponse before the posting.
* 07/07/05
* - Lee Peik Feng <pflee@users.sourceforge.net>
* - Fixed post() to output the chunk size as a hex string.
* *
******************************************************************/ ******************************************************************/
package org.cybergarage.http; package org.cybergarage.http;
import java.io.*; import java.io.InputStream;
import java.net.*; import java.io.OutputStream;
import java.util.*; import java.net.Socket;
import java.util.Calendar;
public class HTTPSocket public class HTTPSocket
{ {
@@ -119,6 +125,7 @@ public class HTTPSocket
sockOut = sock.getOutputStream(); sockOut = sock.getOutputStream();
} }
catch (Exception e) { catch (Exception e) {
//TODO Add blacklistening of the UPnP Device
return false; return false;
} }
return true; return true;
@@ -146,7 +153,9 @@ public class HTTPSocket
private boolean post(HTTPResponse httpRes, byte content[], long contentOffset, long contentLength, boolean isOnlyHeader) private boolean post(HTTPResponse httpRes, byte content[], long contentOffset, long contentLength, boolean isOnlyHeader)
{ {
//TODO Check for bad HTTP agents, this method may be list for IOInteruptedException and for blacklistening
httpRes.setDate(Calendar.getInstance()); httpRes.setDate(Calendar.getInstance());
OutputStream out = getOutputStream(); OutputStream out = getOutputStream();
try { try {
@@ -162,7 +171,8 @@ public class HTTPSocket
boolean isChunkedResponse = httpRes.isChunked(); boolean isChunkedResponse = httpRes.isChunked();
if (isChunkedResponse == true) { if (isChunkedResponse == true) {
String chunSizeBuf = Long.toString(contentLength); // Thanks for Lee Peik Feng <pflee@users.sourceforge.net> (07/07/05)
String chunSizeBuf = Long.toHexString(contentLength);
out.write(chunSizeBuf.getBytes()); out.write(chunSizeBuf.getBytes());
out.write(HTTP.CRLF.getBytes()); out.write(HTTP.CRLF.getBytes());
} }
@@ -187,7 +197,9 @@ public class HTTPSocket
private boolean post(HTTPResponse httpRes, InputStream in, long contentOffset, long contentLength, boolean isOnlyHeader) private boolean post(HTTPResponse httpRes, InputStream in, long contentOffset, long contentLength, boolean isOnlyHeader)
{ {
//TODO Check for bad HTTP agents, this method may be list for IOInteruptedException and for blacklistening
httpRes.setDate(Calendar.getInstance()); httpRes.setDate(Calendar.getInstance());
OutputStream out = getOutputStream(); OutputStream out = getOutputStream();
try { try {
@@ -213,7 +225,8 @@ public class HTTPSocket
int readLen = in.read(readBuf, 0, (int)readSize); int readLen = in.read(readBuf, 0, (int)readSize);
while (0 < readLen && readCnt < contentLength) { while (0 < readLen && readCnt < contentLength) {
if (isChunkedResponse == true) { if (isChunkedResponse == true) {
String chunSizeBuf = Long.toString(readLen); // Thanks for Lee Peik Feng <pflee@users.sourceforge.net> (07/07/05)
String chunSizeBuf = Long.toHexString(readLen);
out.write(chunSizeBuf.getBytes()); out.write(chunSizeBuf.getBytes());
out.write(HTTP.CRLF.getBytes()); out.write(HTTP.CRLF.getBytes());
} }
@@ -242,6 +255,7 @@ public class HTTPSocket
public boolean post(HTTPResponse httpRes, long contentOffset, long contentLength, boolean isOnlyHeader) public boolean post(HTTPResponse httpRes, long contentOffset, long contentLength, boolean isOnlyHeader)
{ {
//TODO Close if Connection != keep-alive
if (httpRes.hasContentInputStream() == true) if (httpRes.hasContentInputStream() == true)
return post(httpRes,httpRes.getContentInputStream(), contentOffset, contentLength, isOnlyHeader); return post(httpRes,httpRes.getContentInputStream(), contentOffset, contentLength, isOnlyHeader);
return post(httpRes,httpRes.getContent(), contentOffset, contentLength, isOnlyHeader); return post(httpRes,httpRes.getContent(), contentOffset, contentLength, isOnlyHeader);

View File

@@ -25,9 +25,9 @@
package org.cybergarage.http; package org.cybergarage.http;
import java.util.*; import java.util.StringTokenizer;
import org.cybergarage.util.*; import org.cybergarage.util.Debug;
public class HTTPStatus public class HTTPStatus
{ {

View File

@@ -15,12 +15,10 @@
package org.cybergarage.http; package org.cybergarage.http;
import java.util.*; import java.util.Vector;
public class ParameterList extends Vector public class ParameterList extends Vector
{ {
private static final long serialVersionUID = -6026765325018137641L;
public ParameterList() public ParameterList()
{ {
} }

View File

@@ -25,8 +25,16 @@
package org.cybergarage.net; package org.cybergarage.net;
import java.net.*; import java.net.Inet4Address;
import java.util.*; import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Vector;
import org.cybergarage.util.Debug;
public class HostInterface public class HostInterface
{ {
@@ -43,6 +51,9 @@ public class HostInterface
//////////////////////////////////////////////// ////////////////////////////////////////////////
private static String ifAddress = ""; private static String ifAddress = "";
public final static int IPV4_BITMASK = 0x0001;
public final static int IPV6_BITMASK = 0x0010;
public final static int LOCAL_BITMASK = 0x0100;
public final static void setInterface(String ifaddr) public final static void setInterface(String ifaddr)
{ {
@@ -101,10 +112,62 @@ public class HostInterface
} }
} }
} }
catch(Exception e){}; catch(Exception e){
Debug.warning(e);
};
return nHostAddrs; return nHostAddrs;
} }
/**
*
* @param ipfilter
* @param interfaces
* @return
* @since 1.8.0
* @author Stefano "Kismet" Lenzi &lt;kismet.sl@gmail.com&gt;
*/
public final static InetAddress[] getInetAddress(int ipfilter,String[] interfaces){
Enumeration nis;
if(interfaces!=null){
Vector iflist = new Vector();
for (int i = 0; i < interfaces.length; i++) {
NetworkInterface ni;
try {
ni = NetworkInterface.getByName(interfaces[i]);
} catch (SocketException e) {
continue;
}
if(ni != null) iflist.add(ni);
}
nis = iflist.elements();
}else{
try {
nis = NetworkInterface.getNetworkInterfaces();
} catch (SocketException e) {
return null;
}
}
ArrayList addresses = new ArrayList();
while (nis.hasMoreElements()){
NetworkInterface ni = (NetworkInterface)nis.nextElement();
Enumeration addrs = ni.getInetAddresses();
while (addrs.hasMoreElements()) {
InetAddress addr = (InetAddress)addrs.nextElement();
if(((ipfilter & LOCAL_BITMASK)==0) && addr.isLoopbackAddress())
continue;
if (((ipfilter & IPV4_BITMASK)!=0) && addr instanceof Inet4Address ) {
addresses.add(addr);
}else if (((ipfilter & IPV6_BITMASK)!=0)&& addr instanceof InetAddress) {
addresses.add(addr);
}
}
}
return (InetAddress[]) addresses.toArray(new InetAddress[]{});
}
public final static String getHostAddress(int n) public final static String getHostAddress(int n)
{ {
if (hasAssignedInterface() == true) if (hasAssignedInterface() == true)
@@ -143,7 +206,9 @@ public class HostInterface
{ {
try { try {
InetAddress addr = InetAddress.getByName(host); InetAddress addr = InetAddress.getByName(host);
return (addr instanceof Inet6Address); if (addr instanceof Inet6Address)
return true;
return false;
} }
catch (Exception e) {} catch (Exception e) {}
return false; return false;
@@ -153,7 +218,9 @@ public class HostInterface
{ {
try { try {
InetAddress addr = InetAddress.getByName(host); InetAddress addr = InetAddress.getByName(host);
return (addr instanceof Inet4Address); if (addr instanceof Inet4Address)
return true;
return false;
} }
catch (Exception e) {} catch (Exception e) {}
return false; return false;

View File

@@ -15,7 +15,8 @@
package org.cybergarage.soap; package org.cybergarage.soap;
import org.cybergarage.xml.*; import org.cybergarage.xml.Node;
import org.cybergarage.xml.Parser;
public class SOAP public class SOAP
{ {

View File

@@ -20,11 +20,15 @@
package org.cybergarage.soap; package org.cybergarage.soap;
import java.io.*; import java.io.ByteArrayInputStream;
import org.cybergarage.http.*; import org.cybergarage.http.HTTP;
import org.cybergarage.xml.*; import org.cybergarage.http.HTTPRequest;
import org.cybergarage.util.*; import org.cybergarage.http.HTTPResponse;
import org.cybergarage.util.Debug;
import org.cybergarage.xml.Node;
import org.cybergarage.xml.Parser;
import org.cybergarage.xml.ParserException;
public class SOAPRequest extends HTTPRequest public class SOAPRequest extends HTTPRequest
{ {
@@ -172,12 +176,12 @@ public class SOAPRequest extends HTTPRequest
public void print() public void print()
{ {
System.out.println(toString()); Debug.message(toString());
if (hasContent() == true) if (hasContent() == true)
return; return;
Node rootElem = getRootNode(); Node rootElem = getRootNode();
if (rootElem == null) if (rootElem == null)
return; return;
System.out.println(rootElem.toString()); Debug.message(rootElem.toString());
} }
} }

View File

@@ -20,8 +20,10 @@
package org.cybergarage.soap; package org.cybergarage.soap;
import org.cybergarage.http.*; import org.cybergarage.http.HTTPResponse;
import org.cybergarage.xml.*; import org.cybergarage.util.Debug;
import org.cybergarage.xml.Node;
import org.cybergarage.xml.XML;
public class SOAPResponse extends HTTPResponse public class SOAPResponse extends HTTPResponse
{ {
@@ -180,12 +182,12 @@ public class SOAPResponse extends HTTPResponse
public void print() public void print()
{ {
System.out.println(toString()); Debug.message(toString());
if (hasContent() == true) if (hasContent() == true)
return; return;
Node rootElem = getRootNode(); Node rootElem = getRootNode();
if (rootElem == null) if (rootElem == null)
return; return;
System.out.println(rootElem.toString()); Debug.message(rootElem.toString());
} }
} }

View File

@@ -22,16 +22,22 @@
* 07/09/04 * 07/09/04
* - Thanks for Dimas <cyberrate@users.sourceforge.net> and Stefano Lenzi <kismet-sl@users.sourceforge.net> * - Thanks for Dimas <cyberrate@users.sourceforge.net> and Stefano Lenzi <kismet-sl@users.sourceforge.net>
* - Changed postControlAction() to set the status code to the UPnPStatus. * - Changed postControlAction() to set the status code to the UPnPStatus.
* 04/12/06
* - Added setUserData() and getUserData() to set a user original data object.
* *
******************************************************************/ ******************************************************************/
package org.cybergarage.upnp; package org.cybergarage.upnp;
import java.util.Iterator;
import org.cybergarage.xml.*; import org.cybergarage.upnp.control.ActionListener;
import org.cybergarage.util.*; import org.cybergarage.upnp.control.ActionRequest;
import org.cybergarage.upnp.control.ActionResponse;
import org.cybergarage.upnp.xml.*; import org.cybergarage.upnp.control.ControlResponse;
import org.cybergarage.upnp.control.*; import org.cybergarage.upnp.xml.ActionData;
import org.cybergarage.util.Debug;
import org.cybergarage.util.Mutex;
import org.cybergarage.xml.Node;
public class Action public class Action
{ {
@@ -58,6 +64,16 @@ public class Action
return new Service(getServiceNode()); return new Service(getServiceNode());
} }
void setService(Service s){
serviceNode=s.getServiceNode();
/*To ensure integrity of the XML structure*/
Iterator i = getArgumentList().iterator();
while (i.hasNext()) {
Argument arg = (Argument) i.next();
arg.setService(s);
}
}
public Node getActionNode() public Node getActionNode()
{ {
return actionNode; return actionNode;
@@ -66,6 +82,11 @@ public class Action
//////////////////////////////////////////////// ////////////////////////////////////////////////
// Constructor // Constructor
//////////////////////////////////////////////// ////////////////////////////////////////////////
public Action(Node serviceNode){
//TODO Test
this.serviceNode = serviceNode;
this.actionNode = new Node(Action.ELEM_NAME);
}
public Action(Node serviceNode, Node actionNode) public Action(Node serviceNode, Node actionNode)
{ {
@@ -141,6 +162,23 @@ public class Action
return argumentList; return argumentList;
} }
public void setArgumentList(ArgumentList al){
Node argumentListNode = getActionNode().getNode(ArgumentList.ELEM_NAME);
if (argumentListNode == null){
argumentListNode = new Node(ArgumentList.ELEM_NAME);
getActionNode().addNode(argumentListNode);
}else{
argumentListNode.removeAllNodes();
}
Iterator i = al.iterator();
while (i.hasNext()) {
Argument a = (Argument) i.next();
a.setService(getService());
argumentListNode.addNode(a.getArgumentNode());
}
}
public ArgumentList getInputArgumentList() public ArgumentList getInputArgumentList()
{ {
ArgumentList allArgList = getArgumentList(); ArgumentList allArgList = getArgumentList();
@@ -184,11 +222,36 @@ public class Action
return null; return null;
} }
/**
* @deprecated You should use one of the following methods instead:<br />
* - {@link #setInArgumentValues(ArgumentList)} <br/>
* - {@link #setOutArgumentValues(ArgumentList)}
*/
public void setArgumentValues(ArgumentList argList) public void setArgumentValues(ArgumentList argList)
{ {
getArgumentList().set(argList); getArgumentList().set(argList);
} }
/**
*
* @param argList
* @since 1.8.0
*/
public void setInArgumentValues(ArgumentList argList)
{
getArgumentList().setReqArgs(argList);
}
/**
*
* @param argList
* @since 1.8.0
*/
public void setOutArgumentValues(ArgumentList argList)
{
getArgumentList().setResArgs(argList);
}
public void setArgumentValue(String name, String value) public void setArgumentValue(String name, String value)
{ {
Argument arg = getArgument(name); Argument arg = getArgument(name);
@@ -323,7 +386,12 @@ public class Action
if (ctrlRes.isSuccessful() == false) if (ctrlRes.isSuccessful() == false)
return false; return false;
ArgumentList outArgList = ctrlRes.getResponse(); ArgumentList outArgList = ctrlRes.getResponse();
actionArgList.set(outArgList); try {
actionArgList.setResArgs(outArgList);
} catch (IllegalArgumentException ex){
setStatus(UPnPStatus.INVALID_ARGS,"Action succesfully delivered but invalid arguments returned.");
return false;
}
return true; return true;
} }
@@ -367,4 +435,19 @@ public class Action
return upnpStatus; return upnpStatus;
} }
////////////////////////////////////////////////
// userData
////////////////////////////////////////////////
private Object userData = null;
public void setUserData(Object data)
{
userData = data;
}
public Object getUserData()
{
return userData;
}
} }

View File

@@ -15,7 +15,7 @@
package org.cybergarage.upnp; package org.cybergarage.upnp;
import java.util.*; import java.util.Vector;
public class ActionList extends Vector public class ActionList extends Vector
{ {
@@ -23,7 +23,6 @@ public class ActionList extends Vector
// Constants // Constants
//////////////////////////////////////////////// ////////////////////////////////////////////////
private static final long serialVersionUID = 1965922721316119846L;
public final static String ELEM_NAME = "actionList"; public final static String ELEM_NAME = "actionList";
//////////////////////////////////////////////// ////////////////////////////////////////////////

View File

@@ -15,7 +15,7 @@
package org.cybergarage.upnp; package org.cybergarage.upnp;
import org.cybergarage.xml.*; import org.cybergarage.xml.Node;
public class AllowedValue public class AllowedValue
{ {
@@ -45,6 +45,21 @@ public class AllowedValue
allowedValueNode = node; allowedValueNode = node;
} }
/**
* Create an AllowedValue by the value String,
* and will create the Node structure by itself
*
* @param value The value that will be associate to thi object
*
* @author Stefano "Kismet" Lenzi - kismet-sl@users.sourceforge.net - 2005
*/
public AllowedValue(String value) {
//TODO Some test are done not stable
allowedValueNode = new Node(ELEM_NAME); //better (twa)
setValue(value); //better (twa)
}
//////////////////////////////////////////////// ////////////////////////////////////////////////
// isAllowedValueNode // isAllowedValueNode
//////////////////////////////////////////////// ////////////////////////////////////////////////

View File

@@ -17,7 +17,8 @@
package org.cybergarage.upnp; package org.cybergarage.upnp;
import java.util.*; import java.util.Iterator;
import java.util.Vector;
public class AllowedValueList extends Vector public class AllowedValueList extends Vector
{ {
@@ -25,7 +26,6 @@ public class AllowedValueList extends Vector
// Constants // Constants
//////////////////////////////////////////////// ////////////////////////////////////////////////
private static final long serialVersionUID = 5740394642751180992L;
public final static String ELEM_NAME = "allowedValueList"; public final static String ELEM_NAME = "allowedValueList";
@@ -37,6 +37,14 @@ public class AllowedValueList extends Vector
{ {
} }
public AllowedValueList(String[] values) {
for (int i = 0; i < values.length; i++) {
add(new AllowedValue(values[i]));
};
}
//////////////////////////////////////////////// ////////////////////////////////////////////////
// Methods // Methods
//////////////////////////////////////////////// ////////////////////////////////////////////////
@@ -46,4 +54,12 @@ public class AllowedValueList extends Vector
return (AllowedValue)get(n); return (AllowedValue)get(n);
} }
public boolean isAllowed(String v){
for (Iterator i = this.iterator(); i.hasNext();) {
AllowedValue av = (AllowedValue) i.next();
if(av.getValue().equals(v))
return true;
}
return false;
}
} }

View File

@@ -15,7 +15,7 @@
package org.cybergarage.upnp; package org.cybergarage.upnp;
import org.cybergarage.xml.*; import org.cybergarage.xml.Node;
public class AllowedValueRange public class AllowedValueRange
{ {
@@ -45,10 +45,25 @@ public class AllowedValueRange
allowedValueRangeNode = node; allowedValueRangeNode = node;
} }
public AllowedValueRange(){
//TODO Test
allowedValueRangeNode = new Node(ELEM_NAME);
}
//////////////////////////////////////////////// ////////////////////////////////////////////////
// isAllowedValueRangeNode // isAllowedValueRangeNode
//////////////////////////////////////////////// ////////////////////////////////////////////////
public AllowedValueRange(Number max, Number min, Number step) {
//TODO Test
allowedValueRangeNode = new Node(ELEM_NAME);
if(max!=null)
setMaximum(max.toString());
if(min!=null)
setMinimum(min.toString());
if(step!=null)
setStep(step.toString());
}
public static boolean isAllowedValueRangeNode(Node node) public static boolean isAllowedValueRangeNode(Node node)
{ {
return ELEM_NAME.equals(node.getName()); return ELEM_NAME.equals(node.getName());

View File

@@ -17,14 +17,15 @@
* - Added getActionNode() and getAction(). * - Added getActionNode() and getAction().
* - Added getServiceNode() and getService(). * - Added getServiceNode() and getService().
* - Added the parent service node to the constructor. * - Added the parent service node to the constructor.
* 04/12/06
* - Added setUserData() and getUserData() to set a user original data object.
* *
******************************************************************/ ******************************************************************/
package org.cybergarage.upnp; package org.cybergarage.upnp;
import org.cybergarage.xml.*; import org.cybergarage.upnp.xml.ArgumentData;
import org.cybergarage.xml.Node;
import org.cybergarage.upnp.xml.*;
public class Argument public class Argument
{ {
@@ -59,6 +60,10 @@ public class Argument
return new Service(getServiceNode()); return new Service(getServiceNode());
} }
void setService(Service s){
s.getServiceNode();
}
public Node getActionNode() public Node getActionNode()
{ {
Node argumentLinstNode = getArgumentNode().getParentNode(); Node argumentLinstNode = getArgumentNode().getParentNode();
@@ -83,10 +88,15 @@ public class Argument
public Argument() public Argument()
{ {
argumentNode = new Node(); argumentNode = new Node(ELEM_NAME);
serviceNode = null; serviceNode = null;
} }
public Argument(Node servNode){
argumentNode = new Node(ELEM_NAME);
serviceNode = servNode;
}
public Argument(Node servNode, Node argNode) public Argument(Node servNode, Node argNode)
{ {
serviceNode = servNode; serviceNode = servNode;
@@ -226,6 +236,18 @@ public class Argument
} }
//////////////////////////////////////////////// ////////////////////////////////////////////////
// Related // userData
//////////////////////////////////////////////// ////////////////////////////////////////////////
private Object userData = null;
public void setUserData(Object data)
{
userData = data;
}
public Object getUserData()
{
return userData;
}
} }

View File

@@ -15,7 +15,7 @@
package org.cybergarage.upnp; package org.cybergarage.upnp;
import java.util.*; import java.util.Vector;
public class ArgumentList extends Vector public class ArgumentList extends Vector
{ {
@@ -23,7 +23,6 @@ public class ArgumentList extends Vector
// Constants // Constants
//////////////////////////////////////////////// ////////////////////////////////////////////////
private static final long serialVersionUID = -5412792105767389170L;
public final static String ELEM_NAME = "argumentList"; public final static String ELEM_NAME = "argumentList";
//////////////////////////////////////////////// ////////////////////////////////////////////////
@@ -60,7 +59,9 @@ public class ArgumentList extends Vector
//////////////////////////////////////////////// ////////////////////////////////////////////////
// Methods // Methods
//////////////////////////////////////////////// ////////////////////////////////////////////////
/**
* @deprecated
*/
public void set(ArgumentList inArgList) public void set(ArgumentList inArgList)
{ {
int nInArgs = inArgList.size(); int nInArgs = inArgList.size();
@@ -73,5 +74,48 @@ public class ArgumentList extends Vector
arg.setValue(inArg.getValue()); arg.setValue(inArg.getValue());
} }
} }
/**
* Set all the Argument which are Input Argoument to the given value in
* the argument list
*
* @param inArgList
*/
public void setReqArgs(ArgumentList inArgList)
{
int nArgs = size();
for (int n=0; n<nArgs; n++) {
Argument arg = getArgument(n);
if (arg.isInDirection()){
String argName = arg.getName();
Argument inArg = inArgList.getArgument(argName);
if (inArg == null)
throw new IllegalArgumentException("Argument \"" + argName + "\" missing.");
arg.setValue(inArg.getValue());
}
}
}
/**
* Set all the Argument which are Output Argoument to the given value in
* the argument list
*
* @param outArgList
*/
public void setResArgs(ArgumentList outArgList)
{
int nArgs = size();
for (int n=0; n<nArgs; n++) {
Argument arg = getArgument(n);
if (arg.isOutDirection()){
String argName = arg.getName();
Argument outArg = outArgList.getArgument(argName);
if (outArg == null)
throw new IllegalArgumentException("Argument \"" + argName + "\" missing.");
arg.setValue(outArg.getValue());
}
}
}
} }

View File

@@ -54,22 +54,47 @@
* the ControlPoint base class adds/removes a UPnP device * the ControlPoint base class adds/removes a UPnP device
* 03/30/05 * 03/30/05
* - Changed addDevice() to use Parser::parse(URL). * - Changed addDevice() to use Parser::parse(URL).
* 04/12/06
* - Added setUserData() and getUserData() to set a user original data object.
* *
*******************************************************************/ *******************************************************************/
package org.cybergarage.upnp; package org.cybergarage.upnp;
import org.cybergarage.net.*; import java.net.InetAddress;
import org.cybergarage.util.*; import java.net.MalformedURLException;
import org.cybergarage.xml.*; import java.net.URL;
import org.cybergarage.http.*;
import org.cybergarage.upnp.control.*; import org.cybergarage.http.HTTPRequest;
import org.cybergarage.upnp.ssdp.*; import org.cybergarage.http.HTTPRequestListener;
import org.cybergarage.upnp.device.*; import org.cybergarage.http.HTTPServerList;
import org.cybergarage.upnp.event.*; import org.cybergarage.net.HostInterface;
import org.cybergarage.upnp.control.RenewSubscriber;
import java.net.*; import org.cybergarage.upnp.device.DeviceChangeListener;
import org.cybergarage.upnp.device.Disposer;
import org.cybergarage.upnp.device.NotifyListener;
import org.cybergarage.upnp.device.ST;
import org.cybergarage.upnp.device.SearchResponseListener;
import org.cybergarage.upnp.device.USN;
import org.cybergarage.upnp.event.EventListener;
import org.cybergarage.upnp.event.NotifyRequest;
import org.cybergarage.upnp.event.Property;
import org.cybergarage.upnp.event.PropertyList;
import org.cybergarage.upnp.event.Subscription;
import org.cybergarage.upnp.event.SubscriptionRequest;
import org.cybergarage.upnp.event.SubscriptionResponse;
import org.cybergarage.upnp.ssdp.SSDP;
import org.cybergarage.upnp.ssdp.SSDPNotifySocketList;
import org.cybergarage.upnp.ssdp.SSDPPacket;
import org.cybergarage.upnp.ssdp.SSDPSearchRequest;
import org.cybergarage.upnp.ssdp.SSDPSearchResponseSocketList;
import org.cybergarage.util.Debug;
import org.cybergarage.util.ListenerList;
import org.cybergarage.util.Mutex;
import org.cybergarage.xml.Node;
import org.cybergarage.xml.NodeList;
import org.cybergarage.xml.Parser;
import org.cybergarage.xml.ParserException;
public class ControlPoint implements HTTPRequestListener public class ControlPoint implements HTTPRequestListener
{ {
@@ -109,10 +134,9 @@ public class ControlPoint implements HTTPRequestListener
// Constructor // Constructor
//////////////////////////////////////////////// ////////////////////////////////////////////////
public ControlPoint(int ssdpPort, int httpPort) public ControlPoint(int ssdpPort, int httpPort,InetAddress[] binds){
{ ssdpNotifySocketList = new SSDPNotifySocketList(binds);
ssdpNotifySocketList = new SSDPNotifySocketList(); ssdpSearchResponseSocketList = new SSDPSearchResponseSocketList(binds);
ssdpSearchResponseSocketList = new SSDPSearchResponseSocketList();
setSSDPPort(ssdpPort); setSSDPPort(ssdpPort);
setHTTPPort(httpPort); setHTTPPort(httpPort);
@@ -126,6 +150,10 @@ public class ControlPoint implements HTTPRequestListener
setRenewSubscriber(null); setRenewSubscriber(null);
} }
public ControlPoint(int ssdpPort, int httpPort){
this(ssdpPort,httpPort,null);
}
public ControlPoint() public ControlPoint()
{ {
this(DEFAULT_SSDP_PORT, DEFAULT_EVENTSUB_PORT); this(DEFAULT_SSDP_PORT, DEFAULT_EVENTSUB_PORT);
@@ -307,14 +335,14 @@ public class ControlPoint implements HTTPRequestListener
devNodeList.remove(rootNode); devNodeList.remove(rootNode);
} }
private void removeDevice(Device dev) protected void removeDevice(Device dev)
{ {
if (dev == null) if (dev == null)
return; return;
removeDevice(dev.getRootNode()); removeDevice(dev.getRootNode());
} }
private void removeDevice(String name) protected void removeDevice(String name)
{ {
Device dev = getDevice(name); Device dev = getDevice(name);
removeDevice(dev); removeDevice(dev);
@@ -392,7 +420,11 @@ public class ControlPoint implements HTTPRequestListener
int listenerSize = deviceNotifyListenerList.size(); int listenerSize = deviceNotifyListenerList.size();
for (int n=0; n<listenerSize; n++) { for (int n=0; n<listenerSize; n++) {
NotifyListener listener = (NotifyListener)deviceNotifyListenerList.get(n); NotifyListener listener = (NotifyListener)deviceNotifyListenerList.get(n);
try{
listener.deviceNotifyReceived(ssdpPacket); listener.deviceNotifyReceived(ssdpPacket);
}catch(Exception e){
Debug.warning("NotifyListener returned an error:", e);
}
} }
} }
@@ -417,7 +449,13 @@ public class ControlPoint implements HTTPRequestListener
int listenerSize = deviceSearchResponseListenerList.size(); int listenerSize = deviceSearchResponseListenerList.size();
for (int n=0; n<listenerSize; n++) { for (int n=0; n<listenerSize; n++) {
SearchResponseListener listener = (SearchResponseListener)deviceSearchResponseListenerList.get(n); SearchResponseListener listener = (SearchResponseListener)deviceSearchResponseListenerList.get(n);
try{
listener.deviceSearchResponseReceived(ssdpPacket); listener.deviceSearchResponseReceived(ssdpPacket);
}catch(Exception e){
Debug.warning("SearchResponseListener returned an error:", e);
}
} }
} }
@@ -465,11 +503,12 @@ public class ControlPoint implements HTTPRequestListener
public void notifyReceived(SSDPPacket packet) public void notifyReceived(SSDPPacket packet)
{ {
if (packet.isRootDevice() == true) { if (packet.isRootDevice() == true) {
if (packet.isAlive() == true) if (packet.isAlive() == true){
addDevice(packet); addDevice(packet);
if (packet.isByeBye() == true) }else if (packet.isByeBye() == true){
removeDevice(packet); removeDevice(packet);
} }
}
performNotifyListener(packet); performNotifyListener(packet);
} }
@@ -900,6 +939,22 @@ public class ControlPoint implements HTTPRequestListener
return true; return true;
} }
////////////////////////////////////////////////
// userData
////////////////////////////////////////////////
private Object userData = null;
public void setUserData(Object data)
{
userData = data;
}
public Object getUserData()
{
return userData;
}
//////////////////////////////////////////////// ////////////////////////////////////////////////
// print // print
//////////////////////////////////////////////// ////////////////////////////////////////////////

View File

@@ -82,26 +82,66 @@
* 04/25/05 * 04/25/05
* - Thanks for Mikael Hakman <mhakman@dkab.net> * - Thanks for Mikael Hakman <mhakman@dkab.net>
* - Added a new setActionListener() and serQueryListner() to include the sub devices. * - Added a new setActionListener() and serQueryListner() to include the sub devices.
* 07/24/05
* - Thanks for Stefano Lenzi <kismet-sl@users.sourceforge.net>
* - Fixed a bug of getParentDevice() to return the parent device normally.
* 02/21/06
* - Changed httpRequestRecieved() not to ignore HEAD requests.
* 04/12/06
* - Added setUserData() and getUserData() to set a user original data object.
* 03/29/08
* - Added isRunning() to know whether the device is running.
* *
******************************************************************/ ******************************************************************/
package org.cybergarage.upnp; package org.cybergarage.upnp;
import java.net.*; import java.io.File;
import java.io.*; import java.io.InputStream;
import java.util.*; import java.net.InetAddress;
import java.net.URL;
import java.util.Calendar;
import org.cybergarage.net.*; import org.cybergarage.http.HTTP;
import org.cybergarage.http.*; import org.cybergarage.http.HTTPRequest;
import org.cybergarage.util.*; import org.cybergarage.http.HTTPResponse;
import org.cybergarage.xml.*; import org.cybergarage.http.HTTPServerList;
import org.cybergarage.soap.*; import org.cybergarage.http.HTTPStatus;
import org.cybergarage.net.HostInterface;
import org.cybergarage.upnp.ssdp.*; import org.cybergarage.soap.SOAPResponse;
import org.cybergarage.upnp.device.*; import org.cybergarage.upnp.control.ActionListener;
import org.cybergarage.upnp.control.*; import org.cybergarage.upnp.control.ActionRequest;
import org.cybergarage.upnp.event.*; import org.cybergarage.upnp.control.ActionResponse;
import org.cybergarage.upnp.xml.*; import org.cybergarage.upnp.control.ControlRequest;
import org.cybergarage.upnp.control.ControlResponse;
import org.cybergarage.upnp.control.QueryListener;
import org.cybergarage.upnp.control.QueryRequest;
import org.cybergarage.upnp.device.Advertiser;
import org.cybergarage.upnp.device.Description;
import org.cybergarage.upnp.device.InvalidDescriptionException;
import org.cybergarage.upnp.device.NTS;
import org.cybergarage.upnp.device.ST;
import org.cybergarage.upnp.device.SearchListener;
import org.cybergarage.upnp.device.USN;
import org.cybergarage.upnp.event.Subscriber;
import org.cybergarage.upnp.event.Subscription;
import org.cybergarage.upnp.event.SubscriptionRequest;
import org.cybergarage.upnp.event.SubscriptionResponse;
import org.cybergarage.upnp.ssdp.SSDPNotifyRequest;
import org.cybergarage.upnp.ssdp.SSDPNotifySocket;
import org.cybergarage.upnp.ssdp.SSDPPacket;
import org.cybergarage.upnp.ssdp.SSDPSearchResponse;
import org.cybergarage.upnp.ssdp.SSDPSearchResponseSocket;
import org.cybergarage.upnp.ssdp.SSDPSearchSocketList;
import org.cybergarage.upnp.xml.DeviceData;
import org.cybergarage.util.Debug;
import org.cybergarage.util.FileUtil;
import org.cybergarage.util.Mutex;
import org.cybergarage.util.TimerUtil;
import org.cybergarage.xml.Node;
import org.cybergarage.xml.Parser;
import org.cybergarage.xml.ParserException;
import org.cybergarage.xml.XML;
public class Device implements org.cybergarage.http.HTTPRequestListener, SearchListener public class Device implements org.cybergarage.http.HTTPRequestListener, SearchListener
{ {
@@ -188,6 +228,16 @@ public class Device implements org.cybergarage.http.HTTPRequestListener, SearchL
loadDescription(descriptionFile); loadDescription(descriptionFile);
} }
/**
* @since 1.8.0
*/
public Device(InputStream input) throws InvalidDescriptionException
{
this(null, null);
loadDescription(input);
}
public Device(String descriptionFileName) throws InvalidDescriptionException public Device(String descriptionFileName) throws InvalidDescriptionException
{ {
this(new File(descriptionFileName)); this(new File(descriptionFileName));
@@ -209,6 +259,47 @@ public class Device implements org.cybergarage.http.HTTPRequestListener, SearchL
mutex.unlock(); mutex.unlock();
} }
////////////////////////////////////////////////
// getAbsoluteURL
////////////////////////////////////////////////
public String getAbsoluteURL(String urlString)
{
try {
URL url = new URL(urlString);
return url.toString();
}
catch (Exception e) {}
Device rootDev = getRootDevice();
String urlBaseStr = rootDev.getURLBase();
// Thanks for Steven Yen (2003/09/03)
if (urlBaseStr == null || urlBaseStr.length() <= 0) {
String location = rootDev.getLocation();
String locationHost = HTTP.getHost(location);
int locationPort = HTTP.getPort(location);
urlBaseStr = HTTP.getRequestHostURL(locationHost, locationPort);
}
urlString = HTTP.toRelativeURL(urlString);
String absUrl = urlBaseStr + urlString;
try {
URL url = new URL(absUrl);
return url.toString();
}
catch (Exception e) {}
absUrl = HTTP.getAbsoluteURL(urlBaseStr, urlString);
try {
URL url = new URL(absUrl);
return url.toString();
}
catch (Exception e) {}
return "";
}
//////////////////////////////////////////////// ////////////////////////////////////////////////
// NMPR // NMPR
//////////////////////////////////////////////// ////////////////////////////////////////////////
@@ -300,15 +391,71 @@ public class Device implements org.cybergarage.http.HTTPRequestListener, SearchL
// Thanks for Stefano Lenzi (07/24/04) // Thanks for Stefano Lenzi (07/24/04)
public Device getParentDevice() /**
{ *
* @return A Device that contain this object.<br>
* Return <code>null</code> if this is a root device.
* @author Stefano "Kismet" Lenzi
*/
public Device getParentDevice() {
if(isRootDevice()) if(isRootDevice())
return null; return null;
Node devNode = getDeviceNode(); Node devNode = getDeviceNode();
Node aux = null;
//<device><deviceList><device> //<device><deviceList><device>
devNode = devNode.getParentNode().getParentNode().getNode(Device.ELEM_NAME); aux = devNode.getParentNode().getParentNode();
return new Device(devNode); return new Device(aux);
} }
/**
* Add a Service to device without checking for duplicate or syntax error
*
* @param s Add Service s to the Device
*/
public void addService(Service s) {
Node serviceListNode = getDeviceNode().getNode(ServiceList.ELEM_NAME);
if (serviceListNode == null) {
serviceListNode = new Node(ServiceList.ELEM_NAME);
getDeviceNode().addNode(serviceListNode);
}
serviceListNode.addNode(s.getServiceNode());
}
/**
* Add a Device to device without checking for duplicate or syntax error.
* This method set or reset the root node of the Device and itself<br>
* <br>
* Note: This method should be used to create a dynamic<br>
* Device withtout writing any XML that describe the device<br>.
*
* @param d Add Device d to the Device
*
* @author Stefano "Kismet" Lenzi - kismet-sl@users.sourceforge.net - 2005
*
*/
public void addDevice(Device d) {
Node deviceListNode = getDeviceNode().getNode(DeviceList.ELEM_NAME);
if (deviceListNode == null) {
//deviceListNode = new Node(ServiceList.ELEM_NAME); twa wrong ELEM_NAME;
deviceListNode = new Node(DeviceList.ELEM_NAME);
getDeviceNode().addNode(deviceListNode);
}
deviceListNode.addNode(d.getDeviceNode());
d.setRootNode(null);
if(getRootNode()==null){
Node root = new Node(RootDescription.ROOT_ELEMENT);
root.setNameSpace("",RootDescription.ROOT_ELEMENT_NAMESPACE);
Node spec = new Node(RootDescription.SPECVERSION_ELEMENT);
Node maj =new Node(RootDescription.MAJOR_ELEMENT);
maj.setValue("1");
Node min =new Node(RootDescription.MINOR_ELEMENT);
min.setValue("0");
spec.addNode(maj);
spec.addNode(min);
root.addNode(spec);
setRootNode(root);
}
}
//////////////////////////////////////////////// ////////////////////////////////////////////////
// UserData // UserData
@@ -366,6 +513,32 @@ public class Device implements org.cybergarage.http.HTTPRequestListener, SearchL
return descriptionFile.getAbsoluteFile().getParent(); return descriptionFile.getAbsoluteFile().getParent();
} }
/**
* @since 1.8.0
*/
public boolean loadDescription(InputStream input) throws InvalidDescriptionException
{
try {
Parser parser = UPnP.getXMLParser();
rootNode = parser.parse(input);
if (rootNode == null)
throw new InvalidDescriptionException(Description.NOROOT_EXCEPTION);
deviceNode = rootNode.getNode(Device.ELEM_NAME);
if (deviceNode == null)
throw new InvalidDescriptionException(Description.NOROOTDEVICE_EXCEPTION);
}
catch (ParserException e) {
throw new InvalidDescriptionException(e);
}
if (initializeLoadedDescription() == false)
return false;
setDescriptionFile(null);
return true;
}
public boolean loadDescription(String descString) throws InvalidDescriptionException public boolean loadDescription(String descString) throws InvalidDescriptionException
{ {
try { try {
@@ -438,9 +611,8 @@ public class Device implements org.cybergarage.http.HTTPRequestListener, SearchL
// Root Device // Root Device
//////////////////////////////////////////////// ////////////////////////////////////////////////
public boolean isRootDevice() public boolean isRootDevice(){
{ return getRootNode().getNode("device").getNodeValue(UDN).equals(getUDN());
return (getRootNode() != null) ? true : false;
} }
//////////////////////////////////////////////// ////////////////////////////////////////////////
@@ -603,7 +775,7 @@ public class Device implements org.cybergarage.http.HTTPRequestListener, SearchL
// manufacture // manufacture
//////////////////////////////////////////////// ////////////////////////////////////////////////
private final static String MANUFACTURE = "manufacture"; private final static String MANUFACTURE = "manufacturer";
public void setManufacture(String value) public void setManufacture(String value)
{ {
@@ -619,7 +791,7 @@ public class Device implements org.cybergarage.http.HTTPRequestListener, SearchL
// manufactureURL // manufactureURL
//////////////////////////////////////////////// ////////////////////////////////////////////////
private final static String MANUFACTURE_URL = "manufactureURL"; private final static String MANUFACTURE_URL = "manufacturerURL";
public void setManufactureURL(String value) public void setManufactureURL(String value)
{ {
@@ -1066,6 +1238,24 @@ public class Device implements org.cybergarage.http.HTTPRequestListener, SearchL
return iconList.getIcon(n); return iconList.getIcon(n);
} }
public Icon getSmallestIcon()
{
Icon smallestIcon = null;
IconList iconList = getIconList();
int iconCount = iconList.size();
for (int n=0; n < iconCount; n++) {
Icon icon = iconList.getIcon(n);
if (null == smallestIcon) {
smallestIcon = icon;
continue;
}
if (icon.getWidth() < smallestIcon.getWidth())
smallestIcon = icon;
}
return smallestIcon;
}
//////////////////////////////////////////////// ////////////////////////////////////////////////
// Notify // Notify
//////////////////////////////////////////////// ////////////////////////////////////////////////
@@ -1103,7 +1293,6 @@ public class Device implements org.cybergarage.http.HTTPRequestListener, SearchL
{ {
TimerUtil.waitRandom(DEFAULT_DISCOVERY_WAIT_TIME); TimerUtil.waitRandom(DEFAULT_DISCOVERY_WAIT_TIME);
} }
public void announce(String bindAddr) public void announce(String bindAddr)
{ {
String devLocation = getLocationURL(bindAddr); String devLocation = getLocationURL(bindAddr);
@@ -1123,6 +1312,11 @@ public class Device implements org.cybergarage.http.HTTPRequestListener, SearchL
ssdpReq.setNT(devNT); ssdpReq.setNT(devNT);
ssdpReq.setUSN(devUSN); ssdpReq.setUSN(devUSN);
ssdpSock.post(ssdpReq); ssdpSock.post(ssdpReq);
String devUDN = getUDN();
ssdpReq.setNT(devUDN);
ssdpReq.setUSN(devUDN);
ssdpSock.post(ssdpReq);
} }
// uuid:device-UUID::urn:schemas-upnp-org:device:deviceType:v // uuid:device-UUID::urn:schemas-upnp-org:device:deviceType:v
@@ -1150,18 +1344,29 @@ public class Device implements org.cybergarage.http.HTTPRequestListener, SearchL
} }
} }
public void announce() public void announce(){
{
notifyWait(); notifyWait();
InetAddress[] binds = getDeviceData().getHTTPBindAddress();
String[] bindAddresses;
if(binds!=null){
bindAddresses = new String[binds.length];
for (int i = 0; i < binds.length; i++) {
bindAddresses[i] = binds[i].getHostAddress();
}
}else{
int nHostAddrs = HostInterface.getNHostAddresses(); int nHostAddrs = HostInterface.getNHostAddresses();
bindAddresses = new String[nHostAddrs];
for (int n=0; n<nHostAddrs; n++) { for (int n=0; n<nHostAddrs; n++) {
String bindAddr = HostInterface.getHostAddress(n); bindAddresses[n] = HostInterface.getHostAddress(n);
if (bindAddr == null || bindAddr.length() <= 0) }
}
for (int j = 0; j < bindAddresses.length; j++) {
if(bindAddresses[j] == null || bindAddresses[j].length() == 0)
continue; continue;
int ssdpCount = getSSDPAnnounceCount(); int ssdpCount = getSSDPAnnounceCount();
for (int i=0; i<ssdpCount; i++) for (int i=0; i<ssdpCount; i++)
announce(bindAddr); announce(bindAddresses[j]);
} }
} }
@@ -1206,16 +1411,29 @@ public class Device implements org.cybergarage.http.HTTPRequestListener, SearchL
} }
} }
public void byebye() public void byebye(){
{
InetAddress[] binds = getDeviceData().getHTTPBindAddress();
String[] bindAddresses;
if(binds!=null){
bindAddresses = new String[binds.length];
for (int i = 0; i < binds.length; i++) {
bindAddresses[i] = binds[i].getHostAddress();
}
}else{
int nHostAddrs = HostInterface.getNHostAddresses(); int nHostAddrs = HostInterface.getNHostAddresses();
bindAddresses = new String[nHostAddrs];
for (int n=0; n<nHostAddrs; n++) { for (int n=0; n<nHostAddrs; n++) {
String bindAddr = HostInterface.getHostAddress(n); bindAddresses[n] = HostInterface.getHostAddress(n);
if (bindAddr == null || bindAddr.length() <= 0) }
}
for (int j = 0; j < bindAddresses.length; j++) {
if (bindAddresses[j] == null || bindAddresses[j].length() <= 0)
continue; continue;
int ssdpCount = getSSDPAnnounceCount(); int ssdpCount = getSSDPAnnounceCount();
for (int i=0; i<ssdpCount; i++) for (int i=0; i<ssdpCount; i++)
byebye(bindAddr); byebye(bindAddresses[j]);
} }
} }
@@ -1223,6 +1441,7 @@ public class Device implements org.cybergarage.http.HTTPRequestListener, SearchL
// Search // Search
//////////////////////////////////////////////// ////////////////////////////////////////////////
private static Calendar cal = Calendar.getInstance();
public boolean postSearchResponse(SSDPPacket ssdpPacket, String st, String usn) public boolean postSearchResponse(SSDPPacket ssdpPacket, String st, String usn)
{ {
String localAddr = ssdpPacket.getLocalAddress(); String localAddr = ssdpPacket.getLocalAddress();
@@ -1231,7 +1450,7 @@ public class Device implements org.cybergarage.http.HTTPRequestListener, SearchL
SSDPSearchResponse ssdpRes = new SSDPSearchResponse(); SSDPSearchResponse ssdpRes = new SSDPSearchResponse();
ssdpRes.setLeaseTime(getLeaseTime()); ssdpRes.setLeaseTime(getLeaseTime());
ssdpRes.setDate(Calendar.getInstance()); ssdpRes.setDate(cal);
ssdpRes.setST(st); ssdpRes.setST(st);
ssdpRes.setUSN(usn); ssdpRes.setUSN(usn);
ssdpRes.setLocation(rootDevLocation); ssdpRes.setLocation(rootDevLocation);
@@ -1324,12 +1543,56 @@ public class Device implements org.cybergarage.http.HTTPRequestListener, SearchL
return getDeviceData().getHTTPPort(); return getDeviceData().getHTTPPort();
} }
public void setHTTPBindAddress(InetAddress[] inets){
this.getDeviceData().setHTTPBindAddress(inets);
}
public InetAddress[] getHTTPBindAddress(){
return this.getDeviceData().getHTTPBindAddress();
}
/**
*
* @return
* @since 1.8
*/
public String getSSDPIPv4MulticastAddress(){
return this.getDeviceData().getMulticastIPv4Address();
}
/**
*
* @param ip
* @since 1.8
*/
public void getSSDPIPv4MulticastAddress(String ip){
this.getDeviceData().setMulticastIPv4Address(ip);
}
/**
*
* @return
* @since 1.8
*/
public String getSSDPIPv6MulticastAddress(){
return this.getDeviceData().getMulticastIPv6Address();
}
/**
*
* @param ip
* @since 1.8
*/
public void getSSDPIPv6MulticastAddress(String ip){
this.getDeviceData().setMulticastIPv6Address(ip);
}
public void httpRequestRecieved(HTTPRequest httpReq) public void httpRequestRecieved(HTTPRequest httpReq)
{ {
if (Debug.isOn() == true) if (Debug.isOn() == true)
httpReq.print(); httpReq.print();
if (httpReq.isGetRequest() == true) { if (httpReq.isGetRequest() == true || httpReq.isHeadRequest() == true) {
httpGetRequestRecieved(httpReq); httpGetRequestRecieved(httpReq);
return; return;
} }
@@ -1377,6 +1640,8 @@ public class Device implements org.cybergarage.http.HTTPRequestListener, SearchL
byte fileByte[] = new byte[0]; byte fileByte[] = new byte[0];
if (isDescriptionURI(uri) == true) { if (isDescriptionURI(uri) == true) {
String localAddr = httpReq.getLocalAddress(); String localAddr = httpReq.getLocalAddress();
if ((localAddr == null) || (localAddr.length() <= 0))
localAddr = HostInterface.getInterface();
fileByte = getDescriptionData(localAddr); fileByte = getDescriptionData(localAddr);
} }
else if ((embDev = getDeviceByDescriptionURI(uri)) != null) { else if ((embDev = getDeviceByDescriptionURI(uri)) != null) {
@@ -1452,6 +1717,13 @@ public class Device implements org.cybergarage.http.HTTPRequestListener, SearchL
ctlReq.post(actRes); ctlReq.post(actRes);
} }
private void invalidArgumentsControlRecieved(ControlRequest ctlReq)
{
ControlResponse actRes = new ActionResponse();
actRes.setFaultResponse(UPnPStatus.INVALID_ARGS);
ctlReq.post(actRes);
}
private void deviceActionControlRecieved(ActionRequest ctlReq, Service service) private void deviceActionControlRecieved(ActionRequest ctlReq, Service service)
{ {
if (Debug.isOn() == true) if (Debug.isOn() == true)
@@ -1465,7 +1737,12 @@ public class Device implements org.cybergarage.http.HTTPRequestListener, SearchL
} }
ArgumentList actionArgList = action.getArgumentList(); ArgumentList actionArgList = action.getArgumentList();
ArgumentList reqArgList = ctlReq.getArgumentList(); ArgumentList reqArgList = ctlReq.getArgumentList();
actionArgList.set(reqArgList); try {
actionArgList.setReqArgs(reqArgList);
} catch (IllegalArgumentException ex){
invalidArgumentsControlRecieved(ctlReq);
return;
}
if (action.performActionListener(ctlReq) == false) if (action.performActionListener(ctlReq) == false)
invalidActionControlRecieved(ctlReq); invalidActionControlRecieved(ctlReq);
} }
@@ -1615,6 +1892,75 @@ public class Device implements org.cybergarage.http.HTTPRequestListener, SearchL
{ {
return getDeviceData().getHTTPServerList(); return getDeviceData().getHTTPServerList();
} }
/**
*
* @param port The port to use for binding the SSDP service
*/
public void setSSDPPort(int port){
this.getDeviceData().setSSDPPort(port);
}
/**
*
* @return The port to use for binding the SSDP service
*/
public int getSSDPPort(){
return this.getDeviceData().getSSDPPort();
}
/**
*
* @param inets The IP that will be used for binding the SSDP service.
* Use <code>null</code> to get the default beahvior
*/
public void setSSDPBindAddress(InetAddress[] inets){
this.getDeviceData().setSSDPBindAddress(inets);
}
/**
*
* @return inets The IP that will be used for binding the SSDP service.
* null means the default setted by the class UPnP
*/
public InetAddress[] getSSDPBindAddress(){
return this.getDeviceData().getSSDPBindAddress();
}
/**
*
* @param ip The IPv4 address used for Multicast comunication
*/
public void setMulticastIPv4Address(String ip){
this.getDeviceData().setMulticastIPv4Address(ip);
}
/**
*
* @return The IPv4 address used for Multicast comunication
*/
public String getMulticastIPv4Address(){
return this.getDeviceData().getMulticastIPv4Address();
}
/**
*
* @param ip The IPv address used for Multicast comunication
*/
public void setMulticastIPv6Address(String ip){
this.getDeviceData().setMulticastIPv6Address(ip);
}
/**
*
* @return The IPv address used for Multicast comunication
*/
public String getMulticastIPv6Address(){
return this.getDeviceData().getMulticastIPv6Address();
}
private SSDPSearchSocketList getSSDPSearchSocketList() private SSDPSearchSocketList getSSDPSearchSocketList()
{ {
@@ -1708,6 +2054,11 @@ public class Device implements org.cybergarage.http.HTTPRequestListener, SearchL
return stop(true); return stop(true);
} }
public boolean isRunning()
{
return (getAdvertiser() != null) ? true : false;
}
//////////////////////////////////////////////// ////////////////////////////////////////////////
// Interface Address // Interface Address
//////////////////////////////////////////////// ////////////////////////////////////////////////
@@ -1776,6 +2127,22 @@ public class Device implements org.cybergarage.http.HTTPRequestListener, SearchL
} }
} }
////////////////////////////////////////////////
// userData
////////////////////////////////////////////////
private Object userData = null;
public void setUserData(Object data)
{
userData = data;
}
public Object getUserData()
{
return userData;
}
//////////////////////////////////////////////// ////////////////////////////////////////////////
// output // output
//////////////////////////////////////////////// ////////////////////////////////////////////////

View File

@@ -15,7 +15,7 @@
package org.cybergarage.upnp; package org.cybergarage.upnp;
import java.util.*; import java.util.Vector;
public class DeviceList extends Vector public class DeviceList extends Vector
{ {
@@ -23,7 +23,6 @@ public class DeviceList extends Vector
// Constants // Constants
//////////////////////////////////////////////// ////////////////////////////////////////////////
private static final long serialVersionUID = 3773784061607435126L;
public final static String ELEM_NAME = "deviceList"; public final static String ELEM_NAME = "deviceList";
//////////////////////////////////////////////// ////////////////////////////////////////////////

View File

@@ -10,12 +10,14 @@
* *
* 11/28/02 * 11/28/02
* - first revision. * - first revision.
* 04/12/06
* - Added setUserData() and getUserData() to set a user original data object.
* *
******************************************************************/ ******************************************************************/
package org.cybergarage.upnp; package org.cybergarage.upnp;
import org.cybergarage.xml.*; import org.cybergarage.xml.Node;
public class Icon public class Icon
{ {
@@ -81,9 +83,21 @@ public class Icon
getIconNode().setNode(WIDTH, value); getIconNode().setNode(WIDTH, value);
} }
public String getWidth() public void setWidth(int value)
{ {
return getIconNode().getNodeValue(WIDTH); try {
setWidth(Integer.toString(value));
}
catch (Exception e) {};
}
public int getWidth()
{
try {
return Integer.parseInt(getIconNode().getNodeValue(WIDTH));
}
catch (Exception e) {};
return 0;
} }
//////////////////////////////////////////////// ////////////////////////////////////////////////
@@ -97,9 +111,21 @@ public class Icon
getIconNode().setNode(HEIGHT, value); getIconNode().setNode(HEIGHT, value);
} }
public String getHeight() public void setHeight(int value)
{ {
return getIconNode().getNodeValue(HEIGHT); try {
setHeight(Integer.toString(value));
}
catch (Exception e) {};
}
public int getHeight()
{
try {
return Integer.parseInt(getIconNode().getNodeValue(HEIGHT));
}
catch (Exception e) {};
return 0;
} }
//////////////////////////////////////////////// ////////////////////////////////////////////////
@@ -133,4 +159,20 @@ public class Icon
{ {
return getIconNode().getNodeValue(URL); return getIconNode().getNodeValue(URL);
} }
////////////////////////////////////////////////
// userData
////////////////////////////////////////////////
private Object userData = null;
public void setUserData(Object data)
{
userData = data;
}
public Object getUserData()
{
return userData;
}
} }

View File

@@ -15,7 +15,7 @@
package org.cybergarage.upnp; package org.cybergarage.upnp;
import java.util.*; import java.util.Vector;
public class IconList extends Vector public class IconList extends Vector
{ {
@@ -23,7 +23,6 @@ public class IconList extends Vector
// Constants // Constants
//////////////////////////////////////////////// ////////////////////////////////////////////////
private static final long serialVersionUID = -1097238335037012991L;
public final static String ELEM_NAME = "iconList"; public final static String ELEM_NAME = "iconList";
//////////////////////////////////////////////// ////////////////////////////////////////////////

View File

@@ -0,0 +1,19 @@
package org.cybergarage.upnp;
/**
* @author Stefano "Kismet" Lenzi - kismet-sl@users.sourceforge.net <br>
* Copyright (c) 2005
*
*/
public interface RootDescription {
public final String ROOT_ELEMENT = "root";
public final String ROOT_ELEMENT_NAMESPACE = "urn:schemas-upnp-org:device-1-0";
public final String SPECVERSION_ELEMENT = "specVersion";
public final String MAJOR_ELEMENT = "major";
public final String MINOR_ELEMENT = "minor";
public final String SERVICE_LIST_ELEMENT = "serviceList";
}

View File

@@ -60,23 +60,42 @@
* 04/25/05 * 04/25/05
* - Thanks for Mikael Hakman <mhakman@dkab.net> * - Thanks for Mikael Hakman <mhakman@dkab.net>
* - Changed getSCPDData() to add a XML declaration at first line. * - Changed getSCPDData() to add a XML declaration at first line.
* 06/21/05
* - Changed notify() to continue when the subscriber is null.
* 04/12/06
* - Added setUserData() and getUserData() to set a user original data object.
* 09/18/2010 Robin V. <robinsp@gmail.com>
* - Fixed getSCPDNode() not to occur recursive http get requests.
* *
******************************************************************/ ******************************************************************/
package org.cybergarage.upnp; package org.cybergarage.upnp;
import java.io.*; import java.io.File;
import java.net.*; import java.io.InputStream;
import java.net.URL;
import java.util.Iterator;
import org.cybergarage.http.*; import org.cybergarage.http.HTTP;
import org.cybergarage.xml.*; import org.cybergarage.http.HTTPResponse;
import org.cybergarage.util.*; import org.cybergarage.upnp.control.ActionListener;
import org.cybergarage.upnp.control.QueryListener;
import org.cybergarage.upnp.ssdp.*; import org.cybergarage.upnp.device.InvalidDescriptionException;
import org.cybergarage.upnp.xml.*; import org.cybergarage.upnp.device.NTS;
import org.cybergarage.upnp.device.*; import org.cybergarage.upnp.device.ST;
import org.cybergarage.upnp.control.*; import org.cybergarage.upnp.event.NotifyRequest;
import org.cybergarage.upnp.event.*; import org.cybergarage.upnp.event.Subscriber;
import org.cybergarage.upnp.event.SubscriberList;
import org.cybergarage.upnp.ssdp.SSDPNotifyRequest;
import org.cybergarage.upnp.ssdp.SSDPNotifySocket;
import org.cybergarage.upnp.ssdp.SSDPPacket;
import org.cybergarage.upnp.xml.ServiceData;
import org.cybergarage.util.Debug;
import org.cybergarage.util.Mutex;
import org.cybergarage.util.StringUtil;
import org.cybergarage.xml.Node;
import org.cybergarage.xml.Parser;
import org.cybergarage.xml.ParserException;
public class Service public class Service
{ {
@@ -100,6 +119,34 @@ public class Service
//////////////////////////////////////////////// ////////////////////////////////////////////////
// Constructor // Constructor
//////////////////////////////////////////////// ////////////////////////////////////////////////
public static final String SCPD_ROOTNODE="scpd";
public static final String SCPD_ROOTNODE_NS="urn:schemas-upnp-org:service-1-0";
public static final String SPEC_VERSION="specVersion";
public static final String MAJOR="major";
public static final String MAJOR_VALUE="1";
public static final String MINOR="minor";
public static final String MINOR_VALUE="0";
public Service(){
this(new Node(ELEM_NAME));
Node sp = new Node(SPEC_VERSION);
Node M =new Node(MAJOR);
M.setValue(MAJOR_VALUE);
sp.addNode(M);
Node m =new Node(MINOR);
m.setValue(MINOR_VALUE);
sp.addNode(m);
//Node scpd = new Node(SCPD_ROOTNODE,SCPD_ROOTNODE_NS); wrong!
Node scpd = new Node(SCPD_ROOTNODE); // better (twa)
scpd.addAttribute("xmlns",SCPD_ROOTNODE_NS); // better (twa)
scpd.addNode(sp);
getServiceData().setSCPDNode(scpd);
}
public Service(Node node) public Service(Node node)
{ {
@@ -307,6 +354,32 @@ public class Service
return true; return true;
} }
/**
* @since 1.8.0
*/
public boolean loadSCPD(InputStream input) throws ParserException
{
Parser parser = UPnP.getXMLParser();
Node scpdNode = parser.parse(input);
if (scpdNode == null)
return false;
ServiceData data = getServiceData();
data.setSCPDNode(scpdNode);
return true;
}
public void setDescriptionURL(String value)
{
getServiceData().setDescriptionURL(value);
}
public String getDescriptionURL()
{
return getServiceData().getDescriptionURL();
}
private Node getSCPDNode(URL scpdUrl) throws ParserException private Node getSCPDNode(URL scpdUrl) throws ParserException
{ {
Parser parser = UPnP.getXMLParser(); Parser parser = UPnP.getXMLParser();
@@ -326,49 +399,54 @@ public class Service
if (scpdNode != null) if (scpdNode != null)
return scpdNode; return scpdNode;
String scpdURLStr = getSCPDURL(); // Thanks for Jaap (Sep 18, 2010)
try {
URL scpdUrl = new URL(scpdURLStr);
scpdNode = getSCPDNode(scpdUrl);
}
catch (Exception e1) {
Device rootDev = getRootDevice(); Device rootDev = getRootDevice();
String urlBaseStr = rootDev.getURLBase(); if (rootDev == null)
// Thanks for Steven Yen (2003/09/03) return null;
if (urlBaseStr == null || urlBaseStr.length() <= 0) {
String location = rootDev.getLocation(); String scpdURLStr = getSCPDURL();
String locationHost = HTTP.getHost(location);
int locationPort = HTTP.getPort(location); // Thanks for Robin V. (Sep 18, 2010)
urlBaseStr = HTTP.getRequestHostURL(locationHost, locationPort); String rootDevPath = rootDev.getDescriptionFilePath();
} if(rootDevPath!=null) {
scpdURLStr = HTTP.toRelativeURL(scpdURLStr); File f;
String newScpdURLStr = urlBaseStr + scpdURLStr; f = new File(rootDevPath.concat(scpdURLStr));
if(f.exists()) {
try { try {
URL newScpdURL = new URL(newScpdURLStr); scpdNode = getSCPDNode(f);
scpdNode = getSCPDNode(newScpdURL); } catch (ParserException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} }
catch (Exception e2) { if(scpdNode!=null) {
newScpdURLStr = HTTP.getAbsoluteURL(urlBaseStr, scpdURLStr); data.setSCPDNode(scpdNode);
return scpdNode;
}
}
}
try { try {
URL newScpdURL = new URL(newScpdURLStr); URL scpdUrl = new URL(rootDev.getAbsoluteURL(scpdURLStr));
scpdNode = getSCPDNode(newScpdURL); scpdNode = getSCPDNode(scpdUrl);
if (scpdNode != null) {
data.setSCPDNode(scpdNode);
return scpdNode;
} }
catch (Exception e3) { }
newScpdURLStr = rootDev.getDescriptionFilePath() + scpdURLStr; catch (Exception e) {}
String newScpdURLStr = rootDev.getDescriptionFilePath() + HTTP.toRelativeURL(scpdURLStr);
try { try {
scpdNode = getSCPDNode(new File(newScpdURLStr)); scpdNode = getSCPDNode(new File(newScpdURLStr));
}
catch (Exception e4) {
Debug.warning(e4);
}
}
}
}
data.setSCPDNode(scpdNode);
return scpdNode; return scpdNode;
} }
catch (Exception e) {
Debug.warning(e);
}
return null;
}
public byte[] getSCPDData() public byte[] getSCPDData()
{ {
@@ -396,7 +474,6 @@ public class Service
Node actionListNode = scdpNode.getNode(ActionList.ELEM_NAME); Node actionListNode = scdpNode.getNode(ActionList.ELEM_NAME);
if (actionListNode == null) if (actionListNode == null)
return actionList; return actionList;
Node serviceNode = getServiceNode();
int nNode = actionListNode.getNNodes(); int nNode = actionListNode.getNNodes();
for (int n=0; n<nNode; n++) { for (int n=0; n<nNode; n++) {
Node node = actionListNode.getNode(n); Node node = actionListNode.getNode(n);
@@ -423,6 +500,22 @@ public class Service
return null; return null;
} }
public void addAction(Action a){
Iterator i = a.getArgumentList().iterator();
while (i.hasNext()) {
Argument arg = (Argument) i.next();
arg.setService(this);
}
Node scdpNode = getSCPDNode();
Node actionListNode = scdpNode.getNode(ActionList.ELEM_NAME);
if (actionListNode == null){
actionListNode = new Node(ActionList.ELEM_NAME);
scdpNode.addNode(actionListNode);
}
actionListNode.addNode(a.getActionNode());
}
//////////////////////////////////////////////// ////////////////////////////////////////////////
// serviceStateTable // serviceStateTable
//////////////////////////////////////////////// ////////////////////////////////////////////////
@@ -657,6 +750,8 @@ public class Service
subs[n] = subList.getSubscriber(n); subs[n] = subList.getSubscriber(n);
for (int n=0; n<subListCnt; n++) { for (int n=0; n<subListCnt; n++) {
Subscriber sub = subs[n]; Subscriber sub = subs[n];
if (sub == null)
continue;
if (sub.isExpired() == true) if (sub.isExpired() == true)
removeSubscriber(sub); removeSubscriber(sub);
} }
@@ -668,6 +763,8 @@ public class Service
subs[n] = subList.getSubscriber(n); subs[n] = subList.getSubscriber(n);
for (int n=0; n<subListCnt; n++) { for (int n=0; n<subListCnt; n++) {
Subscriber sub = subs[n]; Subscriber sub = subs[n];
if (sub == null)
continue;
if (notify(sub, stateVar) == false) { if (notify(sub, stateVar) == false) {
/* Don't remove for NMPR specification. /* Don't remove for NMPR specification.
removeSubscriber(sub); removeSubscriber(sub);
@@ -744,4 +841,47 @@ public class Service
action.setActionListener(listener); action.setActionListener(listener);
} }
} }
/**
* Add the StateVariable to the service.<br>
* <br>
* Note: This method should be used to create a dynamic<br>
* Device withtout writing any XML that describe the device<br>.
* <br>
* Note: that no control for duplicate StateVariable is done.
*
* @param var StateVariable that will be added
*
* @author Stefano "Kismet" Lenzi - kismet-sl@users.sourceforge.net - 2005
*/
public void addStateVariable(StateVariable var) {
//TODO Some test are done not stable
Node stateTableNode = getSCPDNode().getNode(ServiceStateTable.ELEM_NAME);
if (stateTableNode == null){
stateTableNode = new Node(ServiceStateTable.ELEM_NAME);
/*
* Force the node <serviceStateTable> to be the first node inside <scpd>
*/
//getSCPDNode().insertNode(stateTableNode,0);
getSCPDNode().addNode(stateTableNode);
}
var.setServiceNode(getServiceNode());
stateTableNode.addNode(var.getStateVariableNode());
}
////////////////////////////////////////////////
// userData
////////////////////////////////////////////////
private Object userData = null;
public void setUserData(Object data)
{
userData = data;
}
public Object getUserData()
{
return userData;
}
} }

View File

@@ -17,7 +17,7 @@
package org.cybergarage.upnp; package org.cybergarage.upnp;
import java.util.*; import java.util.Vector;
public class ServiceList extends Vector public class ServiceList extends Vector
{ {
@@ -25,7 +25,6 @@ public class ServiceList extends Vector
// Constants // Constants
//////////////////////////////////////////////// ////////////////////////////////////////////////
private static final long serialVersionUID = 6372904993975135597L;
public final static String ELEM_NAME = "serviceList"; public final static String ELEM_NAME = "serviceList";
//////////////////////////////////////////////// ////////////////////////////////////////////////

View File

@@ -15,7 +15,7 @@
package org.cybergarage.upnp; package org.cybergarage.upnp;
import java.util.*; import java.util.Vector;
public class ServiceStateTable extends Vector public class ServiceStateTable extends Vector
{ {
@@ -23,7 +23,6 @@ public class ServiceStateTable extends Vector
// Constants // Constants
//////////////////////////////////////////////// ////////////////////////////////////////////////
private static final long serialVersionUID = 7626909231678469365L;
public final static String ELEM_NAME = "serviceStateTable"; public final static String ELEM_NAME = "serviceStateTable";
//////////////////////////////////////////////// ////////////////////////////////////////////////

View File

@@ -39,16 +39,21 @@
* - Fixed setValue() to compare only when the current value is not null. * - Fixed setValue() to compare only when the current value is not null.
* 02/28/05 * 02/28/05
* - Changed getAllowedValueList() to use AllowedValue instead of String as the member. * - Changed getAllowedValueList() to use AllowedValue instead of String as the member.
* 04/12/06
* - Added setUserData() and getUserData() to set a user original data object.
* *
******************************************************************/ ******************************************************************/
package org.cybergarage.upnp; package org.cybergarage.upnp;
import java.util.Iterator;
import org.cybergarage.xml.*; import org.cybergarage.upnp.control.QueryListener;
import org.cybergarage.util.*; import org.cybergarage.upnp.control.QueryRequest;
import org.cybergarage.upnp.control.QueryResponse;
import org.cybergarage.upnp.control.*; import org.cybergarage.upnp.xml.NodeData;
import org.cybergarage.upnp.xml.*; import org.cybergarage.upnp.xml.StateVariableData;
import org.cybergarage.util.Debug;
import org.cybergarage.xml.Node;
public class StateVariable extends NodeData public class StateVariable extends NodeData
{ {
@@ -70,6 +75,10 @@ public class StateVariable extends NodeData
return serviceNode; return serviceNode;
} }
void setServiceNode(Node n){
serviceNode=n;
}
public Service getService() public Service getService()
{ {
Node serviceNode = getServiceNode(); Node serviceNode = getServiceNode();
@@ -90,7 +99,7 @@ public class StateVariable extends NodeData
public StateVariable() public StateVariable()
{ {
this.serviceNode = null; this.serviceNode = null;
this.stateVariableNode = new Node(); this.stateVariableNode = new Node(ELEM_NAME);
} }
public StateVariable(Node serviceNode, Node stateVarNode) public StateVariable(Node serviceNode, Node stateVarNode)
@@ -238,7 +247,7 @@ public class StateVariable extends NodeData
AllowedValueList valueList= new AllowedValueList(); AllowedValueList valueList= new AllowedValueList();
Node valueListNode = getStateVariableNode().getNode(AllowedValueList.ELEM_NAME); Node valueListNode = getStateVariableNode().getNode(AllowedValueList.ELEM_NAME);
if (valueListNode == null) if (valueListNode == null)
return valueList; return null;
int nNode = valueListNode.getNNodes(); int nNode = valueListNode.getNNodes();
for (int n=0; n<nNode; n++) { for (int n=0; n<nNode; n++) {
Node node = valueListNode.getNode(n); Node node = valueListNode.getNode(n);
@@ -250,10 +259,41 @@ public class StateVariable extends NodeData
return valueList; return valueList;
} }
/**
* This method ovverride the value of the AllowedValueList Node<br>
* of this object. <br>
* <br>
* Note: This method should be used to create a dynamic<br>
* Device withtout writing any XML that describe the device<br>.
* <br>
* Note2: The enforce the constraint of the SCPD rule the<br>
* AllowedValueList and AllowedValueRange are mutal exclusive<br>
* the last set will be the only present<br>
*
* @param avl The new AllowedValueList
*
* @author Stefano "Kismet" Lenzi - kismet-sl@users.sourceforge.net - 2005
*/
public void setAllowedValueList(AllowedValueList avl) {
//TODO Some test done not stable
getStateVariableNode().removeNode(AllowedValueList.ELEM_NAME);
getStateVariableNode().removeNode(AllowedValueRange.ELEM_NAME);
Node n = new Node(AllowedValueList.ELEM_NAME);
Iterator i=avl.iterator();
while (i.hasNext()) {
AllowedValue av = (AllowedValue) i.next();
//n.addNode(new Node(AllowedValue.ELEM_NAME,av.getValue())); wrong!
n.addNode(av.getAllowedValueNode()); //better (twa)
}
getStateVariableNode().addNode(n);
}
public boolean hasAllowedValueList() public boolean hasAllowedValueList()
{ {
AllowedValueList valueList = getAllowedValueList(); AllowedValueList valueList = getAllowedValueList();
return (0 < valueList.size()) ? true : false; return (valueList != null) ? true : false;
} }
//////////////////////////////////////////////// ////////////////////////////////////////////////
@@ -268,6 +308,29 @@ public class StateVariable extends NodeData
return new AllowedValueRange(valueRangeNode); return new AllowedValueRange(valueRangeNode);
} }
/**
* This method ovverride the value of the AllowedValueRange Node<br>
* of this object. <br>
* <br>
* Note: This method should be used to create a dynamic<br>
* Device withtout writing any XML that describe the device<br>.
* <br>
* Note2: The enforce the constraint of the SCPD rule the<br>
* AllowedValueList and AllowedValueRange are mutal exclusive<br>
* the last set will be the only present<br>
*
* @param avr The new AllowedValueRange
*
* @author Stefano "Kismet" Lenzi - kismet-sl@users.sourceforge.net - 2005
*/
public void setAllowedValueRange(AllowedValueRange avr){
//TODO Some test done not stable
getStateVariableNode().removeNode(AllowedValueList.ELEM_NAME);
getStateVariableNode().removeNode(AllowedValueRange.ELEM_NAME);
getStateVariableNode().addNode(avr.getAllowedValueRangeNode());
}
public boolean hasAllowedValueRange() public boolean hasAllowedValueRange()
{ {
return (getAllowedValueRange() != null) ? true : false; return (getAllowedValueRange() != null) ? true : false;
@@ -371,4 +434,44 @@ public class StateVariable extends NodeData
{ {
return upnpStatus; return upnpStatus;
} }
private static final String DEFAULT_VALUE = "defaultValue";
////////////////////////////////////////////////
/**
* Get the value of DefaultValue of this StateVariable
*
* @author Stefano Lenzi kismet-sl@users.sourceforge.net
*/
public String getDefaultValue() {
return getStateVariableNode().getNodeValue(DEFAULT_VALUE);
}
/**
* This method ovverride the value of the DefaultValue of this object. <br>
* <br>
* Note: This method should be used to create a dynamic<br>
* Device withtout writing any XML that describe the device<br>.
*
* @param value The new String value
*
* @author Stefano Lenzi kismet-sl@users.sourceforge.net
*/
public void setDefaultValue(String value){
getStateVariableNode().setNode(DEFAULT_VALUE,value);
}
////////////////////////////////////////////////
// userData
////////////////////////////////////////////////
private Object userData = null;
public void setUserData(Object data)
{
userData = data;
}
public Object getUserData()
{
return userData;
}
} }

View File

@@ -16,17 +16,20 @@
* - Added support for XML Parser * - Added support for XML Parser
* 06/18/03 * 06/18/03
* - Added INMPR03 and INMPR03_VERSION. * - Added INMPR03 and INMPR03_VERSION.
* 04/14/06
* - Added some functios about time-to-live, and the default value is 4.
* 05/11/09
* - Changed loadDefaultXMLParser() to load org.cybergarage.xml.parser.XmlPullParser at first.
* *
******************************************************************/ ******************************************************************/
package org.cybergarage.upnp; package org.cybergarage.upnp;
import org.cybergarage.upnp.ssdp.*; import org.cybergarage.net.HostInterface;
//import org.cybergarage.util.*; import org.cybergarage.soap.SOAP;
import org.cybergarage.xml.*; import org.cybergarage.upnp.ssdp.SSDP;
import org.cybergarage.xml.parser.*; import org.cybergarage.util.Debug;
import org.cybergarage.soap.*; import org.cybergarage.xml.Parser;
import org.cybergarage.net.*;
public class UPnP public class UPnP
{ {
@@ -34,8 +37,15 @@ public class UPnP
// Constants // Constants
//////////////////////////////////////////////// ////////////////////////////////////////////////
public final static String NAME = "CyberLink"; /**
public final static String VERSION = "1.7"; * Name of the system properties used to identifies the default XML Parser.<br>
* The value of the properties MUST BE the fully qualified class name of<br>
* XML Parser which CyberLink should use.
*/
public final static String XML_CLASS_PROPERTTY="cyberlink.upnp.xml.parser";
public final static String NAME = "CyberLinkJava";
public final static String VERSION = "1.8";
public final static int SERVER_RETRY_COUNT = 100; public final static int SERVER_RETRY_COUNT = 100;
public final static int DEFAULT_EXPIRED_DEVICE_EXTRA_TIME = 60; public final static int DEFAULT_EXPIRED_DEVICE_EXTRA_TIME = 60;
@@ -51,7 +61,7 @@ public class UPnP
public final static String INMPR03_VERSION = "1.0"; public final static String INMPR03_VERSION = "1.0";
public final static int INMPR03_DISCOVERY_OVER_WIRELESS_COUNT = 4; public final static int INMPR03_DISCOVERY_OVER_WIRELESS_COUNT = 4;
public final static String XML_DECLARATION = "<?xml version=\"1.0\"?>"; public final static String XML_DECLARATION = "<?xml version=\"1.0\" encoding=\"utf-8\"?>";
//////////////////////////////////////////////// ////////////////////////////////////////////////
// Enable / Disable // Enable / Disable
@@ -193,9 +203,68 @@ public class UPnP
public final static Parser getXMLParser() public final static Parser getXMLParser()
{ {
if(xmlParser == null){
xmlParser = loadDefaultXMLParser();
if(xmlParser == null)
throw new RuntimeException("No XML parser defined. And unable to laod any. \n" +
"Try to invoke UPnP.setXMLParser before UPnP.getXMLParser");
SOAP.setXMLParser(xmlParser);
}
return xmlParser; return xmlParser;
} }
/**
* This method loads the default XML Parser using the following behavior:
* - First if present loads the parsers specified by the system property {@link UPnP#XML_CLASS_PROPERTTY}<br>
* - Second by a fall-back technique, it tries to load the XMLParser from one<br>
* of the following classes: {@link JaxpParser}, {@link kXML2Parser}, {@link XercesParser}
*
* @return {@link Parser} which has been loaded successuflly or null otherwise
*
* @since 1.8.0
*/
private static Parser loadDefaultXMLParser() {
Parser parser = null;
String[] parserClass = new String[]{
System.getProperty(XML_CLASS_PROPERTTY),
"org.cybergarage.xml.parser.XmlPullParser",
"org.cybergarage.xml.parser.JaxpParser",
"org.cybergarage.xml.parser.kXML2Parser",
"org.cybergarage.xml.parser.XercesParser"
};
for (int i = 0; i < parserClass.length; i++) {
if(parserClass[i]==null)
continue;
try {
parser = (Parser) Class.forName(parserClass[i]).newInstance();
return parser;
} catch (Throwable e) {
Debug.warning("Unable to load "+parserClass[i]+" as XMLParser due to "+e);
}
}
return null;
}
////////////////////////////////////////////////
// TTL
////////////////////////////////////////////////
public final static int DEFAULT_TTL = 4;
private static int timeToLive = DEFAULT_TTL;
public final static void setTimeToLive(int value)
{
timeToLive = value;
}
public final static int getTimeToLive()
{
return timeToLive;
}
//////////////////////////////////////////////// ////////////////////////////////////////////////
// Initialize // Initialize
//////////////////////////////////////////////// ////////////////////////////////////////////////
@@ -206,16 +275,14 @@ public class UPnP
// Interface Option // Interface Option
//////////////////////////// ////////////////////////////
setXMLParser(new JaxpParser());
//setXMLParser(new kXML2Parser()); //setXMLParser(new kXML2Parser());
//////////////////////////// ////////////////////////////
// Interface Option // TimeToLive
//////////////////////////// ////////////////////////////
/*
if (HostInterface.hasIPv6Addresses() == true) setTimeToLive(DEFAULT_TTL);
setEnable(USE_ONLY_IPV6_ADDR);
*/
//////////////////////////// ////////////////////////////
// Debug Option // Debug Option

View File

@@ -16,6 +16,7 @@
******************************************************************/ ******************************************************************/
package org.cybergarage.upnp; package org.cybergarage.upnp;
import org.cybergarage.http.HTTPStatus;
public class UPnPStatus public class UPnPStatus
{ {
@@ -39,8 +40,8 @@ public class UPnPStatus
case INVALID_VAR: return "Invalid Var"; case INVALID_VAR: return "Invalid Var";
case PRECONDITION_FAILED: return "Precondition Failed"; case PRECONDITION_FAILED: return "Precondition Failed";
case ACTION_FAILED: return "Action Failed"; case ACTION_FAILED: return "Action Failed";
default: return HTTPStatus.code2String(code);
} }
return "";
} }
//////////////////////////////////////////////// ////////////////////////////////////////////////

View File

@@ -102,6 +102,11 @@ public class ControlResponse extends SOAPResponse
return faultNode; return faultNode;
} }
private Node createFaultResponseNode(int errCode)
{
return createFaultResponseNode(errCode, UPnPStatus.code2String(errCode));
}
//////////////////////////////////////////////// ////////////////////////////////////////////////
// UPnP Error // UPnP Error
//////////////////////////////////////////////// ////////////////////////////////////////////////

View File

@@ -74,6 +74,8 @@ public class QueryRequest extends ControlRequest
{ {
Service service = stateVar.getService(); Service service = stateVar.getService();
String ctrlURL = service.getControlURL();
setRequestHost(service); setRequestHost(service);
setEnvelopeNode(SOAP.createEnvelopeBodyNode()); setEnvelopeNode(SOAP.createEnvelopeBodyNode());

View File

@@ -19,8 +19,6 @@ import java.io.*;
public class InvalidDescriptionException extends Exception public class InvalidDescriptionException extends Exception
{ {
private static final long serialVersionUID = -3144583349586910509L;
public InvalidDescriptionException() public InvalidDescriptionException()
{ {
super(); super();

View File

@@ -115,6 +115,7 @@ public class NotifyRequest extends SOAPRequest
public boolean setRequest(Subscriber sub, String varName, String value) public boolean setRequest(Subscriber sub, String varName, String value)
{ {
String callback = sub.getDeliveryURL();
String sid = sub.getSID(); String sid = sub.getSID();
long notifyCnt = sub.getNotifyCount(); long notifyCnt = sub.getNotifyCount();
String host = sub.getDeliveryHost(); String host = sub.getDeliveryHost();
@@ -154,6 +155,19 @@ public class NotifyRequest extends SOAPRequest
return propSetNode; return propSetNode;
} }
private Node getVariableNode()
{
Node rootNode = getEnvelopeNode();
if (rootNode == null)
return null;
if (rootNode.hasNodes() == false)
return null;
Node propNode = rootNode.getNode(0);
if (propNode.hasNodes() == false)
return null;
return propNode.getNode(0);
}
// Thanks for Giordano Sassaroli <sassarol@cefriel.it> (09/08/03) // Thanks for Giordano Sassaroli <sassarol@cefriel.it> (09/08/03)
private Property getProperty(Node varNode) private Property getProperty(Node varNode)
{ {

View File

@@ -23,7 +23,6 @@ public class PropertyList extends Vector
// Constants // Constants
//////////////////////////////////////////////// ////////////////////////////////////////////////
private static final long serialVersionUID = 8718064210738306226L;
public final static String ELEM_NAME = "PropertyList"; public final static String ELEM_NAME = "PropertyList";
//////////////////////////////////////////////// ////////////////////////////////////////////////

View File

@@ -25,8 +25,6 @@ public class SubscriberList extends Vector
// Constructor // Constructor
//////////////////////////////////////////////// ////////////////////////////////////////////////
private static final long serialVersionUID = -648427977601494972L;
public SubscriberList() public SubscriberList()
{ {
} }

View File

@@ -68,6 +68,8 @@ public class Subscription
{ {
if (headerValue == null) if (headerValue == null)
return ""; return "";
if (headerValue.startsWith(Subscription.UUID) == false)
return headerValue;
return headerValue.substring(Subscription.UUID.length(), headerValue.length()); return headerValue.substring(Subscription.UUID.length(), headerValue.length());
} }

View File

@@ -43,12 +43,12 @@ public class SubscriptionRequest extends HTTPRequest
// Constructor // Constructor
//////////////////////////////////////////////// ////////////////////////////////////////////////
public SubscriptionRequest() public SubscriptionRequest(){
{ setContentLength(0);
} }
public SubscriptionRequest(HTTPRequest httpReq) public SubscriptionRequest(HTTPRequest httpReq){
{ this();
set(httpReq); set(httpReq);
} }

View File

@@ -19,16 +19,32 @@
* 11/19/04 * 11/19/04
* - Theo Beisch <theo.beisch@gmx.de> * - Theo Beisch <theo.beisch@gmx.de>
* - Changed send() to set the TTL as 4. * - Changed send() to set the TTL as 4.
* 08/23/07
* - Thanks for Kazuyuki Shudo
* - Changed receive() to throw IOException.
* 01/10/08
* - Changed getLocalAddress() to return a brank string when the ssdpMultiGroup or ssdpMultiIf is null on Android m3-rc37a.
* *
******************************************************************/ ******************************************************************/
package org.cybergarage.upnp.ssdp; package org.cybergarage.upnp.ssdp;
import java.net.*; import java.net.DatagramPacket;
import java.util.*; import java.net.MulticastSocket;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.NetworkInterface;
import java.util.Enumeration;
import java.io.IOException;
import org.cybergarage.http.*; import org.cybergarage.http.HTTPRequest;
import org.cybergarage.util.*; import org.cybergarage.upnp.UPnP;
import org.cybergarage.util.Debug;
// Dummy Class for Android m3-rc37a
// import org.cybergarage.android.MulticastSocket;
public class HTTPMUSocket public class HTTPMUSocket
{ {
@@ -64,6 +80,8 @@ public class HTTPMUSocket
public String getLocalAddress() public String getLocalAddress()
{ {
if (ssdpMultiGroup == null || ssdpMultiIf == null)
return "";
InetAddress mcastAddr = ssdpMultiGroup.getAddress(); InetAddress mcastAddr = ssdpMultiGroup.getAddress();
Enumeration addrs = ssdpMultiIf.getInetAddresses(); Enumeration addrs = ssdpMultiIf.getInetAddresses();
while (addrs.hasMoreElements()) { while (addrs.hasMoreElements()) {
@@ -76,6 +94,34 @@ public class HTTPMUSocket
return ""; return "";
} }
/**
*
* @return the destination port for multicast packet
* @since 1.8
*/
public int getMulticastPort(){
return ssdpMultiGroup.getPort();
}
/**
*
* @return the source port for multicast packet
* @since 1.8
*/
public int getLocalPort(){
return ssdpMultiSock.getLocalPort();
}
/**
*
* @return the opened {@link MulticastSocket}
* @since 1.8
*/
public MulticastSocket getSocket(){
return ssdpMultiSock;
}
//////////////////////////////////////////////// ////////////////////////////////////////////////
// MulticastAddr // MulticastAddr
//////////////////////////////////////////////// ////////////////////////////////////////////////
@@ -90,19 +136,20 @@ public class HTTPMUSocket
return getMulticastInetAddress().getHostAddress(); return getMulticastInetAddress().getHostAddress();
} }
//////////////////////////////////////////////// /**
// open/close * @param addr {@link String} rappresenting the multicast hostname to join into.
//////////////////////////////////////////////// * @param port int rappresenting the port to be use poth as source and destination
* @param bindAddr {@link InetAddress} which identify the hostname of the interface
public boolean open(String addr, int port, String bindAddr) * to use for sending and recieving multicast packet
{ */
public boolean open(String addr,int port, InetAddress bindAddr){
try { try {
ssdpMultiSock = new MulticastSocket(null); ssdpMultiSock = new MulticastSocket(null);
ssdpMultiSock.setReuseAddress(true); ssdpMultiSock.setReuseAddress(true);
InetSocketAddress bindSockAddr = new InetSocketAddress(port); InetSocketAddress bindSockAddr = new InetSocketAddress(port);
ssdpMultiSock.bind(bindSockAddr); ssdpMultiSock.bind(bindSockAddr);
ssdpMultiGroup = new InetSocketAddress(InetAddress.getByName(addr), port); ssdpMultiGroup = new InetSocketAddress(InetAddress.getByName(addr), port);
ssdpMultiIf = NetworkInterface.getByInetAddress(InetAddress.getByName(bindAddr)); ssdpMultiIf = NetworkInterface.getByInetAddress(bindAddr);
ssdpMultiSock.joinGroup(ssdpMultiGroup, ssdpMultiIf); ssdpMultiSock.joinGroup(ssdpMultiGroup, ssdpMultiIf);
} }
catch (Exception e) { catch (Exception e) {
@@ -113,6 +160,16 @@ public class HTTPMUSocket
return true; return true;
} }
public boolean open(String addr, int port, String bindAddr)
{
try {
return open(addr,port,InetAddress.getByName(bindAddr));
}catch (Exception e) {
Debug.warning(e);
return false;
}
}
public boolean close() public boolean close()
{ {
if (ssdpMultiSock == null) if (ssdpMultiSock == null)
@@ -120,6 +177,7 @@ public class HTTPMUSocket
try { try {
ssdpMultiSock.leaveGroup(ssdpMultiGroup, ssdpMultiIf); ssdpMultiSock.leaveGroup(ssdpMultiGroup, ssdpMultiIf);
ssdpMultiSock.close();
ssdpMultiSock = null; ssdpMultiSock = null;
} }
catch (Exception e) { catch (Exception e) {
@@ -141,12 +199,12 @@ public class HTTPMUSocket
if ((bindAddr) != null && (0 < bindPort)) { if ((bindAddr) != null && (0 < bindPort)) {
msock = new MulticastSocket(null); msock = new MulticastSocket(null);
msock.bind(new InetSocketAddress(bindAddr, bindPort)); msock.bind(new InetSocketAddress(bindAddr, bindPort));
} }else{
else
msock = new MulticastSocket(); msock = new MulticastSocket();
}
DatagramPacket dgmPacket = new DatagramPacket(msg.getBytes(), msg.length(), ssdpMultiGroup); DatagramPacket dgmPacket = new DatagramPacket(msg.getBytes(), msg.length(), ssdpMultiGroup);
// Thnaks for Tho Beisch (11/09/04) // Thnaks for Theo Beisch (11/09/04)
msock.setTimeToLive(4); msock.setTimeToLive(UPnP.getTimeToLive());
msock.send(dgmPacket); msock.send(dgmPacket);
msock.close(); msock.close();
} }
@@ -180,18 +238,21 @@ public class HTTPMUSocket
// reveive // reveive
//////////////////////////////////////////////// ////////////////////////////////////////////////
public SSDPPacket receive() public SSDPPacket receive() throws IOException
{ {
byte ssdvRecvBuf[] = new byte[SSDP.RECV_MESSAGE_BUFSIZE]; byte ssdvRecvBuf[] = new byte[SSDP.RECV_MESSAGE_BUFSIZE];
SSDPPacket recvPacket = new SSDPPacket(ssdvRecvBuf, ssdvRecvBuf.length); SSDPPacket recvPacket = new SSDPPacket(ssdvRecvBuf, ssdvRecvBuf.length);
recvPacket.setLocalAddress(getLocalAddress()); recvPacket.setLocalAddress(getLocalAddress());
try {
ssdpMultiSock.receive(recvPacket.getDatagramPacket()); // Thanks for Kazuyuki Shudo (08/23/07)
// Thanks for Stephan Mehlhase (2010-10-26)
if (ssdpMultiSock != null)
ssdpMultiSock.receive(recvPacket.getDatagramPacket()); // throws IOException
else
throw new IOException("Multicast socket has already been closed.");
recvPacket.setTimeStamp(System.currentTimeMillis()); recvPacket.setTimeStamp(System.currentTimeMillis());
}
catch (Exception e) {
//Debug.warning(e);
}
return recvPacket; return recvPacket;
} }
} }

View File

@@ -23,9 +23,12 @@
package org.cybergarage.upnp.ssdp; package org.cybergarage.upnp.ssdp;
import java.net.*; import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import org.cybergarage.util.*; import org.cybergarage.util.Debug;
public class HTTPUSocket public class HTTPUSocket
{ {
@@ -76,6 +79,15 @@ public class HTTPUSocket
localAddr = addr; localAddr = addr;
} }
/**
*
* @return {@link DatagramSocket} open for receieving packets
* @since 1.8
*/
public DatagramSocket getUDPSocket(){
return ssdpUniSock;
}
public String getLocalAddress() public String getLocalAddress()
{ {
if (0 < localAddr.length()) if (0 < localAddr.length())
@@ -107,17 +119,30 @@ public class HTTPUSocket
close(); close();
try { try {
// Bind only using the port without the interface address. (2003/12/12) // Changed to bind the specified address and port for Android v1.6 (2009/10/07)
InetSocketAddress bindSock = new InetSocketAddress(/*InetAddress.getByName(bindAddr), */ bindPort); InetSocketAddress bindInetAddr = new InetSocketAddress(InetAddress.getByName(bindAddr), bindPort);
ssdpUniSock = new DatagramSocket(null); ssdpUniSock = new DatagramSocket(bindInetAddr);
ssdpUniSock.setReuseAddress(true);
ssdpUniSock.bind(bindSock);
} }
catch (Exception e) { catch (Exception e) {
Debug.warning(e); Debug.warning(e);
return false; return false;
} }
/*
try {
// Bind only using the port without the interface address. (2003/12/12)
InetSocketAddress bindInetAddr = new InetSocketAddress(bindPort);
ssdpUniSock = new DatagramSocket(null);
ssdpUniSock.setReuseAddress(true);
ssdpUniSock.bind(bindInetAddr);
return true;
}
catch (Exception e) {
Debug.warning(e);
return false;
}
*/
setLocalAddress(bindAddr); setLocalAddress(bindAddr);
return true; return true;

View File

@@ -12,19 +12,41 @@
* - first revision. * - first revision.
* 05/13/03 * 05/13/03
* - Added constants for IPv6. * - Added constants for IPv6.
* 08/03/05
* - Thanks for Stefano Lenzi <kismet-sl at users.sourceforge.net>
* and Mikael <mhakman at users.sourceforge.net>
* - Fixed getLeaseTime() to parse normally when the value includes extra strings such as white space.
* *
******************************************************************/ ******************************************************************/
package org.cybergarage.upnp.ssdp; package org.cybergarage.upnp.ssdp;
import org.cybergarage.util.Debug;
/**
*
* This class defines constant value related to SSDP.<br>
* All the values defined here are complaint to the UPnP Standard
*
* @author Satoshi "skonno" Konno
* @author Stefano "Kismet" Lenzi
* @version 1.0
*
*/
public class SSDP public class SSDP
{ {
//////////////////////////////////////////////// ////////////////////////////////////////////////
// Constants // Constants
//////////////////////////////////////////////// ////////////////////////////////////////////////
/**
* Default destination port for SSDP multicast messages
*/
public static final int PORT = 1900; public static final int PORT = 1900;
/**
* Default IPv4 multicast address for SSDP messages
*/
public static final String ADDRESS = "239.255.255.250"; public static final String ADDRESS = "239.255.255.250";
public static final String IPV6_LINK_LOCAL_ADDRESS = "FF02::C"; public static final String IPV6_LINK_LOCAL_ADDRESS = "FF02::C";
@@ -62,15 +84,25 @@ public class SSDP
// LeaseTime // LeaseTime
//////////////////////////////////////////////// ////////////////////////////////////////////////
public final static int getLeaseTime(String cacheCont) public final static int getLeaseTime(String cacheCont){
{ /*
int equIdx = cacheCont.indexOf('='); * Search for max-age keyword instead of equals sign Found value of
* max-age ends at next comma or end of string
*/
int mx = 0; int mx = 0;
int maxAgeIdx = cacheCont.indexOf("max-age");
if (maxAgeIdx >= 0) {
int endIdx = cacheCont.indexOf(',',maxAgeIdx);
if (endIdx < 0)
endIdx = cacheCont.length();
try { try {
String mxStr = new String(cacheCont.getBytes(), equIdx+1, cacheCont.length() - (equIdx+1)); maxAgeIdx = cacheCont.indexOf("=",maxAgeIdx);
String mxStr = cacheCont.substring(maxAgeIdx+1,endIdx).trim();
mx = Integer.parseInt(mxStr); mx = Integer.parseInt(mxStr);
} catch (Exception e) {
Debug.warning (e);
}
} }
catch (Exception e) {}
return mx; return mx;
} }
} }

View File

@@ -15,7 +15,7 @@
package org.cybergarage.upnp.ssdp; package org.cybergarage.upnp.ssdp;
import org.cybergarage.http.*; import org.cybergarage.http.HTTP;
public class SSDPNotifyRequest extends SSDPRequest public class SSDPNotifyRequest extends SSDPRequest
{ {

View File

@@ -19,18 +19,33 @@
* - Mikael Hakman <mhakman@dkab.net> * - Mikael Hakman <mhakman@dkab.net>
* - Handle receive() returning null. * - Handle receive() returning null.
* - Added close() in stop(). * - Added close() in stop().
* 08/23/07
* - Thanks for Kazuyuki Shudo
* - Changed run() to catch IOException of HTTPMUSocket::receive().
* 01/31/08
* - Changed start() not to abort when the interface infomation is null on Android m3-rc37a.
* *
******************************************************************/ ******************************************************************/
package org.cybergarage.upnp.ssdp; package org.cybergarage.upnp.ssdp;
import java.net.*; import java.net.*;
import java.io.IOException;
import org.cybergarage.net.*; import org.cybergarage.net.*;
import org.cybergarage.util.*; import org.cybergarage.util.*;
import org.cybergarage.http.*; import org.cybergarage.http.*;
import org.cybergarage.upnp.*; import org.cybergarage.upnp.*;
/**
*
* This class identifies a SSDP socket only for <b>notifing packet</b>.<br>
*
* @author Satoshi "skonno" Konno
* @author Stefano "Kismet" Lenzi
* @version 1.8
*
*/
public class SSDPNotifySocket extends HTTPMUSocket implements Runnable public class SSDPNotifySocket extends HTTPMUSocket implements Runnable
{ {
private boolean useIPv6Address; private boolean useIPv6Address;
@@ -67,10 +82,13 @@ public class SSDPNotifySocket extends HTTPMUSocket implements Runnable
return controlPoint; return controlPoint;
} }
//////////////////////////////////////////////// /**
// post (SSDPNotifySocket) * This method send a {@link SSDPNotifyRequest} over {@link SSDPNotifySocket}
//////////////////////////////////////////////// *
* @param req the {@link SSDPNotifyRequest} to send
* @return true if and only if the trasmission succeced<br>
* Because it rely on UDP doesn't mean that it's also recieved
*/
public boolean post(SSDPNotifyRequest req) public boolean post(SSDPNotifyRequest req)
{ {
String ssdpAddr = SSDP.ADDRESS; String ssdpAddr = SSDP.ADDRESS;
@@ -94,7 +112,15 @@ public class SSDPNotifySocket extends HTTPMUSocket implements Runnable
while (deviceNotifyThread == thisThread) { while (deviceNotifyThread == thisThread) {
Thread.yield(); Thread.yield();
SSDPPacket packet = receive();
// Thanks for Kazuyuki Shudo (08/23/07)
SSDPPacket packet = null;
try {
packet = receive();
}
catch (IOException e) {
break;
}
// Thanks for Mikael Hakman (04/20/05) // Thanks for Mikael Hakman (04/20/05)
if (packet == null) if (packet == null)
@@ -104,19 +130,26 @@ public class SSDPNotifySocket extends HTTPMUSocket implements Runnable
InetAddress maddr = getMulticastInetAddress(); InetAddress maddr = getMulticastInetAddress();
InetAddress pmaddr = packet.getHostInetAddress(); InetAddress pmaddr = packet.getHostInetAddress();
if (maddr.equals(pmaddr) == false) { if (maddr.equals(pmaddr) == false) {
Debug.warning("Invalidate Multicast Recieved : " + maddr + "," + pmaddr); Debug.warning("Invalidate Multicast Recieved from IP " + maddr + " on " + pmaddr);
continue; continue;
} }
//TODO Must be performed on a different Thread in order to prevent UDP packet losses.
if (ctrlPoint != null) if (ctrlPoint != null)
ctrlPoint.notifyReceived(packet); ctrlPoint.notifyReceived(packet);
} }
} }
public void start() public void start(){
{ StringBuffer name = new StringBuffer("Cyber.SSDPNotifySocket/");
deviceNotifyThread = new Thread(this, "UPnP-SSDPNotifySocket"); String localAddr = this.getLocalAddress();
deviceNotifyThread.setDaemon(true); // localAddr is null on Android m3-rc37a (01/30/08)
if (localAddr != null && 0 < localAddr.length()) {
name.append(this.getLocalAddress()).append(':');
name.append(this.getLocalPort()).append(" -> ");
name.append(this.getMulticastAddress()).append(':');
name.append(this.getMulticastPort());
}
deviceNotifyThread = new Thread(this,name.toString());
deviceNotifyThread.start(); deviceNotifyThread.start();
} }

View File

@@ -15,6 +15,7 @@
package org.cybergarage.upnp.ssdp; package org.cybergarage.upnp.ssdp;
import java.net.InetAddress;
import java.util.*; import java.util.*;
import org.cybergarage.net.*; import org.cybergarage.net.*;
@@ -27,10 +28,18 @@ public class SSDPNotifySocketList extends Vector
// Constructor // Constructor
//////////////////////////////////////////////// ////////////////////////////////////////////////
private static final long serialVersionUID = -7066290881503106399L; private InetAddress[] binds = null;
public SSDPNotifySocketList() public SSDPNotifySocketList() {
{ }
/**
*
* @param binds The host to bind the service <tt>null</tt> means to bind to default.
* @since 1.8
*/
public SSDPNotifySocketList(InetAddress[] binds){
this.binds=binds;
} }
//////////////////////////////////////////////// ////////////////////////////////////////////////
@@ -59,14 +68,28 @@ public class SSDPNotifySocketList extends Vector
// Methods // Methods
//////////////////////////////////////////////// ////////////////////////////////////////////////
public boolean open() public boolean open(){
{ InetAddress[] binds=this.binds ;
String[] bindAddresses;
if(binds!=null){
bindAddresses = new String[binds.length];
for (int i = 0; i < binds.length; i++) {
bindAddresses[i] = binds[i].getHostAddress();
}
}else{
int nHostAddrs = HostInterface.getNHostAddresses(); int nHostAddrs = HostInterface.getNHostAddresses();
bindAddresses = new String[nHostAddrs];
for (int n=0; n<nHostAddrs; n++) { for (int n=0; n<nHostAddrs; n++) {
String bindAddr = HostInterface.getHostAddress(n); bindAddresses[n] = HostInterface.getHostAddress(n);
SSDPNotifySocket ssdpNotifySocket = new SSDPNotifySocket(bindAddr); }
}
for (int i = 0; i < bindAddresses.length; i++) {
if(bindAddresses[i]!=null){
SSDPNotifySocket ssdpNotifySocket = new SSDPNotifySocket(bindAddresses[i]);
add(ssdpNotifySocket); add(ssdpNotifySocket);
} }
}
return true; return true;
} }

View File

@@ -18,6 +18,8 @@
package org.cybergarage.upnp.ssdp; package org.cybergarage.upnp.ssdp;
import java.io.InputStream;
import org.cybergarage.http.*; import org.cybergarage.http.*;
public class SSDPRequest extends HTTPRequest public class SSDPRequest extends HTTPRequest
@@ -31,6 +33,11 @@ public class SSDPRequest extends HTTPRequest
setVersion(HTTP.VERSION_11); setVersion(HTTP.VERSION_11);
} }
public SSDPRequest(InputStream in)
{
super(in);
}
//////////////////////////////////////////////// ////////////////////////////////////////////////
// NT // NT
//////////////////////////////////////////////// ////////////////////////////////////////////////

View File

@@ -24,6 +24,8 @@
package org.cybergarage.upnp.ssdp; package org.cybergarage.upnp.ssdp;
import java.io.InputStream;
import org.cybergarage.http.*; import org.cybergarage.http.*;
public class SSDPResponse extends HTTPResponse public class SSDPResponse extends HTTPResponse
@@ -37,6 +39,11 @@ public class SSDPResponse extends HTTPResponse
setVersion(HTTP.VERSION_11); setVersion(HTTP.VERSION_11);
} }
public SSDPResponse(InputStream in)
{
super(in);
}
//////////////////////////////////////////////// ////////////////////////////////////////////////
// ST (SearchTarget) // ST (SearchTarget)
//////////////////////////////////////////////// ////////////////////////////////////////////////
@@ -114,7 +121,7 @@ public class SSDPResponse extends HTTPResponse
public String getHeader() public String getHeader()
{ {
StringBuilder str = new StringBuilder(); StringBuffer str = new StringBuffer();
str.append(getStatusLineString()); str.append(getStatusLineString());
str.append(getHeaderString()); str.append(getHeaderString());

View File

@@ -12,11 +12,16 @@
* - first revision. * - first revision.
* 05/28/03 * 05/28/03
* - Added post() to send a SSDPSearchRequest. * - Added post() to send a SSDPSearchRequest.
* 01/31/08
* - Changed start() not to abort when the interface infomation is null on Android m3-rc37a.
* *
******************************************************************/ ******************************************************************/
package org.cybergarage.upnp.ssdp; package org.cybergarage.upnp.ssdp;
import java.net.DatagramSocket;
import java.net.InetAddress;
import org.cybergarage.upnp.*; import org.cybergarage.upnp.*;
public class SSDPSearchResponseSocket extends HTTPUSocket implements Runnable public class SSDPSearchResponseSocket extends HTTPUSocket implements Runnable
@@ -74,10 +79,17 @@ public class SSDPSearchResponseSocket extends HTTPUSocket implements Runnable
} }
} }
public void start() public void start() {
{
deviceSearchResponseThread = new Thread(this, "UPnP-SSDPSearchResponseSocket"); StringBuffer name = new StringBuffer("Cyber.SSDPSearchResponseSocket/");
deviceSearchResponseThread.setDaemon(true); DatagramSocket s = getDatagramSocket();
// localAddr is null on Android m3-rc37a (01/30/08)
InetAddress localAddr = s.getLocalAddress();
if (localAddr != null) {
name.append(s.getLocalAddress()).append(':');
name.append(s.getLocalPort());
}
deviceSearchResponseThread = new Thread(this,name.toString());
deviceSearchResponseThread.start(); deviceSearchResponseThread.start();
} }

View File

@@ -17,6 +17,7 @@
package org.cybergarage.upnp.ssdp; package org.cybergarage.upnp.ssdp;
import java.net.InetAddress;
import java.util.*; import java.util.*;
import org.cybergarage.net.*; import org.cybergarage.net.*;
@@ -29,11 +30,22 @@ public class SSDPSearchResponseSocketList extends Vector
// Constructor // Constructor
//////////////////////////////////////////////// ////////////////////////////////////////////////
private static final long serialVersionUID = 4509857798038125744L; private InetAddress[] binds = null;
public SSDPSearchResponseSocketList() public SSDPSearchResponseSocketList() {
{
} }
/**
*
* @param binds The host to bind.Use <tt>null</tt> for the default behavior
*/
public SSDPSearchResponseSocketList(InetAddress[] binds) {
this.binds = binds;
}
////////////////////////////////////////////////
// ControlPoint
//////////////////////////////////////////////// ////////////////////////////////////////////////
// ControlPoint // ControlPoint
@@ -61,17 +73,27 @@ public class SSDPSearchResponseSocketList extends Vector
// Methods // Methods
//////////////////////////////////////////////// ////////////////////////////////////////////////
public boolean open(int port) public boolean open(int port){
{ InetAddress[] binds=this.binds ;
try { String[] bindAddresses;
if(binds!=null){
bindAddresses = new String[binds.length];
for (int i = 0; i < binds.length; i++) {
bindAddresses[i] = binds[i].getHostAddress();
}
}else{
int nHostAddrs = HostInterface.getNHostAddresses(); int nHostAddrs = HostInterface.getNHostAddresses();
bindAddresses = new String[nHostAddrs];
for (int n=0; n<nHostAddrs; n++) { for (int n=0; n<nHostAddrs; n++) {
String bindAddr = HostInterface.getHostAddress(n); bindAddresses[n] = HostInterface.getHostAddress(n);
SSDPSearchResponseSocket socket = new SSDPSearchResponseSocket(bindAddr, port); }
}
try {
for (int j = 0; j < bindAddresses.length; j++) {
SSDPSearchResponseSocket socket = new SSDPSearchResponseSocket(bindAddresses[j], port);
add(socket); add(socket);
} }
} }catch (Exception e) {
catch (Exception e) {
stop(); stop();
close(); close();
clear(); clear();

View File

@@ -18,11 +18,21 @@
* - Mikael Hakman <mhakman@dkab.net> * - Mikael Hakman <mhakman@dkab.net>
* - Added close() in stop(). * - Added close() in stop().
* - Added test for null return from receive() in run(). * - Added test for null return from receive() in run().
* 08/23/07
* - Thanks for Kazuyuki Shudo
* - Changed run() to catch IOException of HTTPMUSocket::receive().
* 01/10/08
* - Changed start() not to abort when the interface infomation is null on Android m3-rc37a.
* *
******************************************************************/ ******************************************************************/
package org.cybergarage.upnp.ssdp; package org.cybergarage.upnp.ssdp;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.io.IOException;
import org.cybergarage.net.*; import org.cybergarage.net.*;
import org.cybergarage.util.*; import org.cybergarage.util.*;
@@ -30,24 +40,74 @@ import org.cybergarage.upnp.device.*;
public class SSDPSearchSocket extends HTTPMUSocket implements Runnable public class SSDPSearchSocket extends HTTPMUSocket implements Runnable
{ {
public SSDPSearchSocket() private boolean useIPv6Address;
{
}
public SSDPSearchSocket(String bindAddr)
{
open(bindAddr);
}
//////////////////////////////////////////////// ////////////////////////////////////////////////
// Constructor // Constructor
//////////////////////////////////////////////// ////////////////////////////////////////////////
/**
*
* @param bindAddr The address to bind the service
* @param port The port used for accepting message
* @param multicast The multicast address to use as destination
* @since 1.8
*/
public SSDPSearchSocket(String bindAddr,int port,String multicast){
open(bindAddr,multicast);
}
/**
*
* @param bindAddr the binding address for senging multicast packet
* @since 1.8
*/
public SSDPSearchSocket(InetAddress bindAddr){
if(bindAddr.getAddress().length!=4){
this.open((Inet6Address)bindAddr);
}else{
this.open((Inet4Address)bindAddr);
}
}
////////////////////////////////////////////////
// Constructor
////////////////////////////////////////////////
public boolean open(Inet4Address bindAddr){
useIPv6Address = false;
return open(SSDP.ADDRESS, SSDP.PORT, bindAddr);
}
public boolean open(Inet6Address bindAddr){
useIPv6Address = true;
return open(SSDP.getIPv6Address(), SSDP.PORT, bindAddr);
}
public boolean open(String bind,String multicast){
if ((HostInterface.isIPv6Address(bind) ) && (HostInterface.isIPv6Address(multicast))){
useIPv6Address = true;
}else if(HostInterface.isIPv4Address(bind) && (HostInterface.isIPv4Address(multicast))){
useIPv6Address = false;
}else{
throw new IllegalArgumentException("Cannot open a UDP Socket for IPv6 address on IPv4 interface or viceversa");
}
return open(multicast, SSDP.PORT, bind);
}
/**
*
* @param bindAddr the hostname of the interface to use for senfing multicast packet
* @return true if and only if it open the socket
* @see {@link SSDP} for default multicast and port destination of the packtes
*/
public boolean open(String bindAddr) public boolean open(String bindAddr)
{ {
String addr = SSDP.ADDRESS; String addr = SSDP.ADDRESS;
useIPv6Address = false;
if (HostInterface.isIPv6Address(bindAddr) == true) { if (HostInterface.isIPv6Address(bindAddr) == true) {
addr = SSDP.getIPv6Address(); addr = SSDP.getIPv6Address();
useIPv6Address = true;
} }
return open(addr, SSDP.PORT, bindAddr); return open(addr, SSDP.PORT, bindAddr);
} }
@@ -89,21 +149,37 @@ public class SSDPSearchSocket extends HTTPMUSocket implements Runnable
while (deviceSearchThread == thisThread) { while (deviceSearchThread == thisThread) {
Thread.yield(); Thread.yield();
SSDPPacket packet = receive();
// Thanks for Kazuyuki Shudo (08/23/07)
SSDPPacket packet = null;
try {
packet = receive();
}
catch (IOException e) {
break;
}
// Thanks for Mikael Hakman (04/20/05) // Thanks for Mikael Hakman (04/20/05)
if (packet == null) if (packet == null)
continue; continue;
//TODO perform delegation with Thread Pooling
if (packet.isDiscover() == true) if (packet.isDiscover() == true)
performSearchListener(packet); performSearchListener(packet);
} }
} }
public void start() public void start() {
{ StringBuffer name = new StringBuffer("Cyber.SSDPSearchSocket/");
deviceSearchThread = new Thread(this,"UPnP-SSDPSearchSocket"); String localAddr = this.getLocalAddress();
deviceSearchThread.setDaemon(true); // localAddr is null on Android m3-rc37a (01/30/08)
if (localAddr != null && 0 < localAddr.length()) {
name.append(this.getLocalAddress()).append(':');
name.append(this.getLocalPort()).append(" -> ");
name.append(this.getMulticastAddress()).append(':');
name.append(this.getMulticastPort());
}
deviceSearchThread = new Thread(this,name.toString());
deviceSearchThread.start(); deviceSearchThread.start();
} }

View File

@@ -18,11 +18,11 @@
package org.cybergarage.upnp.ssdp; package org.cybergarage.upnp.ssdp;
import java.util.*; import java.net.InetAddress;
import java.util.Vector;
import org.cybergarage.net.*; import org.cybergarage.net.HostInterface;
import org.cybergarage.upnp.device.SearchListener;
import org.cybergarage.upnp.device.*;
public class SSDPSearchSocketList extends Vector public class SSDPSearchSocketList extends Vector
{ {
@@ -30,11 +30,39 @@ public class SSDPSearchSocketList extends Vector
// Constructor // Constructor
//////////////////////////////////////////////// ////////////////////////////////////////////////
private static final long serialVersionUID = 4071292828166415028L; private InetAddress[] binds = null;
private String multicastIPv4 = SSDP.ADDRESS;
private String multicastIPv6 = SSDP.getIPv6Address();
private int port = SSDP.PORT;
public SSDPSearchSocketList() public SSDPSearchSocketList()
{ {
} }
/**
*
* @param binds The IP address that we will used for bindind the service
*/
public SSDPSearchSocketList(InetAddress[] binds) {
this.binds = binds;
}
/**
*
* @param binds The IP address that we will used for bindind the service
* @param port The port that we will used for bindind the service
* @param multicastIPv4 The IPv4 address that we will used for multicast comunication
* @param multicastIPv6 The IPv6 address that we will used for multicast comunication
* @since 1.8
*/
public SSDPSearchSocketList(InetAddress[] binds,int port, String multicastIPv4, String multicastIPv6) {
this.binds = binds;
this.port = port;
this.multicastIPv4 = multicastIPv4;
this.multicastIPv6 = multicastIPv6;
}
//////////////////////////////////////////////// ////////////////////////////////////////////////
// Methods // Methods
@@ -58,14 +86,32 @@ public class SSDPSearchSocketList extends Vector
// Methods // Methods
//////////////////////////////////////////////// ////////////////////////////////////////////////
public boolean open() public boolean open() {
{ InetAddress[] binds=this.binds;
String[] bindAddresses;
if(binds!=null){
bindAddresses = new String[binds.length];
for (int i = 0; i < binds.length; i++) {
bindAddresses[i] = binds[i].getHostAddress();
}
}else{
int nHostAddrs = HostInterface.getNHostAddresses(); int nHostAddrs = HostInterface.getNHostAddresses();
bindAddresses = new String[nHostAddrs];
for (int n=0; n<nHostAddrs; n++) { for (int n=0; n<nHostAddrs; n++) {
String bindAddr = HostInterface.getHostAddress(n); bindAddresses[n] = HostInterface.getHostAddress(n);
SSDPSearchSocket ssdpSearchSocket = new SSDPSearchSocket(bindAddr); }
}
for (int i = 0; i < bindAddresses.length; i++) {
if(bindAddresses[i]!=null){
SSDPSearchSocket ssdpSearchSocket;
if(HostInterface.isIPv6Address(bindAddresses[i]))
ssdpSearchSocket = new SSDPSearchSocket(bindAddresses[i],port ,multicastIPv6 );
else
ssdpSearchSocket = new SSDPSearchSocket(bindAddresses[i],port,multicastIPv4 );
add(ssdpSearchSocket); add(ssdpSearchSocket);
} }
}
return true; return true;
} }

View File

@@ -18,6 +18,7 @@
package org.cybergarage.upnp.xml; package org.cybergarage.upnp.xml;
import java.io.*; import java.io.*;
import java.net.InetAddress;
import org.cybergarage.util.*; import org.cybergarage.util.*;
import org.cybergarage.http.*; import org.cybergarage.http.*;
@@ -89,10 +90,23 @@ public class DeviceData extends NodeData
// HTTPServer // HTTPServer
//////////////////////////////////////////////// ////////////////////////////////////////////////
private HTTPServerList httpServerList = new HTTPServerList(); private HTTPServerList httpServerList = null;
public HTTPServerList getHTTPServerList() { public HTTPServerList getHTTPServerList() {
return httpServerList; if(this.httpServerList==null){
this.httpServerList = new HTTPServerList(this.httpBinds,this.httpPort);
}
return this.httpServerList;
}
private InetAddress[] httpBinds = null;
public void setHTTPBindAddress(InetAddress[] inets){
this.httpBinds=inets;
}
public InetAddress[] getHTTPBindAddress(){
return this.httpBinds;
} }
//////////////////////////////////////////////// ////////////////////////////////////////////////
@@ -129,12 +143,99 @@ public class DeviceData extends NodeData
// SSDPSearchSocket // SSDPSearchSocket
//////////////////////////////////////////////// ////////////////////////////////////////////////
private SSDPSearchSocketList ssdpSearchSocketList = new SSDPSearchSocketList(); private SSDPSearchSocketList ssdpSearchSocketList = null;
private String ssdpMulticastIPv4 = SSDP.ADDRESS;
private String ssdpMulticastIPv6 = SSDP.getIPv6Address();
private int ssdpPort = SSDP.PORT;
private InetAddress[] ssdpBinds = null;
public SSDPSearchSocketList getSSDPSearchSocketList() { public SSDPSearchSocketList getSSDPSearchSocketList() {
if(this.ssdpSearchSocketList==null){
this.ssdpSearchSocketList = new SSDPSearchSocketList(this.ssdpBinds,ssdpPort,ssdpMulticastIPv4,ssdpMulticastIPv6);
}
return ssdpSearchSocketList; return ssdpSearchSocketList;
} }
/**
*
* @param port The port to use for binding the SSDP service.
* The port will be used as source port for all SSDP messages
* @since 1.8
*/
public void setSSDPPort(int port){
this.ssdpPort=port;
}
/**
*
* @return The port used for binding the SSDP service.
* The port will be used as source port for all SSDP messages
*/
public int getSSDPPort(){
return this.ssdpPort;
}
/**
*
* @param inets The <tt>InetAddress</tt> that will be binded for listing this service.
* Use <code>null</code> for the default behaviur.
* @see {@link UPnP}
* @see {@link USSDP}
* @see {@link HostInterface}
* @since 1.8
*/
public void setSSDPBindAddress(InetAddress[] inets){
this.ssdpBinds=inets;
}
/**
*
* @return inets The <tt>InetAddress</tt> that will be binded for this service
* <code>null</code> means that defulat behaviur will be used
* @since 1.8
*/
public InetAddress[] getSSDPBindAddress(){
return this.ssdpBinds;
}
/**
*
* @param ip The IPv4 address used as destination address for Multicast comunication
* @since 1.8
*/
public void setMulticastIPv4Address(String ip){
this.ssdpMulticastIPv4=ip;
}
/**
*
* @return The IPv4 address used for Multicast comunication
*/
public String getMulticastIPv4Address(){
return this.ssdpMulticastIPv4;
}
/**
*
* @param ip The IPv6 address used as destination address for Multicast comunication
* @since 1.8
*/
public void setMulticastIPv6Address(String ip){
this.ssdpMulticastIPv6=ip;
}
/**
*
* @return The IPv6 address used as destination address for Multicast comunication
* @since 1.8
*/
public String getMulticastIPv6Address(){
return this.ssdpMulticastIPv6;
}
//////////////////////////////////////////////// ////////////////////////////////////////////////
// SSDPPacket // SSDPPacket
//////////////////////////////////////////////// ////////////////////////////////////////////////

View File

@@ -68,6 +68,20 @@ public class ServiceData extends NodeData
// SID // SID
//////////////////////////////////////////////// ////////////////////////////////////////////////
private String descriptionURL = "";
public String getDescriptionURL() {
return descriptionURL;
}
public void setDescriptionURL(String descriptionURL) {
this.descriptionURL = descriptionURL;
}
////////////////////////////////////////////////
// SID
////////////////////////////////////////////////
private String sid = ""; private String sid = "";
public String getSID() { public String getSID() {

View File

@@ -15,10 +15,33 @@
package org.cybergarage.util; package org.cybergarage.util;
public final class Debug import java.io.PrintStream;
{
public final class Debug{
public static Debug debug = new Debug();
private PrintStream out = System.out;
public Debug(){
}
public synchronized PrintStream getOut() {
return out;
}
public synchronized void setOut(PrintStream out) {
this.out = out;
}
public static boolean enabled = false; public static boolean enabled = false;
public static Debug getDebug(){
return Debug.debug;
}
public static final void on() { public static final void on() {
enabled = true; enabled = true;
} }
@@ -30,22 +53,29 @@ public final class Debug
} }
public static final void message(String s) { public static final void message(String s) {
if (enabled == true) if (enabled == true)
System.out.println("CyberGarage message : " + s); Debug.debug.getOut().println("CyberGarage message : " + s);
} }
public static final void message(String m1, String m2) { public static final void message(String m1, String m2) {
if (enabled == true) if (enabled == true)
System.out.println("CyberGarage message : "); Debug.debug.getOut().println("CyberGarage message : ");
System.out.println(m1); Debug.debug.getOut().println(m1);
System.out.println(m2); Debug.debug.getOut().println(m2);
} }
public static final void warning(String s) { public static final void warning(String s) {
System.out.println("CyberGarage warning : " + s); Debug.debug.getOut().println("CyberGarage warning : " + s);
} }
public static final void warning(String m, Exception e) { public static final void warning(String m, Exception e) {
System.out.println("CyberGarage warning : " + m + " (" + e.getMessage() + ")"); if(e.getMessage()==null){
Debug.debug.getOut().println("CyberGarage warning : " + m + " START");
e.printStackTrace(Debug.debug.getOut());
Debug.debug.getOut().println("CyberGarage warning : " + m + " END");
}else{
Debug.debug.getOut().println("CyberGarage warning : " + m + " (" + e.getMessage() + ")");
e.printStackTrace(Debug.debug.getOut());
}
} }
public static final void warning(Exception e) { public static final void warning(Exception e) {
warning(e.getMessage()); warning(e.getMessage());
e.printStackTrace(); e.printStackTrace(Debug.debug.getOut());
} }
} }

View File

@@ -15,7 +15,9 @@
package org.cybergarage.util; package org.cybergarage.util;
import java.io.*; import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
public final class FileUtil public final class FileUtil
{ {

View File

@@ -15,12 +15,10 @@
package org.cybergarage.util; package org.cybergarage.util;
import java.util.*; import java.util.Vector;
public class ListenerList extends Vector public class ListenerList extends Vector
{ {
private static final long serialVersionUID = 8039231561720446173L;
public boolean add(Object obj) public boolean add(Object obj)
{ {
if (0 <= indexOf(obj)) if (0 <= indexOf(obj))

View File

@@ -10,6 +10,9 @@
* *
* 01/05/04 * 01/05/04
* - first revision. * - first revision.
* 08/23/07
* - Thanks for Kazuyuki Shudo
* - Changed stop() to stop more safety using Thread::interrupt().
* *
******************************************************************/ ******************************************************************/
@@ -43,7 +46,7 @@ public class ThreadCore implements Runnable
{ {
java.lang.Thread threadObject = getThreadObject(); java.lang.Thread threadObject = getThreadObject();
if (threadObject == null) { if (threadObject == null) {
threadObject = new java.lang.Thread(this); threadObject = new java.lang.Thread(this,"Cyber.ThreadCore");
setThreadObject(threadObject); setThreadObject(threadObject);
threadObject.start(); threadObject.start();
} }
@@ -64,6 +67,10 @@ public class ThreadCore implements Runnable
if (threadObject != null) { if (threadObject != null) {
//threadObject.destroy(); //threadObject.destroy();
//threadObject.stop(); //threadObject.stop();
// Thanks for Kazuyuki Shudo (08/23/07)
threadObject.interrupt();
setThreadObject(null); setThreadObject(null);
} }
} }

View File

@@ -15,12 +15,10 @@
package org.cybergarage.xml; package org.cybergarage.xml;
import java.util.*; import java.util.Vector;
public class AttributeList extends Vector public class AttributeList extends Vector
{ {
private static final long serialVersionUID = -5516389508555401104L;
public AttributeList() public AttributeList()
{ {
} }

View File

@@ -22,6 +22,10 @@
* 12/02/04 * 12/02/04
* - Brian Owens <brian@b-owens.com> * - Brian Owens <brian@b-owens.com>
* - Fixed toXMLString() to convert from "'" to "&apos;" instead of "\". * - Fixed toXMLString() to convert from "'" to "&apos;" instead of "\".
* 11/07/05
* - Changed toString() to return as utf-8 string.
* 02/08/08
* - Added addValue().
* *
******************************************************************/ ******************************************************************/
@@ -29,10 +33,16 @@ package org.cybergarage.xml;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.util.Iterator;
public class Node public class Node
{ {
/**
* Create a Node with empty UserData and no Parent Node
*
*/
public Node() public Node()
{ {
setUserData(null); setUserData(null);
@@ -112,7 +122,7 @@ public class Node
// value // value
//////////////////////////////////////////////// ////////////////////////////////////////////////
private String value = ""; private String value = new String();
public void setValue(String value) public void setValue(String value)
{ {
@@ -124,6 +134,16 @@ public class Node
setValue(Integer.toString(value)); setValue(Integer.toString(value));
} }
public void addValue(String value)
{
if (this.value == null) {
this.value = value;
return;
}
if (value != null)
this.value += value;
}
public String getValue() public String getValue()
{ {
return value; return value;
@@ -253,6 +273,17 @@ public class Node
nodeList.insertElementAt(node, index); nodeList.insertElementAt(node, index);
} }
public int getIndex(String name){
int index = -1;
for (Iterator i = nodeList.iterator(); i.hasNext();) {
index++;
Node n = (Node) i.next();
if(n.getName().equals(name))
return index;
}
return index;
}
public boolean removeNode(Node node) { public boolean removeNode(Node node) {
node.setParentNode(null); node.setParentNode(null);
return nodeList.remove(node); return nodeList.remove(node);
@@ -312,17 +343,34 @@ public class Node
return userData; return userData;
} }
//////////////////////////////////////////////// ////////////////////////////////////////////////
// toString // toString
//////////////////////////////////////////////// ////////////////////////////////////////////////
/**
* Inovoke {@link #getIndentLevelString(int, String)} with <code>" "</code> as String
*
* @see #getIndentLevelString(int, String)
*/
public String getIndentLevelString(int nIndentLevel) public String getIndentLevelString(int nIndentLevel)
{ {
char indentString[] = new char[nIndentLevel]; return getIndentLevelString(nIndentLevel," ");
for (int n=0; n<nIndentLevel; n++) }
indentString[n] = '\t' ;
return new String(indentString); /**
*
* @param nIndentLevel the level of indentation to produce
* @param space the String to use for the intendation
* @since 1.8.0
* @return an indentation String
*/
public String getIndentLevelString(int nIndentLevel,String space)
{
StringBuffer indentString = new StringBuffer(nIndentLevel*space.length());
for (int n=0; n<nIndentLevel; n++){
indentString.append(space);
}
return indentString.toString();
} }
public void outputAttributes(PrintWriter ps) public void outputAttributes(PrintWriter ps)
@@ -346,8 +394,8 @@ public class Node
outputAttributes(ps); outputAttributes(ps);
// Thnaks for Tho Beisch (11/09/04) // Thnaks for Tho Beisch (11/09/04)
if (value == null || value.length() == 0) { if (value == null || value.length() == 0) {
// No value, so use short notation <node /> // Not using the short notation <node /> because it cause compatibility trouble
ps.println(" />"); ps.println("></" + name + ">");
} else { } else {
ps.println(">" + XML.escapeXMLChars(value) + "</" + name + ">"); ps.println(">" + XML.escapeXMLChars(value) + "</" + name + ">");
} }
@@ -368,19 +416,24 @@ public class Node
ps.println(indentString +"</" + name + ">"); ps.println(indentString +"</" + name + ">");
} }
public String toString(boolean hasChildNode) public String toString(String enc, boolean hasChildNode)
{ {
ByteArrayOutputStream byteOut = new ByteArrayOutputStream(); ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
PrintWriter pr = new PrintWriter(byteOut); PrintWriter pr = new PrintWriter(byteOut);
output(pr, 0, hasChildNode); output(pr, 0, hasChildNode);
pr.flush(); pr.flush();
try {
if (enc != null && 0 < enc.length())
return byteOut.toString(enc);
}
catch (UnsupportedEncodingException e) {
}
return byteOut.toString(); return byteOut.toString();
} }
@Override
public String toString() public String toString()
{ {
return toString(true); return toString(XML.CHARSET_UTF8, true);
} }
public String toXMLString(boolean hasChildNode) public String toXMLString(boolean hasChildNode)

View File

@@ -15,12 +15,10 @@
package org.cybergarage.xml; package org.cybergarage.xml;
import java.util.*; import java.util.Vector;
public class NodeList extends Vector public class NodeList extends Vector
{ {
private static final long serialVersionUID = 1528884682346143213L;
public NodeList() public NodeList()
{ {
} }

View File

@@ -8,17 +8,27 @@
* *
* Revision; * Revision;
* *
* 11/26/03 * 11/26/2003
* - first revision. * - first revision.
* 03/30/05 * 03/30/2005
* - Change parse(String) to use StringBufferInputStream instead of URL. * - Change parse(String) to use StringBufferInputStream instead of URL.
* 11/11/2009
* - Changed Parser::parser() to use ByteArrayInputStream instead of StringBufferInputStream because of bugs in Android v1.6.
* *
******************************************************************/ ******************************************************************/
package org.cybergarage.xml; package org.cybergarage.xml;
import java.net.*; import java.io.File;
import java.io.*; import java.io.FileInputStream;
import java.io.InputStream;
import java.io.ByteArrayInputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import org.cybergarage.http.HTTP;
import org.cybergarage.http.HTTPRequest;
import org.cybergarage.http.HTTPResponse;
public abstract class Parser public abstract class Parser
{ {
@@ -42,9 +52,20 @@ public abstract class Parser
public Node parse(URL locationURL) throws ParserException public Node parse(URL locationURL) throws ParserException
{ {
String host = locationURL.getHost();
int port = locationURL.getPort();
// Thanks for Hao Hu
if (port == -1)
port = 80;
String uri = locationURL.getPath();
try { try {
HttpURLConnection urlCon = (HttpURLConnection)locationURL.openConnection(); HttpURLConnection urlCon = (HttpURLConnection)locationURL.openConnection();
urlCon.setRequestMethod("GET"); urlCon.setRequestMethod("GET");
urlCon.setRequestProperty(HTTP.CONTENT_LENGTH,"0");
if (host != null)
urlCon.setRequestProperty(HTTP.HOST, host);
InputStream urlIn = urlCon.getInputStream(); InputStream urlIn = urlCon.getInputStream();
Node rootElem = parse(urlIn); Node rootElem = parse(urlIn);
@@ -55,22 +76,19 @@ public abstract class Parser
return rootElem; return rootElem;
} catch (Exception e) { } catch (Exception e) {
throw new ParserException(e); //throw new ParserException(e);
} }
/*
String host = locationURL.getHost();
int port = locationURL.getPort();
String uri = locationURL.getPath();
HTTPRequest httpReq = new HTTPRequest(); HTTPRequest httpReq = new HTTPRequest();
httpReq.setMethod(HTTP.GET); httpReq.setMethod(HTTP.GET);
httpReq.setURI(uri); httpReq.setURI(uri);
HTTPResponse httpRes = httpReq.post(host, port); HTTPResponse httpRes = httpReq.post(host, port);
if (httpRes.isSuccessful() == false) if (httpRes.isSuccessful() == false)
throw new ParserException(locationURL.toString()); throw new ParserException("HTTP comunication failed: no answer from peer." +
"Unable to retrive resoure -> "+locationURL.toString());
String content = new String(httpRes.getContent()); String content = new String(httpRes.getContent());
StringBufferInputStream strBuf = new StringBufferInputStream(content); ByteArrayInputStream strBuf = new ByteArrayInputStream(content.getBytes());
return parse(strBuf); return parse(strBuf);
*/
} }
//////////////////////////////////////////////// ////////////////////////////////////////////////
@@ -97,7 +115,7 @@ public abstract class Parser
public Node parse(String descr) throws ParserException public Node parse(String descr) throws ParserException
{ {
try { try {
StringBufferInputStream decrIn = new StringBufferInputStream(descr); InputStream decrIn = new ByteArrayInputStream(descr.getBytes());
Node root = parse(decrIn); Node root = parse(decrIn);
return root; return root;
} catch (Exception e) { } catch (Exception e) {

View File

@@ -19,8 +19,6 @@ package org.cybergarage.xml;
public class ParserException extends Exception public class ParserException extends Exception
{ {
private static final long serialVersionUID = 7443033796560597360L;
public ParserException(Exception e) public ParserException(Exception e)
{ {
super(e); super(e);

View File

@@ -21,6 +21,7 @@ package org.cybergarage.xml;
public class XML public class XML
{ {
public final static String CONTENT_TYPE = "text/xml; charset=\"utf-8\""; public final static String CONTENT_TYPE = "text/xml; charset=\"utf-8\"";
public final static String CHARSET_UTF8 = "utf-8";
//////////////////////////////////////////////// ////////////////////////////////////////////////
// escapeXMLChars // escapeXMLChars
@@ -28,9 +29,9 @@ public class XML
private final static String escapeXMLChars(String input, boolean quote) private final static String escapeXMLChars(String input, boolean quote)
{ {
StringBuilder out = new StringBuilder();
if (input == null) if (input == null)
return null; return null;
StringBuffer out = new StringBuffer();
int oldsize=input.length(); int oldsize=input.length();
char[] old=new char[oldsize]; char[] old=new char[oldsize];
input.getChars(0,oldsize,old,0); input.getChars(0,oldsize,old,0);
@@ -61,5 +62,25 @@ public class XML
{ {
return escapeXMLChars(input, true); return escapeXMLChars(input, true);
} }
////////////////////////////////////////////////
// unescapeXMLChars
////////////////////////////////////////////////
public final static String unescapeXMLChars(String input)
{
if (input == null)
return null;
String outStr;
outStr = input.replace("&amp;", "&");
outStr = outStr.replace("&lt;", "<");
outStr = outStr.replace("&gt;", ">");
outStr = outStr.replace("&apos;", "\'");
outStr = outStr.replace("&quot;", "\"");
return outStr;
}
} }

View File

@@ -12,6 +12,10 @@
* *
* 06/15/04 * 06/15/04
* - first revision. * - first revision.
* 01/08/08
* - Fixed parse() not to occur null exception when the NamedNodeMap is null on Android.
* 02/08/08
* - Change parse() to use Node::addValue() instead of the setValue().
* *
******************************************************************/ ******************************************************************/
@@ -50,11 +54,15 @@ public class JaxpParser extends Parser
String domNodeName = domNode.getNodeName(); String domNodeName = domNode.getNodeName();
String domNodeValue = domNode.getNodeValue(); String domNodeValue = domNode.getNodeValue();
NamedNodeMap attrs = domNode.getAttributes();
int arrrsLen = (attrs != null) ? attrs.getLength() : 0;
// Debug.message("[" + rank + "] ELEM : " + domNodeName + ", " + domNodeValue + ", type = " + domNodeType + ", attrs = " + arrrsLen); // Debug.message("[" + rank + "] ELEM : " + domNodeName + ", " + domNodeValue + ", type = " + domNodeType + ", attrs = " + arrrsLen);
if (domNodeType == org.w3c.dom.Node.TEXT_NODE) { if (domNodeType == org.w3c.dom.Node.TEXT_NODE) {
parentNode.setValue(domNodeValue); // Change to use Node::addValue() instead of the setValue(). (2008/02/07)
//parentNode.setValue(domNodeValue);
parentNode.addValue(domNodeValue);
return parentNode; return parentNode;
} }
@@ -69,6 +77,7 @@ public class JaxpParser extends Parser
parentNode.addNode(node); parentNode.addNode(node);
NamedNodeMap attrMap = domNode.getAttributes(); NamedNodeMap attrMap = domNode.getAttributes();
if (attrMap != null) {
int attrLen = attrMap.getLength(); int attrLen = attrMap.getLength();
//Debug.message("attrLen = " + attrLen); //Debug.message("attrLen = " + attrLen);
for (int n = 0; n<attrLen; n++) { for (int n = 0; n<attrLen; n++) {
@@ -77,12 +86,17 @@ public class JaxpParser extends Parser
String attrValue = attr.getNodeValue(); String attrValue = attr.getNodeValue();
node.setAttribute(attrName, attrValue); node.setAttribute(attrName, attrValue);
} }
}
org.w3c.dom.Node child = domNode.getFirstChild(); org.w3c.dom.Node child = domNode.getFirstChild();
while (child != null) { if(child==null){
node.setValue("");
return node;
}
do{
parse(node, child, rank+1); parse(node, child, rank+1);
child = child.getNextSibling(); child = child.getNextSibling();
} }while (child != null);
return node; return node;
} }