├── .gitignore ├── README.md ├── docs └── ssdp-protocol.txt ├── pom.xml ├── ssdp-core ├── pom.xml └── src │ ├── main │ └── java │ │ └── com │ │ └── jerabi │ │ └── ssdp │ │ ├── ISSDPControler.java │ │ ├── SSDPControler.java │ │ ├── handler │ │ ├── ISSDPMessageHandler.java │ │ ├── ISSDPResponseHandler.java │ │ ├── SSDPDefaultMessageHandler.java │ │ ├── SSDPDefaultResponseHandler.java │ │ └── SSDPDiscoverResponseHandler.java │ │ ├── listener │ │ └── SSDPMulticastListener.java │ │ ├── message │ │ ├── AbstractSSDPNotifyMessage.java │ │ ├── AliveMessage.java │ │ ├── ByeByeMessage.java │ │ ├── DiscoverMessage.java │ │ ├── DiscoverResponseMessage.java │ │ ├── ISSDPMessage.java │ │ ├── ServiceInfo.java │ │ ├── USNInfo.java │ │ ├── UpdateMessage.java │ │ └── helper │ │ │ └── SSDPMessageHelper.java │ │ ├── network │ │ ├── IMulticastListener.java │ │ ├── ISSDPNetwork.java │ │ ├── IUDPSender.java │ │ └── SSDPNetworkFactory.java │ │ ├── sender │ │ ├── AliveMessageSender.java │ │ ├── SSDPDefaultPeriodicMessageSender.java │ │ ├── SSDPDiscoverSender.java │ │ └── SSDPPeriodicMessageSender.java │ │ └── util │ │ ├── IStateListener.java │ │ ├── SSDPContants.java │ │ ├── State.java │ │ ├── StateHolder.java │ │ └── UUIDGenerator.java │ └── test │ └── java │ └── com │ └── jerabi │ └── ssdp │ ├── handler │ ├── SSDPDefaultHandlerTest.java │ └── SSDPDiscoverResponseHandlerTest.java │ ├── listener │ └── SSDPDefaultMessageListenerTest.java │ ├── message │ ├── ServiceInfoTest.java │ ├── USNInfoTest.java │ └── helper │ │ └── SSDPMessageHelperTest.java │ └── util │ ├── StateHolderTest.java │ └── UUIDGeneratorTest.java ├── ssdp-demo ├── pom.xml └── src │ └── main │ └── java │ └── com │ └── jerabi │ └── ssdp │ └── demo │ ├── Multihome.java │ ├── SSDPClient.java │ ├── SSDPMulticastSniffer.java │ └── SSDPServer.java └── ssdp-network ├── default-impl ├── pom.xml └── src │ ├── main │ └── java │ │ └── com │ │ └── jerabi │ │ └── ssdp │ │ └── network │ │ └── impl │ │ ├── MulticastListener.java │ │ ├── SSDPNetworkImpl.java │ │ └── UDPSender.java │ └── test │ └── java │ └── com │ └── jerabi │ └── ssdp │ ├── SSDPControlerTest.java │ ├── listener │ └── SSDPMulticastListenerTest.java │ ├── network │ └── impl │ │ ├── SSDPNetworkTest.java │ │ ├── UDPSenderTest.java │ │ └── UDPServer.java │ └── sender │ ├── SSDPDiscoverSenderTest.java │ └── SSDPPeriodicMessageSenderTest.java ├── dummy-impl ├── pom.xml └── src │ └── main │ └── java │ └── com │ └── jerabi │ └── ssdp │ └── network │ └── impl │ └── SSDPNetwork.java └── pom.xml /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | *~ 3 | .buildpath 4 | .project 5 | .settings 6 | .classpath 7 | .metadata 8 | .DS_Store 9 | target 10 | test-output 11 | # Package Files # 12 | *.jar 13 | *.war 14 | *.ear 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | jerabi-ssdp 2 | =========== 3 | 4 | Simple Service Discovery Protocol (SSDP) implementation -------------------------------------------------------------------------------- /docs/ssdp-protocol.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jerabi/jerabi-ssdp/30e89a68451173f490a1b138751ab81608497b3c/docs/ssdp-protocol.txt -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 4.0.0 5 | com.jerabi 6 | ssdp 7 | pom 8 | ssdp 9 | 0.0.1-SNAPSHOT 10 | ssdp project 11 | http://kenai.com/projects/dlna-mediasuite 12 | 13 | jira 14 | http://kenai.com/jira/browse/DLNA_MEDIASUITE 15 | 16 | 17 | 18 | survivant 19 | Sebastien Dionne 20 | survivant00@gmail.com 21 | http://www.java.net/blogs/survivant/ 22 | Jerabi 23 | http://sebastiendionne.ca 24 | 25 | 26 | 27 | scm:hg:ssh://survivant00@hg.kenai.com/dlna-mediasuite~dnla-mediasuite 28 | scm:hg:ssh://survivant00@hg.kenai.com/dlna-mediasuite~dnla-mediasuite 29 | https://hg.kenai.com/hg/dlna-mediasuite~dnla-mediasuite 30 | 31 | 32 | install 33 | 34 | 35 | org.apache.maven.plugins 36 | maven-javadoc-plugin 37 | 2.6.1 38 | 39 | 40 | http://java.sun.com/javase/6/docs/api/ 41 | 42 | 43 | 44 | 45 | example. 46 | aoptcmf 47 | Example : 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | junit 58 | junit 59 | 4.7 60 | 61 | 62 | 63 | 64 | 65 | 66 | org.apache.maven.plugins 67 | maven-surefire-report-plugin 68 | 69 | 70 | 71 | org.apache.maven.plugins 72 | maven-pmd-plugin 73 | 74 | true 75 | ISO-8859-1 76 | 30 77 | 1.6 78 | true 79 | 80 | 81 | 82 | org.apache.maven.plugins 83 | maven-javadoc-plugin 84 | 2.6.1 85 | 86 | 87 | non-aggregate 88 | 89 | 90 | http://java.sun.com/javase/6/docs/api/ 91 | 92 | 93 | 94 | 95 | example. 96 | aoptcmf 97 | Example : 98 | 99 | 100 | gr.spinellis.umlgraph.doclet.UmlGraphDoc 101 | 102 | gr.spinellis 103 | UmlGraph 104 | 4.6 105 | 106 | -operations 107 | -qualify 108 | -types 109 | -visibility 110 | -collpackages 111 | 112 | -inferrel -inferdep -quiet -hide java.* 113 | -collpackages java.util.* -qualify 114 | -postfixpackage -nodefontsize 9 115 | -nodefontpackagesize 7 116 | 117 | 118 | 119 | package 120 | javadoc:aggregate 121 | javadoc:test-aggregate 122 | 123 | 124 | javadoc 125 | 126 | 127 | 128 | aggregate 129 | 130 | 131 | http://java.sun.com/javase/6/docs/api/ 132 | 133 | 134 | 135 | 136 | example. 137 | aoptcmf 138 | Example : 139 | 140 | 141 | gr.spinellis.umlgraph.doclet.UmlGraphDoc 142 | 143 | gr.spinellis 144 | UmlGraph 145 | 4.6 146 | 147 | -operations 148 | -qualify 149 | -types 150 | -visibility 151 | -collpackages 152 | 153 | -inferrel -inferdep -quiet -hide java.* 154 | -collpackages java.util.* -qualify 155 | -postfixpackage -nodefontsize 9 156 | -nodefontpackagesize 7 157 | 158 | 159 | 160 | package 161 | javadoc:aggregate 162 | javadoc:test-aggregate 163 | 164 | 165 | aggregate 166 | 167 | 168 | 169 | 170 | 171 | org.apache.maven.plugins 172 | maven-jxr-plugin 173 | 174 | true 175 | 176 | 177 | 178 | com.atlassian.maven.plugins 179 | maven-clover2-plugin 180 | 2.6.3 181 | 182 | 1.6 183 | true 184 | true 185 | true 186 | 187 | ca/sebastiendionne/ssdp/demo/*.java 188 | 189 | 190 | 191 | 192 | 193 | org.codehaus.mojo 194 | findbugs-maven-plugin 195 | 2.1 196 | 197 | true 198 | true 199 | Max 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | ssdp-core 208 | ssdp-network 209 | ssdp-demo 210 | 211 | 212 | 213 | 214 | cloverX 215 | 216 | 217 | false 218 | 219 | coverage 220 | true 221 | 222 | 223 | 224 | 225 | 226 | 227 | com.atlassian.maven.plugins 228 | maven-clover2-plugin 229 | 2.6.3 230 | 231 | 1.6 232 | 233 | true 234 | true 235 | true 236 | 237 | ca/sebastiendionne/ssdp/demo/*.java 238 | 239 | 240 | 241 | 242 | true 243 | clover2 244 | 245 | setup 246 | 247 | 248 | 249 | true 250 | cloversite 251 | pre-site 252 | 253 | aggregate 254 | clover 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | UTF-8 266 | 267 | 268 | -------------------------------------------------------------------------------- /ssdp-core/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | com.jerabi 5 | ssdp 6 | 0.0.1-SNAPSHOT 7 | 8 | 4.0.0 9 | com.jerabi 10 | ssdp-core 11 | ssdp-core 12 | 0.0.1-SNAPSHOT 13 | ssdp-core 14 | 15 | 16 | 17 | 18 | org.apache.maven.plugins 19 | maven-compiler-plugin 20 | 21 | 1.6 22 | 1.6 23 | 24 | 25 | 26 | 27 | org.apache.maven.plugins 28 | maven-jar-plugin 29 | 30 | 31 | **/ca/sebastiendionne/ssdp/network/impl/SSDPNetwork.class 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /ssdp-core/src/main/java/com/jerabi/ssdp/ISSDPControler.java: -------------------------------------------------------------------------------- 1 | package com.jerabi.ssdp; 2 | 3 | import java.util.List; 4 | 5 | import com.jerabi.ssdp.handler.ISSDPMessageHandler; 6 | import com.jerabi.ssdp.listener.SSDPMulticastListener; 7 | import com.jerabi.ssdp.message.ServiceInfo; 8 | import com.jerabi.ssdp.message.ISSDPMessage; 9 | import com.jerabi.ssdp.sender.SSDPDiscoverSender; 10 | import com.jerabi.ssdp.sender.SSDPPeriodicMessageSender; 11 | 12 | /** 13 | * Provides API to send and handle SSDPMessage. 14 | * 15 | * This is the main Interface for a controler. Can be used to implements 16 | * a SSDP client and SSDP server. 17 | * 18 | * @author Sebastien Dionne 19 | * 20 | */ 21 | public interface ISSDPControler { 22 | 23 | /** 24 | * Adds a listener into the ISSDPMessageHandler List 25 | * @param handler Will handle the messages received 26 | * @throws Exception 27 | */ 28 | void addMessageHandler(ISSDPMessageHandler handler) throws Exception; 29 | 30 | /** 31 | * Removes a listener from the ISSDPMessageHandler List 32 | * @param handler Will handle the messages received 33 | * @throws Exception 34 | */ 35 | void removeMessageHandler(ISSDPMessageHandler handler) throws Exception; 36 | 37 | /** 38 | * Returns the list of ISSDPMessageHandler that will handle the messages received. 39 | * @return ISSDPMessageHandler list 40 | * @throws Exception 41 | */ 42 | List getMessageHandlerList() throws Exception; 43 | 44 | /** 45 | * Process the ISSDPMessage received. 46 | * 47 | * @param message ISSDPMessage received from the network 48 | * @throws Exception 49 | */ 50 | void processSSDPMessage(ISSDPMessage message) throws Exception; 51 | 52 | /** 53 | * Process the ISSDPMessage received. This method have informations about the sender (address and port) to send a 54 | * response if required. 55 | * 56 | * @param remoteAddr sender IP address 57 | * @param remotePort sender port 58 | * @param message ISSDPMessage received from the network 59 | * @throws Exception 60 | */ 61 | void processSSDPMessage(String remoteAddr, int remotePort, ISSDPMessage message) throws Exception; 62 | 63 | /** 64 | * Starts the controler and all the senders and listeners that are enabled. 65 | * @throws Exception 66 | */ 67 | void start() throws Exception; 68 | 69 | /** 70 | * Stops the controler and all the senders and listeners. 71 | * Once it's stopped, it can't not restarted. 72 | * @throws Exception 73 | */ 74 | void stop() throws Exception; 75 | 76 | /** 77 | * Returns a list of ServiceInfo 78 | * @return ServiceInfo list 79 | */ 80 | List getServiceInfoList(); 81 | 82 | /** 83 | * Sets the list of ServiceInfo 84 | * @param serviceList 85 | */ 86 | void setServiceInfoList(List serviceList); 87 | 88 | /** 89 | * Adds a ServiceInfo into the ServiceInfoList 90 | * @param serviceInfo new ServiceInfo to add 91 | */ 92 | void addServiceInfo(ServiceInfo serviceInfo); 93 | 94 | /** 95 | * Removes a ServiceInfo from the ServiceInfoList 96 | * @param serviceInfo new ServiceInfo to remove 97 | * @return if the operation is successful 98 | */ 99 | boolean removeServiceInfo(ServiceInfo serviceInfo); 100 | 101 | /** 102 | * Returns true if enabled 103 | * @return enabled or disabled 104 | */ 105 | boolean getPeriodicSenderEnabled(); 106 | 107 | /** 108 | * Enabled or Disabled the PeriodicSender 109 | * @param enabled or disabled 110 | */ 111 | void setPeriodicSenderEnabled(boolean enabled); 112 | 113 | /** 114 | * Returns the {@link SSDPPeriodicMessageSender} 115 | * @return SSDPPeriodicMessageSender 116 | */ 117 | SSDPPeriodicMessageSender getPeriodicMessageSender(); 118 | 119 | /** 120 | * Sets a {@link SSDPPeriodicMessageSender} 121 | * 122 | * @param periodicSender Sender that will send {@link com.jerabi.ssdp.message.AliveMessage} 123 | */ 124 | void setPeriodicMessageSender(SSDPPeriodicMessageSender periodicSender); 125 | 126 | /** 127 | * Returns true if enabled 128 | * @return enabled or disabled 129 | */ 130 | boolean getDiscoverSenderEnabled(); 131 | 132 | /** 133 | * Enabled or Disabled the DiscoverSender 134 | * @param enabled or disabled 135 | */ 136 | void setDiscoverSenderEnabled(boolean enabled); 137 | 138 | /** 139 | * Returns the {@link SSDPDiscoverSender} 140 | * @return SSDPDiscoverSender 141 | */ 142 | SSDPDiscoverSender getDiscoverSender(); 143 | 144 | /** 145 | * Sets a {@link SSDPDiscoverSender} 146 | * 147 | * @param discoverSender Sender that will send {@link com.jerabi.ssdp.message.DiscoverMessage} (M-SEARCH) 148 | */ 149 | void setDiscoverSender(SSDPDiscoverSender discoverSender); 150 | 151 | /** 152 | * Returns true if enabled 153 | * @return enabled or disabled 154 | */ 155 | boolean getMulticastListenerEnabled(); 156 | 157 | /** 158 | * Enabled or Disabled the MulticastListener 159 | * @param enabled or disabled 160 | */ 161 | void setMulticastListenerEnabled(boolean enabled); 162 | 163 | /** 164 | * Returns the {@link SSDPMulticastListener} 165 | * @return SSDPMulticastListener 166 | */ 167 | SSDPMulticastListener getMulticastListener(); 168 | 169 | /** 170 | * Sets a {@link SSDPDiscoverSender} 171 | * 172 | * @param listener that will listen and handle multicast messages received 173 | */ 174 | void setMulticastListener(SSDPMulticastListener listener); 175 | } 176 | -------------------------------------------------------------------------------- /ssdp-core/src/main/java/com/jerabi/ssdp/handler/ISSDPMessageHandler.java: -------------------------------------------------------------------------------- 1 | package com.jerabi.ssdp.handler; 2 | 3 | import com.jerabi.ssdp.message.AliveMessage; 4 | import com.jerabi.ssdp.message.ByeByeMessage; 5 | import com.jerabi.ssdp.message.DiscoverMessage; 6 | import com.jerabi.ssdp.message.DiscoverResponseMessage; 7 | import com.jerabi.ssdp.message.UpdateMessage; 8 | 9 | /** 10 | * Provides API to process {@link com.jerabi.ssdp.message.ISSDPMessage} received. 11 | * 12 | * @author Sebastien Dionne 13 | * @see com.jerabi.ssdp.message.AliveMessage 14 | * @see com.jerabi.ssdp.message.ByeByeMessage 15 | * @see com.jerabi.ssdp.message.DiscoverMessage 16 | * @see com.jerabi.ssdp.message.DiscoverResponseMessage 17 | * @see com.jerabi.ssdp.message.UpdateMessage 18 | */ 19 | public interface ISSDPMessageHandler { 20 | 21 | /** 22 | * Process AliveMessage 23 | * 24 | * @param ssdpMessage message to process 25 | * @throws Exception 26 | */ 27 | void processSSDPAliveMessage(AliveMessage ssdpMessage) throws Exception; 28 | 29 | /** 30 | * Process UpdateMessage 31 | * 32 | * @param ssdpMessage message to process 33 | * @throws Exception 34 | */ 35 | void processSSDPUpdateMessage(UpdateMessage ssdpMessage) throws Exception; 36 | 37 | /** 38 | * Process ByeByeMessage 39 | * 40 | * @param ssdpMessage message to process 41 | * @throws Exception 42 | */ 43 | void processSSDPByeByeMessage(ByeByeMessage ssdpMessage) throws Exception; 44 | 45 | /** 46 | * Process DiscoverMessage (M-SEARCH) 47 | * 48 | * @param remoteAddr sender IP address 49 | * @param remotePort sender port 50 | * @param ssdpMessage message to process 51 | * @throws Exception 52 | */ 53 | void processSSDPDiscoverMessage(String remoteAddr, int remotePort, DiscoverMessage ssdpMessage) throws Exception; 54 | 55 | /** 56 | * Process DiscoverResponseMessage 57 | * 58 | * @param ssdpMessage message to process 59 | * @throws Exception 60 | */ 61 | void processSSDPDiscoverResponseMessage(DiscoverResponseMessage ssdpMessage) throws Exception; 62 | 63 | } 64 | -------------------------------------------------------------------------------- /ssdp-core/src/main/java/com/jerabi/ssdp/handler/ISSDPResponseHandler.java: -------------------------------------------------------------------------------- 1 | package com.jerabi.ssdp.handler; 2 | 3 | import com.jerabi.ssdp.ISSDPControler; 4 | 5 | /** 6 | * Provides a API to handle raw messages received. 7 | * 8 | * Normally the handle methods call {@link com.jerabi.ssdp.ISSDPControler} to process 9 | * the message and it call be used to filter the messages received. 10 | * 11 | * {@link com.jerabi.ssdp.handler.SSDPDiscoverResponseHandler} is a good 12 | * example of a ISSDPHandler that doesn't process DiscoverMessage (M-SEARCH) 13 | * 14 | * This class look like {@link ISSDPMessageHandler} but ISSDPMessageHandler actually process a {@link com.jerabi.ssdp.message.ISSDPMessage} 15 | * generated from the raw message received by this ISSDPHandler. 16 | * 17 | * @author Sebastien Dionne 18 | * @see ISSDPMessageHandler 19 | */ 20 | public interface ISSDPResponseHandler { 21 | 22 | /** 23 | * Sets the ISSDPControler 24 | * @param controler 25 | */ 26 | void setSSDPControler(ISSDPControler controler); 27 | 28 | /** 29 | * Returns the ISSDPControler 30 | * @return ISSDPControler 31 | */ 32 | ISSDPControler getSSDPControler(); 33 | 34 | /** 35 | * Handle the raw message received. If the message has to be process it should be sent to 36 | * the ISSDPControler. 37 | * 38 | * @param message raw message received from the network 39 | * @throws Exception 40 | */ 41 | void handle(String message) throws Exception; 42 | 43 | /** 44 | * Handle the raw message received. If the message has to be process it should be sent to 45 | * the ISSDPControler. This method have informations about the sender (address and port) to send a 46 | * response if required. 47 | * 48 | * @param remoteAddr sender IP address 49 | * @param remotePort sender port 50 | * @param message raw message received from the network 51 | * @throws Exception 52 | */ 53 | void handle(String remoteAddr, int remotePort, String message) throws Exception; 54 | } 55 | -------------------------------------------------------------------------------- /ssdp-core/src/main/java/com/jerabi/ssdp/handler/SSDPDefaultMessageHandler.java: -------------------------------------------------------------------------------- 1 | package com.jerabi.ssdp.handler; 2 | 3 | import java.util.logging.Logger; 4 | 5 | import com.jerabi.ssdp.message.AliveMessage; 6 | import com.jerabi.ssdp.message.ByeByeMessage; 7 | import com.jerabi.ssdp.message.DiscoverMessage; 8 | import com.jerabi.ssdp.message.DiscoverResponseMessage; 9 | import com.jerabi.ssdp.message.UpdateMessage; 10 | 11 | /** 12 | * 13 | * Provides a dummy implementation for processing a {@link com.jerabi.ssdp.message.ISSDPMessage} received. 14 | * 15 | * You need to implements the methods that you need. A reference implementation is UPNP API that used SSDP for 16 | * notification and discover devices/services. 17 | * 18 | * @example. 19 | *
20 |  * // You could implements ISSDPMessageHandler or override SSDPDefaultMessageHandler 
21 |  * 
22 |  * ISSDPMessageHandler listener = new SSDPDefaultMessageHandler(){
23 |  * 	@Override
24 |  *  public void processSSDPAliveMessage(AliveMessage ssdpMessage)
25 |  *			 throws Exception {
26 |  *		// log message here
27 |  *	}
28 |  * };
29 |  * 
30 | * @author Sebastien Dionne 31 | */ 32 | public class SSDPDefaultMessageHandler implements ISSDPMessageHandler { 33 | private static Logger logger = Logger.getLogger(SSDPDefaultMessageHandler.class.getName()); 34 | 35 | /** 36 | * {@inheritDoc} 37 | */ 38 | @Override 39 | public void processSSDPAliveMessage(AliveMessage ssdpMessage) throws Exception { 40 | logger.warning("not implemented"); 41 | } 42 | 43 | /** 44 | * {@inheritDoc} 45 | */ 46 | @Override 47 | public void processSSDPByeByeMessage(ByeByeMessage ssdpMessage) throws Exception { 48 | logger.warning("not implemented"); 49 | } 50 | 51 | /** 52 | * {@inheritDoc} 53 | */ 54 | @Override 55 | public void processSSDPDiscoverMessage(String remoteAddr, int remotePort, DiscoverMessage ssdpMessage) throws Exception { 56 | logger.warning("not implemented"); 57 | } 58 | 59 | /** 60 | * {@inheritDoc} 61 | */ 62 | @Override 63 | public void processSSDPUpdateMessage(UpdateMessage ssdpMessage) throws Exception { 64 | logger.warning("not implemented"); 65 | } 66 | 67 | /** 68 | * {@inheritDoc} 69 | */ 70 | @Override 71 | public void processSSDPDiscoverResponseMessage(DiscoverResponseMessage ssdpMessage) throws Exception { 72 | logger.warning("not implemented"); 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /ssdp-core/src/main/java/com/jerabi/ssdp/handler/SSDPDefaultResponseHandler.java: -------------------------------------------------------------------------------- 1 | package com.jerabi.ssdp.handler; 2 | 3 | import java.util.logging.Logger; 4 | 5 | import com.jerabi.ssdp.ISSDPControler; 6 | import com.jerabi.ssdp.message.ISSDPMessage; 7 | import com.jerabi.ssdp.message.helper.SSDPMessageHelper; 8 | 9 | /** 10 | * Provides a API to handle raw messages received. 11 | * 12 | * Normally the handle methods call {@link com.jerabi.ssdp.ISSDPControler} to process 13 | * the message and it call be used to filter the messages received. 14 | * 15 | * {@link com.jerabi.ssdp.handler.SSDPDiscoverResponseHandler} is a good 16 | * example of a ISSDPHandler that doesn't process DiscoverMessage (M-SEARCH) 17 | * 18 | * This class look like {@link ISSDPMessageHandler} but ISSDPMessageHandler actually process a {@link com.jerabi.ssdp.message.ISSDPMessage} 19 | * generated from the raw message received by this ISSDPHandler. Once a ISSDPMessage is generated, it's passed to the {@link com.jerabi.ssdp.ISSDPControler}. 20 | * 21 | * @author Sebastien Dionne 22 | * @see ISSDPMessageHandler 23 | */ 24 | public class SSDPDefaultResponseHandler implements ISSDPResponseHandler { 25 | private Logger logger = Logger.getLogger(SSDPDefaultResponseHandler.class.getName()); 26 | 27 | protected ISSDPControler controler = null; 28 | 29 | /** 30 | * Constructor 31 | * @param controler that will process {@link ISSDPMessage} 32 | */ 33 | public SSDPDefaultResponseHandler(ISSDPControler controler) { 34 | this.controler = controler; 35 | } 36 | 37 | /** 38 | * {@inheritDoc} 39 | */ 40 | @Override 41 | public ISSDPControler getSSDPControler() { 42 | return controler; 43 | } 44 | 45 | /** 46 | * {@inheritDoc} 47 | */ 48 | @Override 49 | public void setSSDPControler(ISSDPControler controler) { 50 | this.controler = controler; 51 | } 52 | 53 | /** 54 | * {@inheritDoc} 55 | * The message received will be converted to ISSDPMessage 56 | * {@link SSDPMessageHelper#getSSDPMessage(String)}. 57 | * 58 | * The ISSDPMessage will be process by the ISSDPControler 59 | */ 60 | public void handle(String message) throws Exception { 61 | 62 | logger.info("\n" + message); 63 | 64 | ISSDPMessage ssdpMessage = SSDPMessageHelper.getSSDPMessage(message); 65 | 66 | if(ssdpMessage!=null && controler!=null){ 67 | controler.processSSDPMessage(ssdpMessage); 68 | } 69 | 70 | } 71 | 72 | /** 73 | * {@inheritDoc} 74 | * The message received will be converted to ISSDPMessage 75 | * {@link SSDPMessageHelper#getSSDPMessage(String)}. 76 | * 77 | * The ISSDPMessage will be process by the ISSDPControler 78 | */ 79 | @Override 80 | public void handle(String remoteAddr, int remotePort, String message) throws Exception { 81 | logger.info("\n" + message); 82 | 83 | ISSDPMessage ssdpMessage = SSDPMessageHelper.getSSDPMessage(message); 84 | 85 | if(ssdpMessage!=null && controler!=null){ 86 | controler.processSSDPMessage(remoteAddr, remotePort, ssdpMessage); 87 | } 88 | 89 | } 90 | 91 | } 92 | -------------------------------------------------------------------------------- /ssdp-core/src/main/java/com/jerabi/ssdp/handler/SSDPDiscoverResponseHandler.java: -------------------------------------------------------------------------------- 1 | package com.jerabi.ssdp.handler; 2 | 3 | import java.util.logging.Logger; 4 | 5 | import com.jerabi.ssdp.ISSDPControler; 6 | import com.jerabi.ssdp.message.ISSDPMessage; 7 | import com.jerabi.ssdp.message.helper.SSDPMessageHelper; 8 | 9 | /** 10 | * Provides a API to handle raw messages received but don't process DiscoverMessage (M-SEARCH). 11 | * 12 | * Normally the handle methods call {@link com.jerabi.ssdp.ISSDPControler} to process 13 | * the message and it call be used to filter the messages received. 14 | * 15 | * It should be used when you sending DiscoverMessage and don't want to handle the DiscoverMessage that you just sent. 16 | * 17 | * If you want to receive theses DiscoverMessage or change the filters to exclude messages, you could use {@link SSDPDefaultResponseHandler} instead. 18 | * 19 | * This class look like {@link ISSDPMessageHandler} but ISSDPMessageHandler actually process a {@link com.jerabi.ssdp.message.ISSDPMessage} 20 | * generated from the raw message received by this ISSDPHandler. Once a ISSDPMessage is generated, it's passed to the {@link com.jerabi.ssdp.ISSDPControler}. 21 | * 22 | * @author Sebastien Dionne 23 | * @see SSDPDefaultResponseHandler 24 | */ 25 | public class SSDPDiscoverResponseHandler extends SSDPDefaultResponseHandler { 26 | private Logger logger = Logger.getLogger(SSDPDiscoverResponseHandler.class.getName()); 27 | 28 | /** 29 | * Constructor 30 | * @param controler ISSDPControler that will process the {@link ISSDPMessage}. 31 | */ 32 | public SSDPDiscoverResponseHandler(ISSDPControler controler) { 33 | super(controler); 34 | } 35 | 36 | /** 37 | * {@inheritDoc} 38 | * Exclude DiscoverMessage 39 | */ 40 | @Override 41 | public void handle(String message) throws Exception { 42 | 43 | // we shouldn't received M_SEARCH.. but just in case, we skip it. 44 | if(message!=null && !message.startsWith("M-SEARCH")){ 45 | logger.info("\n" + message); 46 | 47 | ISSDPMessage ssdpMessage = SSDPMessageHelper.getSSDPMessage(message); 48 | 49 | if(ssdpMessage!=null && controler!=null){ 50 | controler.processSSDPMessage(ssdpMessage); 51 | } 52 | 53 | } 54 | 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /ssdp-core/src/main/java/com/jerabi/ssdp/listener/SSDPMulticastListener.java: -------------------------------------------------------------------------------- 1 | package com.jerabi.ssdp.listener; 2 | 3 | import java.net.InetAddress; 4 | import java.net.InetSocketAddress; 5 | import java.net.NetworkInterface; 6 | import java.net.SocketTimeoutException; 7 | import java.util.List; 8 | import java.util.logging.Level; 9 | import java.util.logging.Logger; 10 | 11 | import com.jerabi.ssdp.handler.ISSDPResponseHandler; 12 | import com.jerabi.ssdp.network.IMulticastListener; 13 | import com.jerabi.ssdp.network.SSDPNetworkFactory; 14 | import com.jerabi.ssdp.util.SSDPContants; 15 | import com.jerabi.ssdp.util.State; 16 | import com.jerabi.ssdp.util.StateHolder; 17 | 18 | /** 19 | * Provides API to listen for multicast messages over network. 20 | * 21 | * @author Sebastien Dionne 22 | * @example. 23 | *
 24 |  * // You need pass a ISSDPHandler to handle the multicast messages received.
 25 |  * SSDPMulticastListener listener = new SSDPMulticastListener(SSDPContants.DEFAULT_IP, SSDPContants.DEFAULT_PORT, true);
 26 |  * listener.setSSDPHandler(new SSDPDefaultHandler(controler)); 
 27 |  * t = new Thread(listener);
 28 |  * t.start();
 29 |  * 
 30 |  * // using multiples Network Interfaces
 31 |  * 
 32 |  // You need pass a ISSDPHandler to handle the multicast messages received.
 33 |  * List networkInterfaceList = new ArrayList();
 34 |  * networkInterfaceList.add(NetworkInterface.getByName("eth0"));
 35 |  * SSDPMulticastListener listener = new SSDPMulticastListener(new InetSocketAddress(SSDPContants.DEFAULT_IP, SSDPContants.DEFAULT_PORT), networkInterfaceList);
 36 |  * listener.setSSDPHandler(new SSDPDefaultHandler(controler)); 
 37 |  * t = new Thread(listener);
 38 |  * t.start();  
 39 |  * 
40 | * 41 | */ 42 | public class SSDPMulticastListener implements Runnable { 43 | private static final Logger logger = Logger.getLogger(SSDPMulticastListener.class.getName()); 44 | 45 | protected StateHolder stateHolder = new StateHolder(); 46 | 47 | protected int timeout = SSDPContants.DEFAULT_SOCKET_TIMEOUT; 48 | protected String host = null; 49 | protected int port; 50 | protected InetSocketAddress socketAddress = null; 51 | protected List networkInterfaceList = null; 52 | private ISSDPResponseHandler handler = null; 53 | protected boolean blocking = true; 54 | 55 | /** 56 | * Constructor with default delay and listener in blocking mode 57 | * @param host Multicast IP 58 | * @param port Multicast Port 59 | */ 60 | public SSDPMulticastListener(String host, int port) { 61 | this(host, port, SSDPContants.DEFAULT_SOCKET_TIMEOUT, true); 62 | } 63 | 64 | /** 65 | * Constructor with listener in blocking mode 66 | * @param host Multicast IP 67 | * @param port Multicast Port 68 | * @param timeout timeout for the non blocking mode 69 | */ 70 | public SSDPMulticastListener(String host, int port, int timeout) { 71 | this(host, port, timeout, true); 72 | } 73 | 74 | /** 75 | * Constructor with custom values 76 | * @param host Multicast IP 77 | * @param port Multicast Port 78 | * @param timeout timeout for the non blocking mode 79 | * @param blocking is it in blocking mode 80 | */ 81 | public SSDPMulticastListener(String host, int port, int timeout, boolean blocking) { 82 | this.host = host; 83 | this.port = port; 84 | this.timeout = timeout; 85 | this.blocking = blocking; 86 | 87 | setState(State.STOPPED); 88 | } 89 | 90 | /** 91 | * Constructor with default delay and listener in blocking mode 92 | * @param host Multicast IP 93 | * @param port Multicast Port 94 | * @param networkInterfaceList NetworkInterfaces that will be used to listen 95 | */ 96 | public SSDPMulticastListener(String host, int port, List networkInterfaceList) { 97 | this(host, port, networkInterfaceList, SSDPContants.DEFAULT_SOCKET_TIMEOUT, true); 98 | } 99 | 100 | /** 101 | * Constructor with listener in blocking mode 102 | * @param host Multicast IP 103 | * @param port Multicast Port 104 | * @param networkInterfaceList NetworkInterfaces that will be used to listen 105 | * @param timeout timeout for the non blocking mode 106 | */ 107 | public SSDPMulticastListener(String host, int port, List networkInterfaceList, int timeout) { 108 | this(host, port, networkInterfaceList, timeout, true); 109 | } 110 | 111 | /** 112 | * Constructor with custom values 113 | * @param host Multicast IP 114 | * @param port Multicast Port 115 | * @param networkInterfaceList NetworkInterfaces that will be used to listen 116 | * @param timeout timeout for the non blocking mode 117 | * @param blocking is it in blocking mode 118 | */ 119 | public SSDPMulticastListener(String host, int port, List networkInterfaceList, int timeout, boolean blocking) { 120 | this.host = host; 121 | this.port = port; 122 | this.networkInterfaceList = networkInterfaceList; 123 | this.timeout = timeout; 124 | this.blocking = blocking; 125 | 126 | socketAddress = new InetSocketAddress(host, port); 127 | 128 | setState(State.STOPPED); 129 | } 130 | 131 | /** 132 | * Constructor with default delay and listener in blocking mode 133 | * @param socketAddress Multicast IP and port 134 | * @param networkInterfaceList NetworkInterfaces that will be used to listen 135 | */ 136 | public SSDPMulticastListener(InetSocketAddress socketAddress, List networkInterfaceList) { 137 | this(socketAddress, networkInterfaceList, SSDPContants.DEFAULT_SOCKET_TIMEOUT, true); 138 | } 139 | 140 | /** 141 | * Constructor with default delay and listener in blocking mode 142 | * @param socketAddress Multicast IP and port 143 | * @param networkInterfaceList NetworkInterfaces that will be used to listen 144 | * * @param timeout timeout for the non blocking mode 145 | */ 146 | public SSDPMulticastListener(InetSocketAddress socketAddress, List networkInterfaceList, int timeout) { 147 | this(socketAddress, networkInterfaceList, timeout, true); 148 | } 149 | 150 | /** 151 | * Constructor with default delay and listener in blocking mode 152 | * @param socketAddress Multicast IP and port 153 | * @param networkInterfaceList NetworkInterfaces that will be used to listen 154 | * @param timeout timeout for the non blocking mode 155 | * @param blocking is it in blocking mode 156 | */ 157 | public SSDPMulticastListener(InetSocketAddress socketAddress, List networkInterfaceList, int timeout, boolean blocking) { 158 | this.socketAddress = socketAddress; 159 | this.networkInterfaceList = networkInterfaceList; 160 | this.timeout = timeout; 161 | this.blocking = blocking; 162 | 163 | setState(State.STOPPED); 164 | } 165 | 166 | /** 167 | * Returns the ISSDPHandler that handle the multicast messages received 168 | * @return the handler 169 | */ 170 | public ISSDPResponseHandler getSSDPResponseHandler() { 171 | return handler; 172 | } 173 | 174 | /** 175 | * Sets the ISSDPHandler that will handle the multicast messages received 176 | * @param handler 177 | */ 178 | public void setSSDPResponseHandler(ISSDPResponseHandler handler) { 179 | this.handler = handler; 180 | } 181 | 182 | /** 183 | * Returns the current state of this listener 184 | * @return the current state 185 | */ 186 | public State getState() { 187 | return stateHolder.getState(); 188 | } 189 | 190 | /** 191 | * Sets a new state for this listener 192 | * @param state new State 193 | */ 194 | public void setState(State state) { 195 | this.stateHolder.setState(state); 196 | } 197 | 198 | /** 199 | * Returns the timeout of the non blocking mode 200 | * @return timeout in ms. 201 | */ 202 | public int getTimeout() { 203 | return timeout; 204 | } 205 | 206 | /** 207 | * Sets the timeout for the non blocking mode 208 | * @param timeout value in ms. 209 | */ 210 | public void setTimeout(int timeout) { 211 | this.timeout = timeout; 212 | } 213 | 214 | /** 215 | * Returns the Multicast Address on which this listener listen 216 | * @return the IP. 217 | */ 218 | public String getHost() { 219 | return host; 220 | } 221 | 222 | /** 223 | * Sets the Multicast Address on which this listener will listen 224 | * @param host the IP 225 | */ 226 | public void setHost(String host) { 227 | this.host = host; 228 | } 229 | 230 | /** 231 | * Returns the Multicast Port on which this listener listen 232 | * @return the port. 233 | */ 234 | public int getPort() { 235 | return port; 236 | } 237 | 238 | /** 239 | * Sets the Multicast Port on which this listener will listen 240 | * @param port the port 241 | */ 242 | public void setPort(int port) { 243 | this.port = port; 244 | } 245 | 246 | /** 247 | * Sets this listener in blocking mode or non blocking. 248 | *
249 | 	 * In blocking mode this listener will block until a message is received.
250 | 	 * In non blocking mode this listener will wait until the timeout value and loop back again.
251 | 	 * In non blocking mode this listener can be stopped when the timeout expired, and in blocking mode,
252 | 	 * the listener need to receive a message before changing state.
253 | 	 * 
254 | * @param blocking is blocking mode enabled 255 | */ 256 | public void setBlocking(boolean blocking){ 257 | this.blocking = blocking; 258 | } 259 | 260 | /** 261 | * Returns the blocking mode of this listener 262 | *
263 | 	 * In blocking mode this listener will block until a message is received.
264 | 	 * In non blocking mode this listener will wait until the timeout value and loop back again.
265 | 	 * In non blocking mode this listener can be stopped when the timeout expired, and in blocking mode,
266 | 	 * the listener need to receive a message before changing state.
267 | 	 * 
268 | * @return is it blocking mode enabled 269 | */ 270 | public boolean getBlocking(){ 271 | return blocking; 272 | } 273 | 274 | @Override 275 | public void run() { 276 | 277 | stateHolder.setState(State.STARTED); 278 | 279 | IMulticastListener listener = null; 280 | InetAddress group = null; 281 | 282 | try { 283 | 284 | // if NetworkInterface are used, we can join on multiple groups 285 | if(networkInterfaceList!=null && !networkInterfaceList.isEmpty()){ 286 | //listener = SSDPNetworkFactory.getInstance().createMulticastListener(socketAddress, handler); 287 | listener = SSDPNetworkFactory.getInstance().createMulticastListener(socketAddress.getPort(), handler); 288 | for (NetworkInterface ni : networkInterfaceList) { 289 | listener.joinGroup(socketAddress, ni); 290 | } 291 | } else { 292 | group = InetAddress.getByName(host); 293 | listener = SSDPNetworkFactory.getInstance().createMulticastListener(port, handler); 294 | listener.joinGroup(group); 295 | } 296 | 297 | listener.setTimeout(timeout); 298 | 299 | while (!Thread.interrupted() && stateHolder.getState() != State.STOPPED) { 300 | try { 301 | listener.receive(blocking); 302 | } catch (SocketTimeoutException e) { 303 | // does nothing 304 | } 305 | } 306 | } catch(Exception e){ 307 | logger.log(Level.WARNING, e.getMessage(), e); 308 | } finally { 309 | stateHolder.setState(State.STOPPED); 310 | if(listener!=null){ 311 | if(group!=null){ 312 | try { 313 | listener.leaveGroup(group); 314 | } catch (Exception e) { 315 | } 316 | } else if(networkInterfaceList!=null && !networkInterfaceList.isEmpty()){ 317 | for (NetworkInterface ni : networkInterfaceList) { 318 | try { 319 | listener.leaveGroup(socketAddress, ni); 320 | } catch (Exception e) { 321 | } 322 | } 323 | } 324 | } 325 | } 326 | 327 | 328 | } 329 | 330 | } 331 | -------------------------------------------------------------------------------- /ssdp-core/src/main/java/com/jerabi/ssdp/message/AbstractSSDPNotifyMessage.java: -------------------------------------------------------------------------------- 1 | package com.jerabi.ssdp.message; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * Contains the commons fields for notification {@link ISSDPMessage}. 7 | * A parent class will extends this class and add the required fields that are missing. 8 | * 9 | * @author Sebastien Dionne 10 | * 11 | */ 12 | public abstract class AbstractSSDPNotifyMessage implements ISSDPMessage { 13 | protected String message; 14 | protected String notify; 15 | protected String host; 16 | protected String port; 17 | protected String nt; 18 | protected String nts; 19 | protected String usn; 20 | protected List attributes = null; 21 | 22 | /** 23 | * Returns the raw message if parsed with {@link com.jerabi.ssdp.message.helper.SSDPMessageHelper} 24 | * @return message not parsed 25 | */ 26 | public String getMessage() { 27 | return message; 28 | } 29 | 30 | /** 31 | * Sets the raw message if parsed with {@link com.jerabi.ssdp.message.helper.SSDPMessageHelper} 32 | * or for debugging 33 | * @param message original message not parsed 34 | */ 35 | public void setMessage(String message) { 36 | this.message = message; 37 | } 38 | /** 39 | * Returns the (USN) 40 | * @see com.jerabi.ssdp.message.USNInfo 41 | * @return (USN) Unique Service Name 42 | */ 43 | public String getUsn() { 44 | return usn; 45 | } 46 | 47 | /** 48 | * Sets the (USN) 49 | * @see com.jerabi.ssdp.message.USNInfo 50 | * @param usn Unique Service Name 51 | */ 52 | public void setUsn(String usn) { 53 | this.usn = usn; 54 | } 55 | 56 | /** 57 | * Returns the host 58 | * @return host 59 | */ 60 | public String getHost() { 61 | return host; 62 | } 63 | 64 | /** 65 | * Sets the host 66 | * @param host 67 | */ 68 | public void setHost(String host) { 69 | this.host = host; 70 | } 71 | 72 | /** 73 | * Returns Notification Type (NT) 74 | * @return Notification Type 75 | */ 76 | public String getNt() { 77 | return nt; 78 | } 79 | 80 | /** 81 | * Sets Notification Type (NT) 82 | * @param nt 83 | */ 84 | public void setNt(String nt) { 85 | this.nt = nt; 86 | } 87 | 88 | /** 89 | * Sets Notification Sub Type (NTS). It's the message type 90 | * @see AliveMessage 91 | * @see ByeByeMessage 92 | * @see UpdateMessage 93 | * @param nts 94 | */ 95 | public void setNts(String nts) { 96 | this.nts = nts; 97 | } 98 | 99 | /** 100 | * Returns the Notify : the first line of the message 101 | * @return notify 102 | */ 103 | public String getNotify() { 104 | return notify; 105 | } 106 | 107 | /** 108 | * Sets the notify 109 | * @param notify 110 | */ 111 | public void setNotify(String notify) { 112 | this.notify = notify; 113 | } 114 | 115 | /** 116 | * Returns port 117 | * @return port 118 | */ 119 | public String getPort() { 120 | return port; 121 | } 122 | 123 | /** 124 | * Sets port 125 | * @param port 126 | */ 127 | public void setPort(String port) { 128 | this.port = port; 129 | } 130 | 131 | /** 132 | * Returns the extra attributes for the message 133 | * @return extra attributes 134 | */ 135 | public List getAttributes() { 136 | return attributes; 137 | } 138 | 139 | /** 140 | * Sets extra attributes for the message 141 | * @param attributes 142 | */ 143 | public void setAttributes(List attributes) { 144 | this.attributes = attributes; 145 | } 146 | 147 | /** 148 | * Return this message formatted 149 | * @return message formatted 150 | */ 151 | public abstract String toString(); 152 | 153 | /** 154 | * Returns Notification Sub Type (NTS) 155 | * @return nts 156 | */ 157 | public abstract String getNts(); 158 | 159 | } 160 | -------------------------------------------------------------------------------- /ssdp-core/src/main/java/com/jerabi/ssdp/message/AliveMessage.java: -------------------------------------------------------------------------------- 1 | package com.jerabi.ssdp.message; 2 | 3 | import com.jerabi.ssdp.util.SSDPContants; 4 | 5 | /** 6 | * 7 | * Represents a ssdp:alive message. This message is sent periodically as a keep-alive like and for broadcasting 8 | * the service that the device offers. The server must sent this message for advertising his services. 9 | * 10 | * @author Sebastien Dionne 11 | * @example. 12 | *
 13 |  *   NOTIFY * HTTP/1.1
 14 |  *   HOST: 239.255.255.250:1900
 15 |  *   NT: urn:schemas-upnp-org:service:ContentDirectory:1
 16 |  *   NTS: ssdp:alive
 17 |  *   LOCATION: http://142.225.35.55:5001/description/fetch
 18 |  *   USN: uuid:9dcf6222-fc4b-33eb-bf49-e54643b4f416::urn:schemas-upnp-org:service:ContentDirectory:1
 19 |  *   CACHE-CONTROL: max-age=1800
 20 |  *   SERVER: Windows_XP-x86-5.1, UPnP/1.0, PMS/1.11
 21 |  *   
22 | * 23 | * @see AbstractSSDPNotifyMessage 24 | */ 25 | public class AliveMessage extends AbstractSSDPNotifyMessage { 26 | 27 | /** 28 | * First line of the message 29 | */ 30 | public static final String notify = "NOTIFY * HTTP/1.1"; 31 | 32 | /** 33 | * NTS value 34 | */ 35 | public static final String nts = SSDPContants.NTS_ALIVE; 36 | 37 | protected String cacheControl; 38 | protected String location; 39 | protected String server; 40 | 41 | /** 42 | * {@inheritDoc} 43 | */ 44 | @Override 45 | public String getNts() { 46 | return nts; 47 | } 48 | 49 | /** 50 | * Returns a duration for which the advertisement is valid 51 | * @return cache-control value 52 | */ 53 | public String getCacheControl() { 54 | return cacheControl; 55 | } 56 | /** 57 | * Sets the duration for which the advertisement is valid 58 | * @param cacheControl 59 | */ 60 | public void setCacheControl(String cacheControl) { 61 | this.cacheControl = cacheControl; 62 | } 63 | 64 | /** 65 | * Returns the URL for retrieving more information about the device. 66 | * The device most respond to this URL. 67 | * 68 | * @return device location 69 | */ 70 | public String getLocation() { 71 | return location; 72 | } 73 | 74 | /** 75 | * Sets the URL on which the device will publish more information 76 | * @param location 77 | */ 78 | public void setLocation(String location) { 79 | this.location = location; 80 | } 81 | /** 82 | * Returns the server informations. 83 | * Format is : OS/version, UPnP/version, product/version 84 | * @return server informations 85 | */ 86 | public String getServer() { 87 | return server; 88 | } 89 | 90 | /** 91 | * Sets the server informations. 92 | * Format must be : OS/version, UPnP/version, product/version 93 | * @param server informations 94 | */ 95 | public void setServer(String server) { 96 | this.server = server; 97 | } 98 | 99 | /** 100 | * {@inheritDoc} 101 | */ 102 | @Override 103 | public String toString() { 104 | StringBuffer sb = new StringBuffer(); 105 | 106 | sb.append(getNotify()).append("\r\n"); 107 | sb.append(SSDPContants.HOST + " " + getHost()).append("\r\n"); 108 | sb.append(SSDPContants.NT + " " + getNt()).append("\r\n"); 109 | sb.append(SSDPContants.NTS + " " + getNts()).append("\r\n"); 110 | sb.append(SSDPContants.LOCATION + " " + getLocation()).append("\r\n"); 111 | sb.append(SSDPContants.USN + " " + getUsn()).append("\r\n"); 112 | sb.append(SSDPContants.CACHECONTROL + " " + getCacheControl()).append("\r\n"); 113 | sb.append(SSDPContants.SERVER + " " + getServer()).append("\r\n"); 114 | sb.append("\r\n"); 115 | 116 | return sb.toString(); 117 | } 118 | 119 | } 120 | -------------------------------------------------------------------------------- /ssdp-core/src/main/java/com/jerabi/ssdp/message/ByeByeMessage.java: -------------------------------------------------------------------------------- 1 | package com.jerabi.ssdp.message; 2 | 3 | import com.jerabi.ssdp.util.SSDPContants; 4 | 5 | /** 6 | * 7 | * Represents a ssdp:byebye message. 8 | * 9 | * When a device and its services are going to be removed from the network, the device SHOULD multicast an ssdp:byebye message 10 | * corresponding to each of the ssdp:alive messages it multicasted that have not already expired. If the device is removed abruptly 11 | * from the network, it might not be possible to multicast a message. 12 | * 13 | * When the device starts a ssdp:byebye message must be sent before any other messages. (It's not mandatory but strongly suggested) 14 | * 15 | * @author Sebastien Dionne 16 | * @example. 17 | *
18 |  *   NOTIFY * HTTP/1.1
19 |  *   HOST: 239.255.255.250:1900
20 |  *   NTS: ssdp:byebye
21 |  *   USN: uuid:9dcf6222-fc4b-33eb-bf49-e54643b4f416::urn:schemas-upnp-org:service:ContentDirectory:1
22 |  *   NT: urn:schemas-upnp-org:service:ContentDirectory:1
23 |  *   CONTENT-LENGTH: 0
24 |  *   
25 | * 26 | * @see AbstractSSDPNotifyMessage 27 | */ 28 | public class ByeByeMessage extends AbstractSSDPNotifyMessage { 29 | 30 | /** 31 | * First line of the message 32 | */ 33 | public static final String notify = "NOTIFY * HTTP/1.1"; 34 | 35 | /** 36 | * NTS value 37 | */ 38 | public static final String nts = SSDPContants.NTS_BYEBYE; 39 | protected String contentLength; 40 | 41 | /** 42 | * {@inheritDoc} 43 | */ 44 | @Override 45 | public String getNts() { 46 | return nts; 47 | } 48 | 49 | /** 50 | * Returns the bytes in the body 51 | * @return body length 52 | */ 53 | public String getContentLength() { 54 | return contentLength; 55 | } 56 | 57 | /** 58 | * Sets the byte length available in the body 59 | * @param contentLength 60 | */ 61 | public void setContentLength(String contentLength) { 62 | this.contentLength = contentLength; 63 | } 64 | 65 | /** 66 | * {@inheritDoc} 67 | */ 68 | @Override 69 | public String toString() { 70 | StringBuffer sb = new StringBuffer(); 71 | 72 | sb.append(getNotify()).append("\r\n"); 73 | sb.append(SSDPContants.HOST + " " + getHost()).append("\r\n"); 74 | sb.append(SSDPContants.NT + " " + getNt()).append("\r\n"); 75 | sb.append(SSDPContants.NTS + " " + getNts()).append("\r\n"); 76 | sb.append(SSDPContants.USN + " " + getUsn()).append("\r\n"); 77 | sb.append(SSDPContants.CONTENTLENGTH + " " + getContentLength()).append("\r\n"); 78 | 79 | return sb.toString(); 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /ssdp-core/src/main/java/com/jerabi/ssdp/message/DiscoverMessage.java: -------------------------------------------------------------------------------- 1 | package com.jerabi.ssdp.message; 2 | 3 | import java.util.List; 4 | 5 | import com.jerabi.ssdp.util.SSDPContants; 6 | 7 | /** 8 | * Represents a "ssdp:discover" message (M-SEARCH). 9 | * 10 | * When a Client (Control Point) want to search for device, it must send a discover message. 11 | * 12 | * You can search for any device and a particular device/service with the parameter : ST. 13 | * 14 | * @author Sebastien Dionne 15 | * 16 | * @example. 17 | * 18 | *
 19 |  * M-SEARCH * HTTP/1.1
 20 |  * HOST: 239.255.255.250:1900
 21 |  * ST: urn:schemas-upnp-org:device:MediaServer:1
 22 |  * MAN: "ssdp:discover"
 23 |  * MX: 2
 24 |  * X-AV-Client-Info: av=5.0; cn="Sony Computer Entertainment Inc."; mn="PLAYSTATION 3"; mv="1.0";
 25 |  * 
26 | * 27 | * @see DiscoverResponseMessage 28 | */ 29 | public class DiscoverMessage implements ISSDPMessage { 30 | 31 | /** 32 | * First line of the message 33 | */ 34 | public static final String notify = "M-SEARCH * HTTP/1.1"; 35 | /** 36 | * Field for discover message (M-SEARCH) 37 | */ 38 | public static final String man = SSDPContants.NTS_DISCOVER; 39 | 40 | protected String message; 41 | protected String host = null; 42 | protected String port; 43 | protected String st = null; 44 | protected String mx = null; 45 | protected List attributes = null; 46 | 47 | /** 48 | * Default constructor 49 | */ 50 | public DiscoverMessage(){ 51 | 52 | } 53 | 54 | /** 55 | * Constructor 56 | * 57 | * @param host IP address that the device broadcast 58 | * @param port that the device broadcast 59 | * @param ttl Time-to-Live for this advertisement 60 | * @param device which device/service that we searching for. 61 | * @param attributes extra attributes for the DiscoverMessage 62 | */ 63 | public DiscoverMessage(String host, int port, int ttl, String device, List attributes){ 64 | this.host = host; 65 | this.port = Integer.toString(port); 66 | this.mx = Integer.toString(ttl); 67 | this.st = device; 68 | this.attributes = attributes; 69 | } 70 | 71 | /** 72 | * Returns the raw message if parsed with {@link com.jerabi.ssdp.message.helper.SSDPMessageHelper} 73 | * @return message not parsed 74 | */ 75 | public String getMessage() { 76 | return message; 77 | } 78 | 79 | /** 80 | * Sets the raw message if parsed with {@link com.jerabi.ssdp.message.helper.SSDPMessageHelper} 81 | * or for debugging 82 | * @param message original message not parsed 83 | */ 84 | public void setMessage(String message) { 85 | this.message = message; 86 | } 87 | 88 | /** 89 | * Returns the host 90 | * @return host 91 | */ 92 | public String getHost() { 93 | return host; 94 | } 95 | 96 | /** 97 | * Sets the host 98 | * @param host 99 | */ 100 | public void setHost(String host) { 101 | this.host = host; 102 | } 103 | 104 | /** 105 | * Returns the search target (ST) 106 | * @return st URN target 107 | */ 108 | public String getSt() { 109 | return st; 110 | } 111 | 112 | /** 113 | * Sets the search target (ST) 114 | * @param st URN target 115 | */ 116 | public void setSt(String st) { 117 | this.st = st; 118 | } 119 | 120 | /** 121 | * Returns the maximum wait time in seconds 122 | * @return the "time-to-live" value 123 | */ 124 | public String getMx() { 125 | return mx; 126 | } 127 | 128 | /** 129 | * Sets the maximum wait time in seconds 130 | * @param mx the "time-to-live" value 131 | */ 132 | public void setMx(String mx) { 133 | this.mx = mx; 134 | } 135 | 136 | /** 137 | * Returns the listen port 138 | * @return port 139 | */ 140 | public String getPort() { 141 | return port; 142 | } 143 | 144 | /** 145 | * Sets the listen port 146 | * @param port 147 | */ 148 | public void setPort(String port) { 149 | this.port = port; 150 | } 151 | 152 | /** 153 | * Returns the extra attributes for the message 154 | * @return extra attributes 155 | */ 156 | public List getAttributes() { 157 | return attributes; 158 | } 159 | 160 | /** 161 | * Sets extra attributes for the message 162 | * @param attributes 163 | */ 164 | public void setAttributes(List attributes) { 165 | this.attributes = attributes; 166 | } 167 | 168 | /** 169 | * {@inheritDoc} 170 | */ 171 | public String toString(){ 172 | StringBuffer sb = new StringBuffer(); 173 | 174 | String host = getHost(); 175 | 176 | if(getPort()!=null){ 177 | host = host + ":" + getPort(); 178 | } else { 179 | host = host + ":" + SSDPContants.DEFAULT_PORT; 180 | } 181 | 182 | sb.append(notify).append("\r\n"); 183 | sb.append(SSDPContants.HOST + " " + host).append("\r\n"); 184 | sb.append(SSDPContants.MAN + " " + man).append("\r\n"); 185 | sb.append(SSDPContants.MX + " " + mx).append("\r\n"); 186 | sb.append(SSDPContants.ST + " " + st).append("\r\n"); 187 | 188 | // custom attributes 189 | if(attributes!=null && attributes.size()>0){ 190 | for (String attribute : attributes) { 191 | sb.append(attribute).append("\r\n"); 192 | } 193 | } 194 | sb.append("\r\n"); 195 | 196 | return sb.toString(); 197 | } 198 | } 199 | -------------------------------------------------------------------------------- /ssdp-core/src/main/java/com/jerabi/ssdp/message/DiscoverResponseMessage.java: -------------------------------------------------------------------------------- 1 | package com.jerabi.ssdp.message; 2 | 3 | import java.util.List; 4 | 5 | import com.jerabi.ssdp.util.SSDPContants; 6 | 7 | 8 | 9 | /** 10 | * Represents a response to a {@link DiscoverMessage}. 11 | * 12 | * @author Sebastien Dionne 13 | * 14 | * @example. 15 | *
 16 |  * HTTP/1.1 200 OK
 17 |  * CACHE-CONTROL: max-age=1200
 18 |  * DATE: Tue, 05 May 2009 13:31:51 GMT
 19 |  * LOCATION: http://142.225.35.55:5001/description/fetch
 20 |  * SERVER: Windows_XP-x86-5.1, UPnP/1.0, PMS/1.11
 21 |  * ST: upnp:rootdevice
 22 |  * EXT: 
 23 |  * USN: uuid:9dcf6222-fc4b-33eb-bf49-e54643b4f416::upnp:rootdevice
 24 |  * Content-Length: 0
 25 |  * 
26 | * 27 | * @see DiscoverMessage 28 | */ 29 | public class DiscoverResponseMessage implements ISSDPMessage { 30 | 31 | /** 32 | * First line of the message 33 | */ 34 | public static final String notify = "HTTP/1.1 200 OK"; 35 | 36 | protected String message; 37 | protected String cacheControl; 38 | protected String date; 39 | protected String location; 40 | protected String server; 41 | protected String st; 42 | protected String ext; 43 | protected String usn; 44 | protected String contentLength; 45 | protected List attributes = null; 46 | 47 | /** 48 | * Returns the Notify : the first line of the message 49 | * @return notify 50 | */ 51 | public String getNotify() { 52 | return notify; 53 | } 54 | 55 | /** 56 | * Returns a duration for which the advertisement is valid 57 | * @return cache-control value 58 | */ 59 | public String getCacheControl() { 60 | return cacheControl; 61 | } 62 | 63 | /** 64 | * Sets the duration for which the advertisement is valid 65 | * @param cacheControl 66 | */ 67 | public void setCacheControl(String cacheControl) { 68 | this.cacheControl = cacheControl; 69 | } 70 | 71 | /** 72 | * Returns when response was generated 73 | * @return date 74 | */ 75 | public String getDate() { 76 | return date; 77 | } 78 | 79 | /** 80 | * Sets the date when the response was generated 81 | * @param date 82 | */ 83 | public void setDate(String date) { 84 | this.date = date; 85 | } 86 | 87 | /** 88 | * Returns the URL for retrieving more information about the device. 89 | * The device most respond to this URL. 90 | * 91 | * @return device location 92 | */ 93 | public String getLocation() { 94 | return location; 95 | } 96 | 97 | /** 98 | * Sets the URL on which the device will publish more information 99 | * @param location 100 | */ 101 | public void setLocation(String location) { 102 | this.location = location; 103 | } 104 | 105 | /** 106 | * Returns the server informations. 107 | * Format is : OS/version, UPnP/version, product/version 108 | * @return server informations 109 | */ 110 | public String getServer() { 111 | return server; 112 | } 113 | 114 | /** 115 | * Sets the server informations. 116 | * Format must be : OS/version, UPnP/version, product/version 117 | * @param server informations 118 | */ 119 | public void setServer(String server) { 120 | this.server = server; 121 | } 122 | 123 | /** 124 | * Returns the search target (ST) 125 | * @return st URN target 126 | */ 127 | public String getSt() { 128 | return st; 129 | } 130 | 131 | /** 132 | * Sets the search target (ST) 133 | * @param st URN target 134 | */ 135 | public void setSt(String st) { 136 | this.st = st; 137 | } 138 | /** 139 | * Returns EXT value 140 | * Backwards compatibility with UPnP 1.0. (Header field name only; no field value.) 141 | * @return EXT value 142 | */ 143 | public String getExt() { 144 | return ext; 145 | } 146 | 147 | /** 148 | * Backwards compatibility with UPnP 1.0. (Header field name only; no field value.) 149 | * @param ext new value 150 | */ 151 | public void setExt(String ext) { 152 | this.ext = ext; 153 | } 154 | 155 | /** 156 | * Returns the bytes in the body 157 | * @return body length 158 | */ 159 | public String getContentLength() { 160 | return contentLength; 161 | } 162 | 163 | /** 164 | * Sets the byte length available in the body 165 | * @param contentLength 166 | */ 167 | public void setContentLength(String contentLength) { 168 | this.contentLength = contentLength; 169 | } 170 | 171 | /** 172 | * Returns the raw message if parsed with {@link com.jerabi.ssdp.message.helper.SSDPMessageHelper} 173 | * @return message not parsed 174 | */ 175 | public String getMessage() { 176 | return message; 177 | } 178 | 179 | /** 180 | * Sets the raw message if parsed with {@link com.jerabi.ssdp.message.helper.SSDPMessageHelper} 181 | * or for debugging 182 | * @param message original message not parsed 183 | */ 184 | public void setMessage(String message) { 185 | this.message = message; 186 | } 187 | 188 | /** 189 | * Returns the (USN) 190 | * @see com.jerabi.ssdp.message.USNInfo 191 | * @return (USN) Unique Service Name 192 | */ 193 | public String getUsn() { 194 | return usn; 195 | } 196 | 197 | /** 198 | * Sets the (USN) 199 | * @see com.jerabi.ssdp.message.USNInfo 200 | * @param usn Unique Service Name 201 | */ 202 | public void setUsn(String usn) { 203 | this.usn = usn; 204 | } 205 | 206 | /** 207 | * Returns the extra attributes for the message 208 | * @return extra attributes 209 | */ 210 | public List getAttributes() { 211 | return attributes; 212 | } 213 | 214 | /** 215 | * Sets extra attributes for the message 216 | * @param attributes 217 | */ 218 | public void setAttributes(List attributes) { 219 | this.attributes = attributes; 220 | } 221 | 222 | /** 223 | * {@inheritDoc} 224 | */ 225 | /* 226 | * @return a notify response from theses attributes 227 | */ 228 | public String toString(){ 229 | 230 | StringBuffer sb = new StringBuffer(); 231 | 232 | // the message is different based on the type 233 | 234 | sb.append(getNotify()).append("\r\n"); 235 | sb.append(SSDPContants.CACHECONTROL + " " + getCacheControl()).append("\r\n"); 236 | sb.append(SSDPContants.DATE + " " + getDate()).append("\r\n"); 237 | sb.append(SSDPContants.LOCATION + " " + getLocation()).append("\r\n"); 238 | sb.append(SSDPContants.SERVER + " " + getServer()).append("\r\n"); 239 | sb.append(SSDPContants.ST + " " + getSt()).append("\r\n"); 240 | sb.append(SSDPContants.EXT + " " + getExt()).append("\r\n"); 241 | sb.append(SSDPContants.USN + " " + getUsn()).append("\r\n"); 242 | sb.append(SSDPContants.CONTENTLENGTH + " " + getContentLength()).append("\r\n"); 243 | sb.append("\r\n"); 244 | 245 | return sb.toString(); 246 | } 247 | } 248 | -------------------------------------------------------------------------------- /ssdp-core/src/main/java/com/jerabi/ssdp/message/ISSDPMessage.java: -------------------------------------------------------------------------------- 1 | package com.jerabi.ssdp.message; 2 | 3 | /** 4 | * Interface for a ISSDMessage 5 | * 6 | * @author Sebastien Dionne 7 | * 8 | */ 9 | public interface ISSDPMessage { 10 | 11 | /** 12 | * Returns the message formatted 13 | * @return message formatted 14 | */ 15 | String toString(); 16 | 17 | } 18 | -------------------------------------------------------------------------------- /ssdp-core/src/main/java/com/jerabi/ssdp/message/ServiceInfo.java: -------------------------------------------------------------------------------- 1 | package com.jerabi.ssdp.message; 2 | 3 | 4 | /** 5 | * Represents a device/service for notification over the network. 6 | * 7 | * @author Sebastien Dionne 8 | * @example. 9 | *
 10 |  * new ServiceInfo(SSDPContants.DEFAULT_IP, 
 11 |  *                 SSDPContants.DEFAULT_PORT, 
 12 |  *                 "upnp:rootdevice",
 13 |  *                 "http://127.0.0.1:9000/config", 
 14 |  *                 new USNInfo("1acf6222-fc4b-33eb-bf49-e54643b4f416","upnp:rootdevice"));
 15 |  * 
16 | * @see com.jerabi.ssdp.message.helper.SSDPMessageHelper 17 | */ 18 | public class ServiceInfo implements Comparable { 19 | 20 | private String host; 21 | private int port; 22 | private String nt; 23 | private String location; 24 | private USNInfo usn; 25 | 26 | /** 27 | * Default constructor 28 | */ 29 | public ServiceInfo(){ 30 | 31 | } 32 | 33 | /** 34 | * Constructor with custom values 35 | * @param host multicast IP 36 | * @param port multicast Port 37 | * @param nt Notification Type (NT) 38 | * @param location URL on which the device will publish more information 39 | * @param usn Unique Service Name (USN) 40 | */ 41 | public ServiceInfo(String host, int port, String nt, String location, USNInfo usn){ 42 | this.host = host; 43 | this.port = port; 44 | this.nt = nt; 45 | this.location = location; 46 | this.usn = usn; 47 | } 48 | 49 | /** 50 | * Returns Notification Type (NT) 51 | * @return Notification Type 52 | */ 53 | public String getNt() { 54 | return nt; 55 | } 56 | 57 | /** 58 | * Sets Notification Type (NT) 59 | * @param nt 60 | */ 61 | public void setNt(String nt) { 62 | this.nt = nt; 63 | } 64 | 65 | /** 66 | * Returns the URL for retrieving more informations about the device. 67 | * The device most respond to this URL. 68 | * 69 | * @return device location 70 | */ 71 | public String getLocation() { 72 | return location; 73 | } 74 | 75 | /** 76 | * Sets the URL on which the device will publish more informations 77 | * @param location 78 | */ 79 | public void setLocation(String location) { 80 | this.location = location; 81 | } 82 | /** 83 | * Returns the (USN) 84 | * @return (USN) Unique Service Name 85 | */ 86 | public USNInfo getUsn() { 87 | return usn; 88 | } 89 | 90 | /** 91 | * Sets the (USN) 92 | * @param usn Unique Service Name 93 | */ 94 | public void setUsn(USNInfo usn) { 95 | this.usn = usn; 96 | } 97 | 98 | /** 99 | * Returns the host 100 | * @return host 101 | */ 102 | public String getHost() { 103 | return host; 104 | } 105 | 106 | /** 107 | * Sets the host 108 | * @param host 109 | */ 110 | public void setHost(String host) { 111 | this.host = host; 112 | } 113 | 114 | /** 115 | * Returns the listen port 116 | * @return port 117 | */ 118 | public int getPort() { 119 | return port; 120 | } 121 | 122 | /** 123 | * Sets the listen port 124 | * @param port 125 | */ 126 | public void setPort(int port) { 127 | this.port = port; 128 | } 129 | 130 | /** 131 | * Returns the root path of the location 132 | * @return "http://" + server + port(if present) 133 | */ 134 | public String getLocationPath(){ 135 | if(location==null){ 136 | return null; 137 | } 138 | 139 | String path = null; 140 | 141 | if(location.toLowerCase().startsWith("http://")){ 142 | int index = location.toLowerCase().indexOf("/", "http://".length()); 143 | 144 | if(index>0){ 145 | path = location.substring(index); 146 | } else { 147 | // if there isn't path, use blank 148 | // ex : http://localhost:8080 149 | path = ""; 150 | } 151 | 152 | } 153 | 154 | return path; 155 | } 156 | 157 | /** 158 | * {@inheritDoc} 159 | */ 160 | @Override 161 | public int hashCode() { 162 | final int prime = 31; 163 | int result = 1; 164 | result = prime * result + ((host == null) ? 0 : host.hashCode()); 165 | result = prime * result 166 | + ((location == null) ? 0 : location.hashCode()); 167 | result = prime * result + ((nt == null) ? 0 : nt.hashCode()); 168 | result = prime * result + port; 169 | result = prime * result + ((usn == null) ? 0 : usn.hashCode()); 170 | return result; 171 | } 172 | 173 | /** 174 | * {@inheritDoc} 175 | */ 176 | @Override 177 | public boolean equals(Object obj) { 178 | if (this == obj) 179 | return true; 180 | if (obj == null) 181 | return false; 182 | if (getClass() != obj.getClass()) 183 | return false; 184 | ServiceInfo other = (ServiceInfo) obj; 185 | if (host == null) { 186 | if (other.host != null) 187 | return false; 188 | } else if (!host.equals(other.host)) 189 | return false; 190 | if (location == null) { 191 | if (other.location != null) 192 | return false; 193 | } else if (!location.equals(other.location)) 194 | return false; 195 | if (nt == null) { 196 | if (other.nt != null) 197 | return false; 198 | } else if (!nt.equals(other.nt)) 199 | return false; 200 | if (port != other.port) 201 | return false; 202 | if (usn == null) { 203 | if (other.usn != null) 204 | return false; 205 | } else if (!usn.equals(other.usn)) 206 | return false; 207 | return true; 208 | } 209 | 210 | /** 211 | * @return Returns this ServiceInfo as a String 212 | */ 213 | public String toString(){ 214 | 215 | StringBuffer sb = new StringBuffer(); 216 | 217 | sb.append("host=").append(host).append("\n"); 218 | sb.append("port=").append(port).append("\n"); 219 | sb.append("nt=").append(nt).append("\n"); 220 | sb.append("location=").append(location).append("\n"); 221 | sb.append("usn=").append(usn).append("\n"); 222 | 223 | return sb.toString(); 224 | } 225 | 226 | /** 227 | * {@inheritDoc} 228 | */ 229 | @Override 230 | public int compareTo(ServiceInfo o) { 231 | return this.toString().compareToIgnoreCase(o.toString()); 232 | } 233 | 234 | } 235 | -------------------------------------------------------------------------------- /ssdp-core/src/main/java/com/jerabi/ssdp/message/USNInfo.java: -------------------------------------------------------------------------------- 1 | package com.jerabi.ssdp.message; 2 | 3 | /** 4 | * 5 | * Unique Service Name (USN) - An identifier that is unique across all 6 | * services for all time. It is used to uniquely identify a particular 7 | * service in order to allow services of identical service type to be 8 | * differentiated. 9 | *
 10 |  *  A USN is formed by two parts : UUID and URN and they are not mandatory.  
 11 |  *  
 12 |  *  UUID : Universally Unique Identifier {@link com.jerabi.ssdp.util.UUIDGenerator}
 13 |  *  URN  : Uniform Resource Name.
 14 |  *      
 15 |  *  A URN must respect this format : 
 16 | 
 17 |  *  urn:schemas-upnp-org:device:deviceType:ver
 18 |  *  or
 19 |  *  urn:domain-name:device:deviceType:ver
 20 |  *  
21 | *
 22 |  *  Example : 
 23 |  *  
 24 |  *     USN: uuid:9dcf6abc-fc5b-33eb-bf49-e54643b4f416::upnp:rootdevice
 25 |  *     USN: uuid:9dcf6abc-fc5b-33eb-bf49-e54643b4f416::urn:schemas-upnp-org:service:ContentDirectory:1
 26 |  *  
27 | * 28 | * @author Sebastien Dionne 29 | */ 30 | public class USNInfo implements Comparable { 31 | 32 | protected String uuid; 33 | protected String urn; 34 | 35 | /** 36 | * Constructor with from a USN 37 | * @param usn must contains a UUID and URN separated by "::" 38 | * @throws Exception 39 | */ 40 | public USNInfo(String usn) throws Exception { 41 | 42 | int separator = usn.indexOf("::"); 43 | 44 | if(separator<0){ 45 | throw new Exception("Invalid USN"); 46 | } 47 | 48 | uuid = usn.substring(0,separator); 49 | urn = usn.substring(separator+2); 50 | 51 | } 52 | 53 | /** 54 | * Constructor from UUID and URN. 55 | * The values can be null or empty 56 | * 57 | * @param uuid is not mandatory 58 | * @param urn is not mandatory 59 | */ 60 | public USNInfo(String uuid, String urn){ 61 | this.uuid = uuid; 62 | this.urn = urn; 63 | } 64 | 65 | /** 66 | * Returns UUID 67 | * @return uuid 68 | */ 69 | public String getUuid() { 70 | return uuid; 71 | } 72 | /** 73 | * Sets UUID 74 | * @param uuid new UUID 75 | */ 76 | public void setUuid(String uuid) { 77 | this.uuid = uuid; 78 | } 79 | /** 80 | * Returns URN 81 | * @return urn 82 | */ 83 | public String getUrn() { 84 | return urn; 85 | } 86 | /** 87 | * Sets URN 88 | * @param urn new URN 89 | */ 90 | public void setUrn(String urn) { 91 | this.urn = urn; 92 | } 93 | 94 | /** 95 | * Returns a USN from UUID and URN. 96 | * If URN is not null or empty, the USN will contains "::" as separator 97 | * @return usn 98 | */ 99 | public String toString(){ 100 | // be sure that uuid doesn't already contains uuid: 101 | String uuidValue = uuid; 102 | if(uuid==null || !uuid.toLowerCase().startsWith("uuid:")){ 103 | uuidValue = "uuid:" + uuidValue; 104 | } 105 | 106 | if(urn!=null && urn.length()>0){ 107 | return uuidValue + "::" + urn; 108 | } else { 109 | return uuidValue; 110 | } 111 | } 112 | 113 | /** 114 | * {@inheritDoc} 115 | */ 116 | @Override 117 | public int hashCode() { 118 | final int prime = 31; 119 | int result = 1; 120 | result = prime * result + ((urn == null) ? 0 : urn.hashCode()); 121 | result = prime * result + ((uuid == null) ? 0 : uuid.hashCode()); 122 | return result; 123 | } 124 | 125 | /** 126 | * {@inheritDoc} 127 | */ 128 | @Override 129 | public boolean equals(Object obj) { 130 | if (this == obj) 131 | return true; 132 | if (obj == null) 133 | return false; 134 | if (getClass() != obj.getClass()) 135 | return false; 136 | USNInfo other = (USNInfo) obj; 137 | if (urn == null) { 138 | if (other.urn != null) 139 | return false; 140 | } else if (!urn.equals(other.urn)) 141 | return false; 142 | if (uuid == null) { 143 | if (other.uuid != null) 144 | return false; 145 | } else if (!uuid.equals(other.uuid)) 146 | return false; 147 | return true; 148 | } 149 | 150 | /** 151 | * {@inheritDoc} 152 | */ 153 | @Override 154 | public int compareTo(USNInfo obj) { 155 | return this.toString().compareToIgnoreCase(obj.toString()); 156 | } 157 | 158 | } 159 | -------------------------------------------------------------------------------- /ssdp-core/src/main/java/com/jerabi/ssdp/message/UpdateMessage.java: -------------------------------------------------------------------------------- 1 | package com.jerabi.ssdp.message; 2 | 3 | import com.jerabi.ssdp.util.SSDPContants; 4 | 5 | /** 6 | * 7 | * Represents a ssdp:update message. This message is sent 8 | * when the device changes. When a client receive this message, 9 | * it must refresh his data on the device. 10 | * 11 | * @author Sebastien Dionne 12 | * @example. 13 | *
 14 |  *   NOTIFY * HTTP/1.1
 15 |  *   HOST: 239.255.255.250:1900
 16 |  *   NT: urn:schemas-upnp-org:service:ContentDirectory:1
 17 |  *   NTS: ssdp:update
 18 |  *   LOCATION: http://142.225.35.55:5001/description/fetch
 19 |  *   USN: uuid:9dcf6222-fc4b-33eb-bf49-e54643b4f416::urn:schemas-upnp-org:service:ContentDirectory:1
 20 |  *   CACHE-CONTROL: max-age=1800
 21 |  *   SERVER: Windows_XP-x86-5.1, UPnP/1.0, PMS/1.11
 22 |  *   
23 | * 24 | * @see AbstractSSDPNotifyMessage 25 | */ 26 | public class UpdateMessage extends AbstractSSDPNotifyMessage { 27 | 28 | /** 29 | * First line of the message 30 | */ 31 | public static final String notify = "NOTIFY * HTTP/1.1"; 32 | 33 | /** 34 | * NTS value 35 | */ 36 | public static final String nts = SSDPContants.NTS_UPDATE; 37 | 38 | protected String cacheControl; 39 | protected String location; 40 | protected String server; 41 | 42 | /** 43 | * {@inheritDoc} 44 | */ 45 | @Override 46 | public String getNts() { 47 | return nts; 48 | } 49 | 50 | /** 51 | * Returns a duration for which the advertisement is valid 52 | * @return cache-control value 53 | */ 54 | public String getCacheControl() { 55 | return cacheControl; 56 | } 57 | 58 | /** 59 | * Sets the duration for which the advertisement is valid 60 | * @param cacheControl 61 | */ 62 | public void setCacheControl(String cacheControl) { 63 | this.cacheControl = cacheControl; 64 | } 65 | 66 | /** 67 | * Returns the URL for retrieving more information about the device. 68 | * The device most respond to this URL. 69 | * 70 | * @return device location 71 | */ 72 | public String getLocation() { 73 | return location; 74 | } 75 | 76 | /** 77 | * Sets the URL on which the device will publish more information 78 | * @param location 79 | */ 80 | public void setLocation(String location) { 81 | this.location = location; 82 | } 83 | 84 | /** 85 | * Returns the server informations. 86 | * Format is : OS/version, UPnP/version, product/version 87 | * @return server informations 88 | */ 89 | public String getServer() { 90 | return server; 91 | } 92 | 93 | /** 94 | * Sets the server informations. 95 | * Format must be : OS/version, UPnP/version, product/version 96 | * @param server informations 97 | */ 98 | public void setServer(String server) { 99 | this.server = server; 100 | } 101 | 102 | /** 103 | * {@inheritDoc} 104 | */ 105 | @Override 106 | public String toString() { 107 | StringBuffer sb = new StringBuffer(); 108 | 109 | sb.append(getNotify()).append("\r\n"); 110 | sb.append(SSDPContants.HOST + " " + getHost()).append("\r\n"); 111 | sb.append(SSDPContants.NT + " " + getNt()).append("\r\n"); 112 | sb.append(SSDPContants.NTS + " " + getNts()).append("\r\n"); 113 | sb.append(SSDPContants.LOCATION + " " + getLocation()).append("\r\n"); 114 | sb.append(SSDPContants.USN + " " + getUsn()).append("\r\n"); 115 | sb.append(SSDPContants.CACHECONTROL + " " + getCacheControl()).append("\r\n"); 116 | sb.append(SSDPContants.SERVER + " " + getServer()).append("\r\n"); 117 | sb.append("\r\n"); 118 | 119 | return sb.toString(); 120 | } 121 | 122 | } 123 | -------------------------------------------------------------------------------- /ssdp-core/src/main/java/com/jerabi/ssdp/message/helper/SSDPMessageHelper.java: -------------------------------------------------------------------------------- 1 | package com.jerabi.ssdp.message.helper; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.logging.Logger; 6 | 7 | import com.jerabi.ssdp.message.AbstractSSDPNotifyMessage; 8 | import com.jerabi.ssdp.message.AliveMessage; 9 | import com.jerabi.ssdp.message.ByeByeMessage; 10 | import com.jerabi.ssdp.message.DiscoverMessage; 11 | import com.jerabi.ssdp.message.DiscoverResponseMessage; 12 | import com.jerabi.ssdp.message.ISSDPMessage; 13 | import com.jerabi.ssdp.message.ServiceInfo; 14 | import com.jerabi.ssdp.message.UpdateMessage; 15 | import com.jerabi.ssdp.util.SSDPContants; 16 | 17 | /** 18 | * This helper provides API to create and parse {@link ISSDPMessage}. 19 | * 20 | * You can create a ISSDPMessage using a {@link ServiceInfo}. 21 | * 22 | * @example. 23 | *
 24 |  * //You could received a message over the network and want to convert it to ISSDPMessage.
 25 |  * 
 26 |  * StringBuffer sb = new StringBuffer();
 27 |  * sb.append("HTTP/1.1 200 OK").append("\n");
 28 |  * sb.append("CACHE-CONTROL: max-age=1200").append("\n");
 29 |  * sb.append("DATE: Tue, 05 May 2009 13:31:51 GMT").append("\n");
 30 |  * sb.append("LOCATION: http://142.225.35.55:5001/description/fetch").append("\n");
 31 |  * sb.append("SERVER: Windows_XP-x86-5.1, UPnP/1.0, PMS/1.11").append("\n");
 32 |  * sb.append("ST: upnp:rootdevice").append("\n");
 33 |  * sb.append("EXT: ").append("\n");
 34 |  * sb.append("USN: uuid:9dcf6222-fc4b-33eb-bf49-e54643b4f416::upnp:rootdevice").append("\n");
 35 |  * sb.append("Content-Length: 0").append("\n");
 36 |  *	
 37 |  * ISSDPMessage message = SSDPMessageHelper.getSSDPMessage(sb.toString());
 38 |  *	
39 | * @author Sebastien Dionne 40 | * 41 | * @see AliveMessage 42 | * @see ByeByeMessage 43 | * @see DiscoverMessage 44 | * @see DiscoverResponseMessage 45 | * @see UpdateMessage 46 | */ 47 | public class SSDPMessageHelper { 48 | 49 | private static final Logger logger = Logger.getLogger(SSDPMessageHelper.class.getName()); 50 | 51 | 52 | /** 53 | * Parse the message and returns a ISSDPMessage if the message is supported. 54 | * If the message is not recognized a null value will be return. 55 | * 56 | * Some extra attributes could be received within the message. Even if there are not 57 | * part of the SSDP specs, and they be parsed and kept into the property : Attributes. 58 | * 59 | * @param message message to parse 60 | * @return ISSDPMessage if a valid message is received or null if it's a unknown format 61 | */ 62 | public static ISSDPMessage getSSDPMessage(String message){ 63 | 64 | if(message==null || message.trim().length()==0){ 65 | return null; 66 | } 67 | 68 | String[] split = message.split("\n"); 69 | 70 | String notify = null; 71 | String cacheControl = null; 72 | String date = null; 73 | String location = null; 74 | String server = null; 75 | String st = null; 76 | String ext = null; 77 | String usn = null; 78 | String contentLength = null; 79 | String host = null; 80 | String port = null; 81 | String nt = null; 82 | String nts = null; 83 | String mx = null; 84 | @SuppressWarnings("unused") 85 | String man = null; 86 | List othersAttributes = new ArrayList(); 87 | 88 | for (int i = 0; i < split.length; i++) { 89 | 90 | String line = split[i]; 91 | 92 | if(i==0){ 93 | notify = line.trim(); 94 | } else if(line.toUpperCase().startsWith(SSDPContants.CACHECONTROL)){ 95 | cacheControl = line.substring(SSDPContants.CACHECONTROL.length()).trim(); 96 | } else if(line.toUpperCase().startsWith(SSDPContants.DATE)){ 97 | date = line.substring(SSDPContants.DATE.length()).trim(); 98 | } else if(line.toUpperCase().startsWith(SSDPContants.LOCATION)){ 99 | location = line.substring(SSDPContants.LOCATION.length()).trim(); 100 | } else if(line.toUpperCase().startsWith(SSDPContants.SERVER)){ 101 | server = line.substring(SSDPContants.SERVER.length()).trim(); 102 | } else if(line.toUpperCase().startsWith(SSDPContants.ST)){ 103 | st = line.substring(SSDPContants.ST.length()).trim(); 104 | } else if(line.toUpperCase().startsWith(SSDPContants.EXT)){ 105 | ext = line.substring(SSDPContants.EXT.length()).trim(); 106 | } else if(line.toUpperCase().startsWith(SSDPContants.USN)){ 107 | usn = line.substring(SSDPContants.USN.length()).trim(); 108 | } else if(line.toUpperCase().startsWith(SSDPContants.CONTENTLENGTH)){ 109 | contentLength = line.substring(SSDPContants.CONTENTLENGTH.length()).trim(); 110 | } else if(line.toUpperCase().startsWith(SSDPContants.HOST)){ 111 | host = line.substring(SSDPContants.HOST.length()).trim(); 112 | 113 | // extract port if found 114 | int portIndex = host.indexOf(":"); 115 | if(portIndex>0){ 116 | port = host.substring(portIndex+1); 117 | host = host.substring(0,portIndex); 118 | } else { 119 | // use default port 120 | port = Integer.toString(SSDPContants.DEFAULT_PORT); 121 | } 122 | 123 | } else if(line.toUpperCase().startsWith(SSDPContants.NT)){ 124 | nt = line.substring(SSDPContants.NT.length()).trim(); 125 | } else if(line.toUpperCase().startsWith(SSDPContants.NTS)){ 126 | nts = line.substring(SSDPContants.NTS.length()).trim(); 127 | } else if(line.toUpperCase().startsWith(SSDPContants.MX)){ 128 | mx = line.substring(SSDPContants.MX.length()).trim(); 129 | } else if(line.toUpperCase().startsWith(SSDPContants.MAN)){ 130 | man = line.substring(SSDPContants.MAN.length()).trim(); 131 | } else { 132 | othersAttributes.add(line); 133 | } 134 | 135 | } 136 | 137 | // is it a M-SEARCH ? 138 | if(notify!=null && notify.toUpperCase().startsWith("M-SEARCH")){ 139 | 140 | DiscoverMessage ssdpMessage = new DiscoverMessage(); 141 | 142 | ssdpMessage.setMessage(message); 143 | ssdpMessage.setHost(host); 144 | ssdpMessage.setPort(port); 145 | ssdpMessage.setMx(mx); 146 | ssdpMessage.setSt(st); 147 | ssdpMessage.setAttributes(othersAttributes); 148 | 149 | return ssdpMessage; 150 | 151 | } else if(notify!=null && notify.equalsIgnoreCase("HTTP/1.1 200 OK")){ 152 | // probably a M-SEARCH response 153 | DiscoverResponseMessage ssdpMessage = new DiscoverResponseMessage(); 154 | 155 | ssdpMessage.setMessage(message); 156 | //ssdpMessage.setNotify(notify); 157 | ssdpMessage.setCacheControl(cacheControl); 158 | ssdpMessage.setDate(date); 159 | ssdpMessage.setLocation(location); 160 | ssdpMessage.setServer(server); 161 | ssdpMessage.setSt(st); 162 | ssdpMessage.setExt(ext); 163 | ssdpMessage.setUsn(usn); 164 | ssdpMessage.setContentLength(contentLength); 165 | ssdpMessage.setAttributes(othersAttributes); 166 | 167 | return ssdpMessage; 168 | } else if(nts!=null && nts.trim().length()>0){ 169 | // assign values now 170 | 171 | AbstractSSDPNotifyMessage ssdpMessage = null; 172 | 173 | if(SSDPContants.NTS_ALIVE.equals(nts)){ 174 | ssdpMessage = new AliveMessage(); 175 | 176 | ((AliveMessage)ssdpMessage ).setCacheControl(cacheControl); 177 | ((AliveMessage)ssdpMessage ).setLocation(location); 178 | ((AliveMessage)ssdpMessage ).setServer(server); 179 | 180 | } else if(SSDPContants.NTS_UPDATE.equals(nts)){ 181 | ssdpMessage = new UpdateMessage(); 182 | 183 | ((UpdateMessage)ssdpMessage ).setCacheControl(cacheControl); 184 | ((UpdateMessage)ssdpMessage ).setLocation(location); 185 | ((UpdateMessage)ssdpMessage ).setServer(server); 186 | 187 | } else if(SSDPContants.NTS_BYEBYE.equals(nts)){ 188 | ssdpMessage = new ByeByeMessage(); 189 | 190 | ((ByeByeMessage)ssdpMessage ).setContentLength(contentLength); 191 | 192 | } else { 193 | logger.info("SSDPNotifyMessage not reconized : \n" + message); 194 | return null; 195 | } 196 | // commons fields 197 | 198 | ssdpMessage.setMessage(message); 199 | ssdpMessage.setNotify(notify); 200 | ssdpMessage.setHost(host); 201 | ssdpMessage.setPort(port); 202 | ssdpMessage.setNt(nt); 203 | ssdpMessage.setNts(nts); 204 | ssdpMessage.setUsn(usn); 205 | ssdpMessage.setAttributes(othersAttributes); 206 | 207 | return ssdpMessage; 208 | } else { 209 | logger.finest("Message not recognized : \n" + message); 210 | } 211 | 212 | return null; 213 | } 214 | 215 | /** 216 | * Creates a {@link AliveMessage} from a {@link ServiceInfo}. 217 | * 218 | * @param deviceInfo info on your device 219 | * @return AliveMessage 220 | */ 221 | public static AliveMessage createSSDPAliveMessage(ServiceInfo deviceInfo) { 222 | AliveMessage message = new AliveMessage(); 223 | 224 | message.setNotify(AliveMessage.notify); 225 | message.setHost(deviceInfo.getHost() + ":" + deviceInfo.getPort()); 226 | message.setNts(AliveMessage.nts); 227 | message.setNt(deviceInfo.getNt()); 228 | message.setLocation(deviceInfo.getLocation()); 229 | message.setUsn(deviceInfo.getUsn().toString()); 230 | 231 | return message; 232 | } 233 | 234 | /** 235 | * Creates a {@link UpdateMessage} from a {@link ServiceInfo}. 236 | * 237 | * @param deviceInfo info on your device 238 | * @return UpdateMessage 239 | */ 240 | public static UpdateMessage createSSDPUpdateMessage(ServiceInfo deviceInfo) { 241 | UpdateMessage message = new UpdateMessage(); 242 | 243 | message.setNotify(UpdateMessage.notify); 244 | message.setHost(deviceInfo.getHost() + ":" + deviceInfo.getPort()); 245 | message.setNts(UpdateMessage.nts); 246 | message.setNt(deviceInfo.getNt()); 247 | message.setUsn(deviceInfo.getUsn().toString()); 248 | 249 | return message; 250 | } 251 | 252 | /** 253 | * Creates a {@link ByeByeMessage} from a {@link ServiceInfo}. 254 | * 255 | * @param deviceInfo info on your device 256 | * @return ByeByeMessage 257 | */ 258 | public static ByeByeMessage createSSDPByeByeMessage(ServiceInfo deviceInfo) { 259 | ByeByeMessage message = new ByeByeMessage(); 260 | 261 | message.setNotify(ByeByeMessage.notify); 262 | message.setHost(deviceInfo.getHost() + ":" + deviceInfo.getPort()); 263 | message.setNts(ByeByeMessage.nts); 264 | message.setNt(deviceInfo.getNt()); 265 | message.setUsn(deviceInfo.getUsn().toString()); 266 | 267 | return message; 268 | } 269 | 270 | /** 271 | * Creates a {@link DiscoverMessage} from the info on your device. 272 | * 273 | * @param host on which host the device is located 274 | * @param port on which port the device is listening 275 | * @param ttl the time to live value 276 | * @param device device URN ex : urn:schemas-upnp-org:device:MediaServer:1 277 | * @param attributes add extra attributes on the message 278 | * @return DiscoverMessage 279 | */ 280 | public static DiscoverMessage createSSDPDiscoverMessage(String host, int port, int ttl, String device, List attributes) { 281 | DiscoverMessage message = new DiscoverMessage(host, port, ttl, device, attributes); 282 | 283 | return message; 284 | } 285 | 286 | } 287 | -------------------------------------------------------------------------------- /ssdp-core/src/main/java/com/jerabi/ssdp/network/IMulticastListener.java: -------------------------------------------------------------------------------- 1 | package com.jerabi.ssdp.network; 2 | 3 | import java.net.InetAddress; 4 | import java.net.NetworkInterface; 5 | import java.net.SocketAddress; 6 | 7 | /** 8 | * Provides API to listen for incoming multicast UDP, with additional capabilities for 9 | * joining "groups" of other multicast hosts on the Internet. 10 | * 11 | * A multicast group is specified by a class D IP address 12 | * and by a standard UDP port number. Class D IP addresses 13 | * are in the range 224.0.0.0 to 239.255.255.255, 14 | * inclusive. The address 224.0.0.0 is reserved and should not be used. 15 | * 16 | * To join a multicast group you need to invoke joinGroup(InetAddress groupAddr). 17 | * To leave a multicast group you need to invoke leaveGroup(InetAddress groupAddr). 18 | * 19 | * When a multicast message is sent, all the subscribers will receive the message (within the ttl range). 20 | * 21 | * It's possible to send a multicast message without the needs to join a group. 22 | * 23 | * @author Sebastien Dionne 24 | * 25 | * @example. 26 | * 27 | * 28 | */ 29 | public interface IMulticastListener { 30 | 31 | /** 32 | * Reads for incoming message. This method use the default timeout. 33 | * If you need a blocking reader look {@link #receive(boolean)} 34 | * @throws Exception 35 | */ 36 | void receive() throws Exception; 37 | 38 | 39 | /** 40 | * Reads for incoming message. This method is blocking until a message is received. 41 | * If you need a non blocking reader look {@link #receive()} 42 | * 43 | * @param blocking in blocking mode is set to true 44 | * @throws Exception 45 | */ 46 | void receive(boolean blocking) throws Exception; 47 | 48 | /** 49 | * Joins a multicast group 50 | * @param group the new to join 51 | * @throws Exception 52 | */ 53 | void joinGroup(InetAddress group) throws Exception; 54 | 55 | /** 56 | * Leaves a multicast group 57 | * @param group group to leave 58 | * @throws Exception 59 | */ 60 | void leaveGroup(InetAddress group) throws Exception; 61 | 62 | /** 63 | * Joins a multicast group 64 | * @param socketAddress the new to join 65 | * @param ni NetworkInterface that will be used. 66 | * @throws Exception 67 | */ 68 | void joinGroup(SocketAddress socketAddress, NetworkInterface ni) throws Exception; 69 | 70 | /** 71 | * Leaves a multicast group 72 | * @param socketAddress the new to join 73 | * @param ni NetworkInterface that will be used. 74 | * @throws Exception 75 | */ 76 | void leaveGroup(SocketAddress socketAddress, NetworkInterface ni) throws Exception; 77 | 78 | /** 79 | * Sets the timeout for non blocking socket 80 | * @param timeout value in ms. 81 | */ 82 | void setTimeout(int timeout); 83 | 84 | /** 85 | * Returns the timeout for non blocking socket 86 | * @return timeout value in ms. 87 | */ 88 | int getTimeout(); 89 | 90 | } 91 | -------------------------------------------------------------------------------- /ssdp-core/src/main/java/com/jerabi/ssdp/network/ISSDPNetwork.java: -------------------------------------------------------------------------------- 1 | package com.jerabi.ssdp.network; 2 | 3 | import java.net.InetAddress; 4 | import java.net.NetworkInterface; 5 | import java.net.SocketAddress; 6 | 7 | import com.jerabi.ssdp.handler.ISSDPResponseHandler; 8 | 9 | /** 10 | * 11 | * Provides API for sending and receiving messages over network. 12 | * 13 | * @author Sebastien Dionne 14 | */ 15 | public interface ISSDPNetwork { 16 | 17 | 18 | // SSDPPeriodicMessageSender -> 19 | /** 20 | * Sends a multicast UDP message without the needs to join a group. 21 | * 22 | * The multicast addresses are in the range 224.0.0.0 to 239.255.255.255, 23 | * inclusive. The address 224.0.0.0 is reserved and should not be used. 24 | * 25 | * @param message message to send 26 | * @param address destination address 27 | * @throws Exception 28 | */ 29 | void sendMulticastMessage(String message, SocketAddress address) throws Exception; 30 | 31 | /** 32 | * Sends a multicast UDP message without the needs to join a group. 33 | * 34 | * The multicast addresses are in the range 224.0.0.0 to 239.255.255.255, 35 | * inclusive. The address 224.0.0.0 is reserved and should not be used. 36 | * 37 | * @param message message to send 38 | * @param address destination address 39 | * @param ni NetworkInterface that will be used. 40 | * @throws Exception 41 | */ 42 | void sendMulticastMessage(String message, SocketAddress address, NetworkInterface ni) throws Exception; 43 | 44 | /** 45 | * 46 | * Sends a multicast UDP message 47 | * 48 | * The multicast addresses are in the range 224.0.0.0 to 239.255.255.255, 49 | * inclusive. The address 224.0.0.0 is reserved and should not be used. 50 | * 51 | * @param message message to send 52 | * @param address destination address 53 | * @param port destination port 54 | * @throws Exception 55 | */ 56 | void sendMulticastMessage(String message, InetAddress address, int port) throws Exception; 57 | 58 | /** 59 | * 60 | * Sends a multicast UDP message and wait for a response. TTL defines the timeout for the response. 61 | * If a response is received, it will be forward to the callback {@link ISSDPResponseHandler}. 62 | * 63 | * The multicast addresses are in the range 224.0.0.0 to 239.255.255.255, 64 | * inclusive. The address 224.0.0.0 is reserved and should not be used. 65 | * 66 | * @param message message to send 67 | * @param address destination address 68 | * @param callbackHandler handle the response 69 | * @param ttl Time to live (timeout) 70 | * @throws Exception 71 | */ 72 | void sendMulticastMessage(String message, SocketAddress address, ISSDPResponseHandler callbackHandler, int ttl) throws Exception; 73 | 74 | /** 75 | * 76 | * Sends a multicast UDP message and wait for a response. TTL defines the timeout for the response. 77 | * If a response is received, it will be forward to the callback {@link ISSDPResponseHandler}. 78 | * 79 | * The multicast addresses are in the range 224.0.0.0 to 239.255.255.255, 80 | * inclusive. The address 224.0.0.0 is reserved and should not be used. 81 | * 82 | * @param message message to send 83 | * @param address destination address 84 | * @param port destination port 85 | * @param callbackHandler handle the response 86 | * @param ttl Time to live (timeout) 87 | * @throws Exception 88 | */ 89 | void sendMulticastMessage(String message, InetAddress address, int port, ISSDPResponseHandler callbackHandler, int ttl) throws Exception; 90 | 91 | // SSDPDiscoverSender -> <- 92 | /** 93 | * Creates a {@link IUDPSender} instance. 94 | * @return IUDPSender 95 | * @throws Exception 96 | */ 97 | IUDPSender createUDPSender() throws Exception; 98 | 99 | /** 100 | * Creates a {@link IUDPSender} instance. 101 | * 102 | * @param port port that will be used 103 | * @return IUDPSender 104 | * @throws Exception 105 | */ 106 | IUDPSender createUDPSender(int port) throws Exception; 107 | 108 | // SSDPMulticastListener <- 109 | /** 110 | * Creates a {@link IMulticastListener} instance. 111 | * 112 | * @param port listening port 113 | * @param callbackHandler handle the response 114 | * @return IMulticastListener 115 | * @throws Exception 116 | */ 117 | IMulticastListener createMulticastListener(int port, ISSDPResponseHandler callbackHandler) throws Exception; 118 | 119 | /** 120 | * Creates a {@link IMulticastListener} instance. 121 | * 122 | * @param bindAddress listening address 123 | * @param callbackHandler handle the response 124 | * @return IMulticastListener 125 | * @throws Exception 126 | */ 127 | IMulticastListener createMulticastListener(SocketAddress bindAddress, ISSDPResponseHandler callbackHandler) throws Exception; 128 | 129 | /** 130 | * Creates a {@link IMulticastListener} instance. 131 | * 132 | * @param bindAddress listening address 133 | * @param callbackHandler handle the response 134 | * @param ni NetworkInterface that will be used. 135 | * @return IMulticastListener 136 | * @throws Exception 137 | */ 138 | IMulticastListener createMulticastListener(SocketAddress bindAddress, ISSDPResponseHandler callbackHandler, NetworkInterface ni) throws Exception; 139 | 140 | 141 | } 142 | -------------------------------------------------------------------------------- /ssdp-core/src/main/java/com/jerabi/ssdp/network/IUDPSender.java: -------------------------------------------------------------------------------- 1 | package com.jerabi.ssdp.network; 2 | 3 | import java.net.InetAddress; 4 | import java.net.SocketAddress; 5 | 6 | import com.jerabi.ssdp.handler.ISSDPResponseHandler; 7 | 8 | /** 9 | * Provides API for sending and receiving UDP messages over network. 10 | * 11 | * This sender will not send multicast UDP. If you need multicast UDP look {@link ISSDPNetwork}. 12 | * 13 | * @author Sebastien Dionne 14 | */ 15 | public interface IUDPSender { 16 | 17 | /** 18 | * Sends a UDP message and wait for a response. TTL defines the timeout for the response. 19 | * If a response is received, it will be forward to the callback {@link ISSDPResponseHandler}. 20 | * 21 | * @param message message to send 22 | * @param address destination address 23 | * @param callbackHandler handle the response 24 | * @param ttl Time to live (timeout) 25 | * @throws Exception 26 | */ 27 | void sendMessage(String message, SocketAddress address, ISSDPResponseHandler callbackHandler, int ttl) throws Exception; 28 | 29 | /** 30 | * Sends a UDP message and wait for a response. TTL defines the timeout for the response. 31 | * If a response is received, it will be forward to the callback {@link ISSDPResponseHandler}. 32 | * 33 | * @param message message to send 34 | * @param address destination address 35 | * @param port destination port 36 | * @param callbackHandler handle the response 37 | * @param ttl Time to live (timeout) 38 | * @throws Exception 39 | */ 40 | void sendMessage(String message, InetAddress address, int port, ISSDPResponseHandler callbackHandler, int ttl) throws Exception; 41 | 42 | } 43 | -------------------------------------------------------------------------------- /ssdp-core/src/main/java/com/jerabi/ssdp/network/SSDPNetworkFactory.java: -------------------------------------------------------------------------------- 1 | package com.jerabi.ssdp.network; 2 | 3 | import java.lang.reflect.InvocationTargetException; 4 | 5 | 6 | /** 7 | * 8 | * Provides API for sending and receiving messages over network. 9 | * 10 | * This class is a dummy that doesn't implements any methods. 11 | * It used for compilation purpose. An implementation must be 12 | * available in another package. 13 | * 14 | * @author Sebastien Dionne 15 | * 16 | */ 17 | public class SSDPNetworkFactory { 18 | 19 | private static final String DEFAULT_IMPL = "com.jerabi.ssdp.network.impl.SSDPNetworkImpl"; 20 | private static ISSDPNetwork instance = null; 21 | 22 | /** 23 | * Private Constructor. You need to use getInstance() 24 | * @see #getInstance() 25 | */ 26 | private SSDPNetworkFactory(){} 27 | 28 | /** 29 | * Returns a ISSDPNetwork instance. 30 | * 31 | * @return ISSDPNetwork 32 | * @throws ClassNotFoundException 33 | * @throws IllegalAccessException 34 | * @throws InstantiationException 35 | * @throws InvocationTargetException 36 | * @throws IllegalArgumentException 37 | * @throws SecurityException 38 | * @throws NoSuchMethodException 39 | */ 40 | public static ISSDPNetwork getInstance() throws InstantiationException, IllegalAccessException, ClassNotFoundException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException { 41 | 42 | if(instance==null){ 43 | instance = (ISSDPNetwork) Class.forName(DEFAULT_IMPL).newInstance(); 44 | } 45 | 46 | return instance; 47 | 48 | } 49 | 50 | 51 | } 52 | -------------------------------------------------------------------------------- /ssdp-core/src/main/java/com/jerabi/ssdp/sender/AliveMessageSender.java: -------------------------------------------------------------------------------- 1 | package com.jerabi.ssdp.sender; 2 | 3 | import java.net.NetworkInterface; 4 | import java.util.ArrayList; 5 | import java.util.List; 6 | 7 | import com.jerabi.ssdp.ISSDPControler; 8 | import com.jerabi.ssdp.message.AliveMessage; 9 | import com.jerabi.ssdp.message.ISSDPMessage; 10 | import com.jerabi.ssdp.message.ServiceInfo; 11 | import com.jerabi.ssdp.message.helper.SSDPMessageHelper; 12 | 13 | /** 14 | * This class is a Sender that sends periodically {@link AliveMessage} and doesn't handle responses. If 15 | * a response is required, you will have to override {@link #sendMessage(String)}. 16 | * 17 | * This class is a implementation of {@link SSDPDefaultPeriodicMessageSender}. 18 | * 19 | * Once this sender is stopped it can't be restarted. You need to create a new instance. 20 | * 21 | * This sender will send the message and enter in sleep mode for the delay used and return to started mode until 22 | * the sender is stopped by the controller. 23 | * 24 | * 25 | * @author Sebastien Dionne 26 | * @example. 27 | *
 28 |  * 
 29 |  *  // a simple example that will send 5 times the same message each time.
 30 |  * ...
 31 |  * sender = new AliveMessageSender(controler, SSDPContants.DEFAULT_IP, SSDPContants.DEFAULT_PORT, SSDPContants.DEFAULT_DELAY, "max-age=1800", "Demo Server", 5);
 32 |  * 		
 33 |  * 	...
 34 |  * 
35 | * 36 | * 37 | */ 38 | public class AliveMessageSender extends SSDPDefaultPeriodicMessageSender { 39 | 40 | protected String cacheControl = ""; 41 | protected String serverName = ""; 42 | protected int multipleTimeToSend = 1; 43 | 44 | /** 45 | * Constructor that will use the default delay see com.jerabi.ssdp.util.SSDPContants.DEFAULT_DELAY value 46 | * @param controler ISSDPControler 47 | * @param ssdpHost multicast IP 48 | * @param ssdpPort multicast port 49 | * @param cacheControl cache-control value 50 | * @param serverName the name or description of the server 51 | */ 52 | public AliveMessageSender(ISSDPControler controler, String ssdpHost, int ssdpPort, String cacheControl, String serverName) { 53 | super(controler, ssdpHost, ssdpPort); 54 | this.cacheControl = cacheControl; 55 | this.serverName = serverName; 56 | } 57 | 58 | /** 59 | * Constructor that will use the default delay see com.jerabi.ssdp.util.SSDPContants.DEFAULT_DELAY value 60 | * @param controler ISSDPControler 61 | * @param ssdpHost multicast IP 62 | * @param ssdpPort multicast port 63 | * @param cacheControl cache-control value 64 | * @param serverName the name or description of the server 65 | * @param multipleTimeToSend number time each messages will be sent each time 66 | */ 67 | public AliveMessageSender(ISSDPControler controler, String ssdpHost, int ssdpPort, String cacheControl, String serverName, int multipleTimeToSend) { 68 | super(controler, ssdpHost, ssdpPort); 69 | this.cacheControl = cacheControl; 70 | this.serverName = serverName; 71 | this.multipleTimeToSend = multipleTimeToSend; 72 | } 73 | 74 | /** 75 | * Constructor with a custom default delay in ms. 76 | * @param controler ISSDPControler 77 | * @param ssdpHost multicast IP 78 | * @param ssdpPort multicast port 79 | * @param delay delay before the next batch of messages are sent 80 | * @param cacheControl cache-control value 81 | * @param serverName the name or description of the server 82 | */ 83 | public AliveMessageSender(ISSDPControler controler, String ssdpHost, int ssdpPort, int delay, String cacheControl, String serverName) { 84 | super(controler, ssdpHost, ssdpPort, delay); 85 | this.cacheControl = cacheControl; 86 | this.serverName = serverName; 87 | } 88 | 89 | /** 90 | * Constructor with a custom default delay in ms. 91 | * @param controler ISSDPControler 92 | * @param ssdpHost multicast IP 93 | * @param ssdpPort multicast port 94 | * @param delay delay before the next batch of messages are sent 95 | * @param cacheControl cache-control value 96 | * @param serverName the name or description of the server 97 | * @param multipleTimeToSend number time each messages will be sent each time 98 | */ 99 | public AliveMessageSender(ISSDPControler controler, String ssdpHost, int ssdpPort, int delay, String cacheControl, String serverName, int multipleTimeToSend) { 100 | super(controler, ssdpHost, ssdpPort, delay); 101 | this.cacheControl = cacheControl; 102 | this.serverName = serverName; 103 | this.multipleTimeToSend = multipleTimeToSend; 104 | } 105 | 106 | /** 107 | * Constructor that will use the default delay see com.jerabi.ssdp.util.SSDPContants.DEFAULT_DELAY value 108 | * @param controler ISSDPControler 109 | * @param ssdpHost multicast IP 110 | * @param ssdpPort multicast port 111 | * @param cacheControl cache-control value 112 | * @param serverName the name or description of the server 113 | * @param networkInterfaceList NetworkInterfaces that will be used 114 | */ 115 | public AliveMessageSender(ISSDPControler controler, String ssdpHost, int ssdpPort, String cacheControl, String serverName, List networkInterfaceList) { 116 | super(controler, ssdpHost, ssdpPort, networkInterfaceList); 117 | this.cacheControl = cacheControl; 118 | this.serverName = serverName; 119 | } 120 | 121 | /** 122 | * Constructor that will use the default delay see com.jerabi.ssdp.util.SSDPContants.DEFAULT_DELAY value 123 | * @param controler ISSDPControler 124 | * @param ssdpHost multicast IP 125 | * @param ssdpPort multicast port 126 | * @param cacheControl cache-control value 127 | * @param serverName the name or description of the server 128 | * @param networkInterfaceList NetworkInterfaces that will be used 129 | * @param multipleTimeToSend number time each messages will be sent each time 130 | */ 131 | public AliveMessageSender(ISSDPControler controler, String ssdpHost, int ssdpPort, String cacheControl, String serverName, List networkInterfaceList, int multipleTimeToSend) { 132 | super(controler, ssdpHost, ssdpPort, networkInterfaceList); 133 | this.cacheControl = cacheControl; 134 | this.serverName = serverName; 135 | this.multipleTimeToSend = multipleTimeToSend; 136 | } 137 | 138 | /** 139 | * Constructor with a custom default delay in ms. 140 | * @param controler ISSDPControler 141 | * @param ssdpHost multicast IP 142 | * @param ssdpPort multicast port 143 | * @param delay delay before the next batch of messages are sent 144 | * @param cacheControl cache-control value 145 | * @param serverName the name or description of the server 146 | * @param networkInterfaceList NetworkInterfaces that will be used 147 | */ 148 | public AliveMessageSender(ISSDPControler controler, String ssdpHost, int ssdpPort, int delay, String cacheControl, String serverName, List networkInterfaceList) { 149 | super(controler, ssdpHost, ssdpPort, networkInterfaceList, delay); 150 | this.cacheControl = cacheControl; 151 | this.serverName = serverName; 152 | } 153 | 154 | /** 155 | * Constructor with a custom default delay in ms. 156 | * @param controler ISSDPControler 157 | * @param ssdpHost multicast IP 158 | * @param ssdpPort multicast port 159 | * @param delay delay before the next batch of messages are sent 160 | * @param cacheControl cache-control value 161 | * @param serverName the name or description of the server 162 | * @param networkInterfaceList NetworkInterfaces that will be used 163 | * @param multipleTimeToSend number time each messages will be sent each time 164 | */ 165 | public AliveMessageSender(ISSDPControler controler, String ssdpHost, int ssdpPort, int delay, String cacheControl, String serverName, List networkInterfaceList, int multipleTimeToSend) { 166 | super(controler, ssdpHost, ssdpPort, networkInterfaceList, delay); 167 | this.cacheControl = cacheControl; 168 | this.serverName = serverName; 169 | this.multipleTimeToSend = multipleTimeToSend; 170 | } 171 | 172 | /** 173 | * {@inheritDoc} 174 | */ 175 | @Override 176 | public List getSSDPMessagesToSend() { 177 | List list = new ArrayList(); 178 | 179 | for (ServiceInfo deviceInfo : controler.getServiceInfoList()) { 180 | 181 | AliveMessage message = SSDPMessageHelper.createSSDPAliveMessage(deviceInfo); 182 | 183 | message.setCacheControl(cacheControl); 184 | message.setServer(serverName); 185 | 186 | for(int i=0;i 25 | * 26 | * // a simple example that will send 5 times the same message each time. 27 | * ... 28 | * sender = new SSDPDefaultPeriodicMessageSender(controler, SSDPContants.DEFAULT_IP, SSDPContants.DEFAULT_PORT, SSDPContants.DEFAULT_DELAY) { 29 | * @Override 30 | * public List<ISSDPMessage> getSSDPMessagesToSend() { 31 | * List<ISSDPMessage> list = new ArrayList<ISSDPMessage>(); 32 | * 33 | * // add 5 times the same message to the list 34 | * for(int i=0;i<5;i++){ 35 | * list.add(new ISSDPMessage(){ 36 | * public String toString() { 37 | * return "messagetosend"; 38 | * }}); 39 | * } 40 | * 41 | * return list; 42 | * } 43 | * }; 44 | * 45 | * ... 46 | * 47 | * 48 | * 49 | */ 50 | public class SSDPDefaultPeriodicMessageSender extends SSDPPeriodicMessageSender { 51 | 52 | /** 53 | * Constructor that will use the default delay see com.jerabi.ssdp.util.SSDPContants.DEFAULT_DELAY value 54 | * @param controler ISSDPControler 55 | * @param ssdpHost multicast IP 56 | * @param ssdpPort multicast port 57 | */ 58 | public SSDPDefaultPeriodicMessageSender(ISSDPControler controler, String ssdpHost, int ssdpPort) { 59 | super(controler, ssdpHost, ssdpPort); 60 | } 61 | 62 | /** 63 | * Constructor with a custom default delay in ms. 64 | * @param controler ISSDPControler 65 | * @param ssdpHost multicast IP 66 | * @param ssdpPort multicast port 67 | * @param delay delay before the next batch of messages are sent 68 | */ 69 | public SSDPDefaultPeriodicMessageSender(ISSDPControler controler, String ssdpHost, int ssdpPort, int delay) { 70 | super(controler, ssdpHost, ssdpPort, delay); 71 | } 72 | 73 | /** 74 | * Constructor that will use the default delay see com.jerabi.ssdp.util.SSDPContants.DEFAULT_DELAY value 75 | * @param controler ISSDPControler 76 | * @param ssdpHost multicast IP 77 | * @param ssdpPort multicast port 78 | * @param networkInterfaceList NetworkInterfaces that will be used 79 | */ 80 | public SSDPDefaultPeriodicMessageSender(ISSDPControler controler, String ssdpHost, int ssdpPort, List networkInterfaceList) { 81 | super(controler, ssdpHost, ssdpPort, networkInterfaceList); 82 | } 83 | 84 | /** 85 | * Constructor with a custom default delay in ms. 86 | * @param controler ISSDPControler 87 | * @param ssdpHost multicast IP 88 | * @param ssdpPort multicast port 89 | * @param networkInterfaceList NetworkInterfaces that will be used 90 | * @param delay delay before the next batch of messages are sent 91 | */ 92 | public SSDPDefaultPeriodicMessageSender(ISSDPControler controler, String ssdpHost, int ssdpPort, List networkInterfaceList, int delay) { 93 | super(controler, ssdpHost, ssdpPort, networkInterfaceList, delay); 94 | } 95 | 96 | /** 97 | * {@inheritDoc} 98 | */ 99 | @Override 100 | public List getSSDPMessagesToSend() { 101 | return null; 102 | } 103 | 104 | } 105 | -------------------------------------------------------------------------------- /ssdp-core/src/main/java/com/jerabi/ssdp/sender/SSDPDiscoverSender.java: -------------------------------------------------------------------------------- 1 | package com.jerabi.ssdp.sender; 2 | 3 | import java.net.InetAddress; 4 | import java.net.NetworkInterface; 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | import java.util.concurrent.Callable; 8 | import java.util.logging.Logger; 9 | 10 | import com.jerabi.ssdp.ISSDPControler; 11 | import com.jerabi.ssdp.handler.ISSDPResponseHandler; 12 | import com.jerabi.ssdp.message.DiscoverMessage; 13 | import com.jerabi.ssdp.message.ISSDPMessage; 14 | import com.jerabi.ssdp.network.IUDPSender; 15 | import com.jerabi.ssdp.network.SSDPNetworkFactory; 16 | import com.jerabi.ssdp.util.SSDPContants; 17 | 18 | /** 19 | * This class in a {@link SSDPPeriodicMessageSender} that send DiscoverMessage and handle responses for the messages sent. 20 | * 21 | * The sender is a {@link IUDPSender} and it sends UDP instead of Multicast UDP. The responses will be handle by a {@link ISSDPResponseHandler}, if the handler is null, 22 | * the responses will be ignored. 23 | * 24 | * When you change the port, the {@link IUDPSender} will be set to null and recreated when you send a message. 25 | * 26 | * @author Sebastien Dionne 27 | * @example. 28 | *
 29 |  * ...
 30 |  * // you need a ISSDPControler to process the responses.
 31 |  * SSDPDiscoverSender discoverSender = new SSDPDiscoverSender(controler, SSDPContants.DEFAULT_IP, SSDPContants.DEFAULT_PORT);
 32 |  * discoverSender.setSSDPResponseHandler(new SSDPDiscoverResponseHandler(controler));
 33 |  * Thread t = new Thread(discoverSender);
 34 |  * t.start();
 35 |  * 
36 | * @see DiscoverMessage 37 | * @see IUDPSender 38 | */ 39 | public class SSDPDiscoverSender extends SSDPPeriodicMessageSender { 40 | private Logger logger = Logger.getLogger(SSDPDiscoverSender.class.getName()); 41 | 42 | private IUDPSender udpSender = null; 43 | private ISSDPResponseHandler handler = null; 44 | private int TTL = 3; // MX 45 | 46 | /** 47 | * Constructor that will use the default delay see com.jerabi.ssdp.util.SSDPContants.DEFAULT_DELAY value 48 | * and creates a IUDPSender using ssdpPort 49 | * 50 | * @param controler ISSDPControler 51 | * @param ssdpHost multicast IP 52 | * @param ssdpPort multicast port 53 | */ 54 | public SSDPDiscoverSender(ISSDPControler controler, String ssdpHost, int ssdpPort) { 55 | super(controler, ssdpHost, ssdpPort); 56 | } 57 | 58 | /** 59 | * Constructor with a custom default delay in ms. 60 | * and creates a IUDPSender using ssdpPort 61 | * 62 | * @param controler ISSDPControler 63 | * @param ssdpHost multicast IP 64 | * @param ssdpPort multicast port 65 | * @param delay delay before the next batch of messages are sent 66 | */ 67 | public SSDPDiscoverSender(ISSDPControler controler, String ssdpHost, int ssdpPort, int delay) { 68 | super(controler, ssdpHost, ssdpPort, delay); 69 | } 70 | 71 | /** 72 | * Constructor that will use the default delay see com.jerabi.ssdp.util.SSDPContants.DEFAULT_DELAY value 73 | * and creates a IUDPSender using ssdpPort 74 | * 75 | * @param controler ISSDPControler 76 | * @param ssdpHost multicast IP 77 | * @param ssdpPort multicast port 78 | * @param networkInterfaceList NetworkInterfaces that will be used 79 | */ 80 | public SSDPDiscoverSender(ISSDPControler controler, String ssdpHost, int ssdpPort, List networkInterfaceList) { 81 | super(controler, ssdpHost, ssdpPort, networkInterfaceList); 82 | } 83 | 84 | /** 85 | * Constructor with a custom default delay in ms. 86 | * and creates a IUDPSender using ssdpPort 87 | * 88 | * @param controler ISSDPControler 89 | * @param ssdpHost multicast IP 90 | * @param ssdpPort multicast port 91 | * @param networkInterfaceList NetworkInterfaces that will be used 92 | * @param delay delay before the next batch of messages are sent 93 | */ 94 | public SSDPDiscoverSender(ISSDPControler controler, String ssdpHost, int ssdpPort, List networkInterfaceList, int delay) { 95 | super(controler, ssdpHost, ssdpPort, networkInterfaceList, delay); 96 | } 97 | 98 | /** 99 | * Return a ISSDPHandler that will handle the discover responses. 100 | * @return handler 101 | */ 102 | public ISSDPResponseHandler getSSDPResponseHandler() { 103 | return handler; 104 | } 105 | 106 | /** 107 | * Sets a ISSDPHandler that will handle the discover responses. 108 | * @param handler 109 | */ 110 | public void setSSDPResponseHandler(ISSDPResponseHandler handler) { 111 | this.handler = handler; 112 | } 113 | 114 | /** 115 | * {@inheritDoc} 116 | * Sets IUDPSender to null. If will be recreate when a message is sent. 117 | */ 118 | @Override 119 | public void setSSDPPort(int port) { 120 | super.setSSDPPort(port); 121 | udpSender=null; 122 | } 123 | 124 | /** 125 | * {@inheritDoc} 126 | * Creates a {@link DiscoverMessage} and add it twice to the list. 127 | * It's strongly suggested to send DiscoverMessage twice. 128 | */ 129 | @Override 130 | public List getSSDPMessagesToSend() { 131 | 132 | List list = new ArrayList(); 133 | DiscoverMessage discoverMessage = new DiscoverMessage(SSDPContants.DEFAULT_IP, SSDPContants.DEFAULT_PORT, TTL, "upnp:rootdevice", null); 134 | 135 | list.add(discoverMessage); 136 | list.add(discoverMessage); 137 | 138 | return list; 139 | } 140 | 141 | /** 142 | * Sends the messages using {@link IUDPSender} and wait for a response until a timeout (Time-to-live). 143 | * When a response is received, a {@link ISSDPResponseHandler} will handle it. If the port changed since the 144 | * last time you sent a message, a new IUDPSender will be created. 145 | */ 146 | @Override 147 | public void sendMessage(String message) throws Exception { 148 | 149 | if(message==null){ 150 | return; 151 | } 152 | 153 | logger.info("sending M-SEARCH \n" + message); 154 | 155 | if(udpSender==null){ 156 | udpSender = SSDPNetworkFactory.getInstance().createUDPSender(); 157 | } 158 | 159 | final String msg = message; 160 | threadPool.submit(new Callable() { 161 | @Override 162 | public Boolean call() throws Exception { 163 | udpSender.sendMessage(msg, InetAddress.getByName(host), port, handler, TTL); 164 | return Boolean.TRUE; 165 | } 166 | }); 167 | 168 | } 169 | 170 | } 171 | -------------------------------------------------------------------------------- /ssdp-core/src/main/java/com/jerabi/ssdp/sender/SSDPPeriodicMessageSender.java: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jerabi/jerabi-ssdp/30e89a68451173f490a1b138751ab81608497b3c/ssdp-core/src/main/java/com/jerabi/ssdp/sender/SSDPPeriodicMessageSender.java -------------------------------------------------------------------------------- /ssdp-core/src/main/java/com/jerabi/ssdp/util/IStateListener.java: -------------------------------------------------------------------------------- 1 | package com.jerabi.ssdp.util; 2 | 3 | /** 4 | * Provides the notification mechanism for state changes. 5 | * 6 | * @author Sebastien Dionne 7 | * 8 | * @param State 9 | */ 10 | public interface IStateListener { 11 | 12 | /** 13 | * Notify the listener that the state changed. 14 | * 15 | * @param state the new current state 16 | */ 17 | void notifyStateChange(E state); 18 | } 19 | -------------------------------------------------------------------------------- /ssdp-core/src/main/java/com/jerabi/ssdp/util/SSDPContants.java: -------------------------------------------------------------------------------- 1 | package com.jerabi.ssdp.util; 2 | 3 | /** 4 | * 5 | * Defines all SSDP Constants. 6 | * 7 | * @author Sebastien Dionne 8 | * 9 | */ 10 | public class SSDPContants { 11 | 12 | /** 13 | * Method for sending notifications and events. First line of the message. 14 | */ 15 | public static final String NOTIFY = "NOTIFY:"; 16 | 17 | /** 18 | * Field value MUST have the max-age directive ("max-age=") followed by an integer that specifies the number of 19 | * seconds the advertisement is valid 20 | */ 21 | public static final String CACHECONTROL = "CACHE-CONTROL:"; 22 | /** 23 | * Field value contains when response was generated 24 | */ 25 | public static final String DATE = "DATE:"; 26 | /** 27 | * Field value contains a URL to the UPnP description of the root device 28 | */ 29 | public static final String LOCATION = "LOCATION:"; 30 | /** 31 | * Server informations. The format is : OS/version, UPnP/version, product/version 32 | */ 33 | public static final String SERVER = "SERVER:"; 34 | /** 35 | * Field value contains Search Target. 36 | */ 37 | public static final String ST = "ST:"; 38 | /** 39 | * Backwards compatibility with UPnP 1.0. (Header field name only; no field value.) 40 | */ 41 | public static final String EXT = "EXT:"; 42 | /** 43 | * Field value contains Unique Service Name. Identifies a unique instance of a device or service 44 | */ 45 | public static final String USN = "USN:"; 46 | /** 47 | * Field value contains the byte count in the body 48 | */ 49 | public static final String CONTENTLENGTH = "CONTENT-LENGTH:"; 50 | 51 | /** 52 | * Field value contains multicast address and port reserved for SSDP by Internet Assigned Numbers Authority (IANA). 53 | * MUST be 239.255.255.250:1900. If the port number (":1900") is omitted, the receiver MUST assume the default SSDP port 54 | * number of 1900. 55 | */ 56 | public static final String HOST = "HOST:"; 57 | /** 58 | * Field value contains Notification Type. 59 | */ 60 | public static final String NT = "NT:"; 61 | /** 62 | * Field value contains Notification Sub Type 63 | */ 64 | public static final String NTS = "NTS:"; 65 | /** 66 | * HTTP Extension Framework. Unlike the NTS and ST field values, the field value of the MAN header field is 67 | * enclosed in double quotes; it defines the scope (namespace) of the extension. MUST be "ssdp:discover". 68 | */ 69 | public static final String MAN = "MAN:"; 70 | /** 71 | * Field value contains maximum wait time in seconds. MUST be greater than or equal to 1 and SHOULD be less than 72 | * 5 inclusive. Device responses SHOULD be delayed a random duration between 0 and this many seconds to balance load for 73 | * the control point when it processes responses 74 | */ 75 | public static final String MX = "MX:"; 76 | 77 | /** 78 | * Default SSDP port 79 | */ 80 | public static final int DEFAULT_PORT = 1900; 81 | 82 | /** 83 | * Default SSDP IP 84 | */ 85 | public static final String DEFAULT_IP = "239.255.255.250"; 86 | 87 | /** 88 | * Default sleep value for periodically messages in ms. 89 | */ 90 | public static final int DEFAULT_DELAY = 5000; 91 | 92 | /** 93 | * Default value for non blocking socket timeout 94 | */ 95 | public static final int DEFAULT_SOCKET_TIMEOUT = 3000; 96 | 97 | /** 98 | * NTS value for {@link com.jerabi.ssdp.message.AliveMessage} 99 | */ 100 | public static final String NTS_ALIVE = "ssdp:alive"; 101 | /** 102 | * NTS value for {@link com.jerabi.ssdp.message.DiscoverMessage} 103 | */ 104 | public static final String NTS_DISCOVER = "\"ssdp:discover\""; 105 | /** 106 | * NTS value for {@link com.jerabi.ssdp.message.ByeByeMessage} 107 | */ 108 | public static final String NTS_BYEBYE = "ssdp:byebye"; 109 | /** 110 | * NTS value for {@link com.jerabi.ssdp.message.UpdateMessage} 111 | */ 112 | public static final String NTS_UPDATE = "ssdp:update"; 113 | /** 114 | * NTS value for discover all devices and services @see com.jerabi.ssdp.message.DiscoverMessage 115 | */ 116 | public static final String NTS_DISCOVER_ALL = "ssdp:all"; 117 | 118 | } 119 | -------------------------------------------------------------------------------- /ssdp-core/src/main/java/com/jerabi/ssdp/util/State.java: -------------------------------------------------------------------------------- 1 | package com.jerabi.ssdp.util; 2 | 3 | /** 4 | * Defines available SSDP states. 5 | * 6 | * @author Sebastien Dionne 7 | * 8 | */ 9 | public enum State { 10 | /** 11 | * Used when the process is stopped 12 | */ 13 | STOPPED, 14 | /** 15 | * Used when the process is started 16 | */ 17 | STARTED, 18 | /** 19 | * Used when the process is sleeping 20 | */ 21 | SLEEP, 22 | /** 23 | * Used when the process is supended 24 | */ 25 | SUSPENDED 26 | } 27 | -------------------------------------------------------------------------------- /ssdp-core/src/main/java/com/jerabi/ssdp/util/StateHolder.java: -------------------------------------------------------------------------------- 1 | package com.jerabi.ssdp.util; 2 | 3 | import java.util.LinkedList; 4 | import java.util.List; 5 | import java.util.concurrent.atomic.AtomicReference; 6 | import java.util.concurrent.locks.ReentrantReadWriteLock; 7 | 8 | /** 9 | * Class that will hold a State {@link State}. 10 | * 11 | * Uses {@link AtomicReference} with {@link ReentrantReadWriteLock}. 12 | * 13 | * Notify listener when the state changes. 14 | * 15 | * @see State 16 | * 17 | * @author Sebastien Dionne 18 | * @param State 19 | */ 20 | public class StateHolder { 21 | private AtomicReference state; 22 | 23 | private ReentrantReadWriteLock readWriteLock; 24 | private List> stateListenerList = null; 25 | 26 | /** 27 | * Instantiates a new state holder. 28 | */ 29 | public StateHolder(){ 30 | state = new AtomicReference(); 31 | readWriteLock = new ReentrantReadWriteLock(); 32 | stateListenerList = new LinkedList>(); 33 | } 34 | 35 | /** 36 | * Adds the state listener. 37 | * 38 | * @param listener the listener 39 | */ 40 | public void addStateListener(IStateListener listener){ 41 | if(listener!=null){ 42 | stateListenerList.add(listener); 43 | } 44 | } 45 | 46 | /** 47 | * Removes the state listener. 48 | * 49 | * @param listener the listener 50 | */ 51 | public void removeStateListener(IStateListener listener){ 52 | if(listener!=null){ 53 | stateListenerList.remove(listener); 54 | } 55 | } 56 | 57 | /** 58 | * Gets the state. 59 | * If the state is not setted, null value will be return 60 | * 61 | * @return the state 62 | * @see State 63 | */ 64 | public E getState() { 65 | readWriteLock.readLock().lock(); 66 | 67 | E currentState = state.get(); 68 | 69 | readWriteLock.readLock().unlock(); 70 | 71 | return currentState; 72 | } 73 | 74 | /** 75 | * Sets the state and notify all registered listeners. 76 | * Used a {@link ReentrantReadWriteLock} 77 | * 78 | * @param state the new state 79 | * @see State 80 | */ 81 | public void setState(E state) { 82 | readWriteLock.writeLock().lock(); 83 | 84 | this.state.set(state); 85 | 86 | // downgrading lock to read 87 | readWriteLock.readLock().lock(); 88 | readWriteLock.writeLock().unlock(); 89 | 90 | // notifyListener 91 | notifyListeners(state); 92 | 93 | // release lock 94 | readWriteLock.readLock().unlock(); 95 | } 96 | 97 | /** 98 | * Notify listeners. 99 | * 100 | * @param state the state 101 | */ 102 | protected void notifyListeners(E state){ 103 | for (IStateListener listener : stateListenerList) { 104 | listener.notifyStateChange(state); 105 | } 106 | } 107 | 108 | } 109 | -------------------------------------------------------------------------------- /ssdp-core/src/main/java/com/jerabi/ssdp/util/UUIDGenerator.java: -------------------------------------------------------------------------------- 1 | package com.jerabi.ssdp.util; 2 | 3 | import java.net.NetworkInterface; 4 | import java.net.SocketException; 5 | import java.util.UUID; 6 | 7 | /** 8 | * 9 | * Provide API to generate {@link java.util.UUID}. 10 | * 11 | * A UUID is an acronym for : Universally Unique Identifier 12 | * 13 | *
 
14 | *    UUID                   = <time_low> - <time_mid> - <time_high_and_version> - <clock_seq_and_reserved> <clock_seq_low> - <node>
15 | *    
16 | *    time_low               = 4*<hexOctet>
17 | *    time_mid               = 2*<hexOctet>
18 | *    time_high_and_version  = 2*<hexOctet>
19 | *    clock_seq_and_reserved = <hexOctet>
20 | *    clock_seq_low          = <hexOctet>
21 | *    node                   = 6*<hexOctet
22 | *    hexOctet               = <hexDigit> <hexDigit>
23 | *
24 | *    hexDigit = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | a | b | c | d | e | f | A | B | C | D | E | F
25 | *    
26 | *    The following is an example of the string representation of a UUID:
27 | *
28 | *    f81d4fae-7dec-11d0-a765-00a0c91e6bf6
29 | *	
30 | * 31 | * @see java.util.UUID 32 | * 33 | * @author Sebastien Dionne 34 | * 35 | */ 36 | public class UUIDGenerator { 37 | 38 | /** 39 | * Generates a random UUID 40 | * 41 | * @return UUID 42 | * @see java.util.UUID 43 | */ 44 | public static String getUUID(){ 45 | return UUID.randomUUID().toString(); 46 | } 47 | 48 | /** 49 | * Generates a UUID based on the MAC address. 50 | * If the NetworkInterface is null, null value will be return 51 | * 52 | * @param ni NetworkInterface used 53 | * @return a UUID based on the MAC address of the NetworkInterface 54 | * @throws SocketException 55 | * @see java.util.UUID 56 | */ 57 | public static String getUUID(NetworkInterface ni) throws SocketException { 58 | 59 | if(ni==null){ 60 | return null; 61 | } 62 | 63 | byte[] mac = ni.getHardwareAddress(); 64 | 65 | return UUID.nameUUIDFromBytes(mac).toString(); 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /ssdp-core/src/test/java/com/jerabi/ssdp/handler/SSDPDefaultHandlerTest.java: -------------------------------------------------------------------------------- 1 | package com.jerabi.ssdp.handler; 2 | 3 | import static org.junit.Assert.*; 4 | import static org.junit.Assert.assertEquals; 5 | import static org.junit.Assert.fail; 6 | 7 | import java.util.concurrent.CountDownLatch; 8 | 9 | import org.junit.After; 10 | import org.junit.Before; 11 | import org.junit.BeforeClass; 12 | import org.junit.Test; 13 | 14 | import com.jerabi.ssdp.ISSDPControler; 15 | import com.jerabi.ssdp.SSDPControler; 16 | import com.jerabi.ssdp.handler.SSDPDefaultResponseHandler; 17 | import com.jerabi.ssdp.message.ISSDPMessage; 18 | import com.jerabi.ssdp.message.ServiceInfo; 19 | import com.jerabi.ssdp.message.USNInfo; 20 | import com.jerabi.ssdp.message.helper.SSDPMessageHelper; 21 | import com.jerabi.ssdp.util.SSDPContants; 22 | 23 | public class SSDPDefaultHandlerTest { 24 | 25 | private ServiceInfo deviceInfo = new ServiceInfo("localhost",1999,"nt","location", new USNInfo("uuid", "urn")); 26 | 27 | @BeforeClass 28 | public static void setUpBeforeClass() throws Exception { 29 | } 30 | 31 | @Before 32 | public void setUp() throws Exception { 33 | } 34 | 35 | @After 36 | public void tearDown() throws Exception { 37 | } 38 | 39 | 40 | @Test 41 | public void testSetSSDPControler() throws Exception{ 42 | ISSDPControler controler = new SSDPControler(){ 43 | @Override 44 | public void processSSDPMessage(ISSDPMessage message) 45 | throws Exception { 46 | } 47 | }; 48 | 49 | SSDPDefaultResponseHandler handler = new SSDPDefaultResponseHandler(null); 50 | 51 | assertNull(handler.getSSDPControler()); 52 | 53 | handler.setSSDPControler(controler); 54 | 55 | assertEquals(controler, handler.getSSDPControler()); 56 | } 57 | 58 | @Test 59 | public void testHandleMessage() throws Exception { 60 | 61 | final CountDownLatch countDown = new CountDownLatch(5); 62 | 63 | ISSDPControler controler = new SSDPControler(){ 64 | @Override 65 | public void processSSDPMessage(ISSDPMessage message) 66 | throws Exception { 67 | countDown.countDown(); 68 | } 69 | }; 70 | 71 | SSDPDefaultResponseHandler handler = new SSDPDefaultResponseHandler(controler); 72 | 73 | try { 74 | handler.handle(SSDPMessageHelper.createSSDPAliveMessage(deviceInfo).toString()); 75 | handler.handle(SSDPMessageHelper.createSSDPByeByeMessage(deviceInfo).toString()); 76 | handler.handle(SSDPMessageHelper.createSSDPUpdateMessage(deviceInfo).toString()); 77 | handler.handle(SSDPMessageHelper.createSSDPDiscoverMessage(SSDPContants.DEFAULT_IP, SSDPContants.DEFAULT_PORT, 3, "upnp:rootdevice", null).toString()); 78 | 79 | StringBuffer sb = new StringBuffer(); 80 | 81 | sb.append("HTTP/1.1 200 OK").append("\n"); 82 | sb.append("CACHE-CONTROL: max-age=1200").append("\n"); 83 | sb.append("DATE: Tue, 05 May 2009 13:31:51 GMT").append("\n"); 84 | sb.append("LOCATION: http://142.225.35.55:5001/description/fetch").append("\n"); 85 | sb.append("SERVER: Windows_XP-x86-5.1, UPnP/1.0, PMS/1.11").append("\n"); 86 | sb.append("ST: upnp:rootdevice").append("\n"); 87 | sb.append("EXT: ").append("\n"); 88 | sb.append("USN: uuid:9dcf6222-fc4b-33eb-bf49-e54643b4f416::upnp:rootdevice").append("\n"); 89 | sb.append("Content-Length: 0").append("\n"); 90 | 91 | handler.handle( SSDPMessageHelper.getSSDPMessage(sb.toString()).toString()); 92 | 93 | 94 | handler.handle(null, -1, SSDPMessageHelper.createSSDPAliveMessage(deviceInfo).toString()); 95 | 96 | handler.setSSDPControler(null); 97 | handler.handle(SSDPMessageHelper.createSSDPAliveMessage(deviceInfo).toString()); 98 | 99 | 100 | 101 | } catch (Exception e) { 102 | fail("Should not throws Exception"); 103 | } 104 | 105 | assertEquals(0, countDown.getCount()); 106 | 107 | } 108 | 109 | } 110 | -------------------------------------------------------------------------------- /ssdp-core/src/test/java/com/jerabi/ssdp/handler/SSDPDiscoverResponseHandlerTest.java: -------------------------------------------------------------------------------- 1 | package com.jerabi.ssdp.handler; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import java.util.concurrent.CountDownLatch; 6 | 7 | import org.junit.After; 8 | import org.junit.Before; 9 | import org.junit.BeforeClass; 10 | import org.junit.Test; 11 | 12 | import com.jerabi.ssdp.ISSDPControler; 13 | import com.jerabi.ssdp.SSDPControler; 14 | import com.jerabi.ssdp.handler.SSDPDiscoverResponseHandler; 15 | import com.jerabi.ssdp.message.ISSDPMessage; 16 | import com.jerabi.ssdp.message.ServiceInfo; 17 | import com.jerabi.ssdp.message.USNInfo; 18 | import com.jerabi.ssdp.message.helper.SSDPMessageHelper; 19 | import com.jerabi.ssdp.util.SSDPContants; 20 | 21 | public class SSDPDiscoverResponseHandlerTest { 22 | 23 | private ServiceInfo deviceInfo = new ServiceInfo("localhost",1999,"nt","location", new USNInfo("uuid", "urn")); 24 | 25 | @BeforeClass 26 | public static void setUpBeforeClass() throws Exception { 27 | } 28 | 29 | @Before 30 | public void setUp() throws Exception { 31 | } 32 | 33 | @After 34 | public void tearDown() throws Exception { 35 | } 36 | 37 | @Test 38 | public void testHandleMessage() throws Exception{ 39 | final CountDownLatch countDown = new CountDownLatch(1); 40 | 41 | ISSDPControler controler = new SSDPControler(){ 42 | @Override 43 | public void processSSDPMessage(ISSDPMessage message) 44 | throws Exception { 45 | countDown.countDown(); 46 | } 47 | }; 48 | 49 | SSDPDiscoverResponseHandler handler = new SSDPDiscoverResponseHandler(controler); 50 | 51 | try { 52 | handler.handle(null); 53 | handler.handle(SSDPMessageHelper.createSSDPAliveMessage(deviceInfo).toString()); 54 | handler.handle(SSDPMessageHelper.createSSDPByeByeMessage(deviceInfo).toString()); 55 | handler.handle(SSDPMessageHelper.createSSDPUpdateMessage(deviceInfo).toString()); 56 | handler.handle(SSDPMessageHelper.createSSDPDiscoverMessage(SSDPContants.DEFAULT_IP, SSDPContants.DEFAULT_PORT, 3, "upnp:rootdevice", null).toString()); 57 | 58 | StringBuffer sb = new StringBuffer(); 59 | 60 | sb.append("HTTP/1.1 200 OK").append("\n"); 61 | sb.append("CACHE-CONTROL: max-age=1200").append("\n"); 62 | sb.append("DATE: Tue, 05 May 2009 13:31:51 GMT").append("\n"); 63 | sb.append("LOCATION: http://142.225.35.55:5001/description/fetch").append("\n"); 64 | sb.append("SERVER: Windows_XP-x86-5.1, UPnP/1.0, PMS/1.11").append("\n"); 65 | sb.append("ST: upnp:rootdevice").append("\n"); 66 | sb.append("EXT: ").append("\n"); 67 | sb.append("USN: uuid:9dcf6222-fc4b-33eb-bf49-e54643b4f416::upnp:rootdevice").append("\n"); 68 | sb.append("Content-Length: 0").append("\n"); 69 | 70 | handler.handle( SSDPMessageHelper.getSSDPMessage(sb.toString()).toString()); 71 | } catch (Exception e) { 72 | e.printStackTrace(); 73 | fail("Should not throws Exception"); 74 | } 75 | 76 | assertEquals(0, countDown.getCount()); 77 | } 78 | 79 | @Test 80 | public void testHandleMessageSSDPControlerNull() throws Exception { 81 | final CountDownLatch countDown = new CountDownLatch(1); 82 | 83 | ISSDPControler controler = new SSDPControler(){ 84 | @Override 85 | public void processSSDPMessage(ISSDPMessage message) 86 | throws Exception { 87 | countDown.countDown(); 88 | } 89 | }; 90 | 91 | SSDPDiscoverResponseHandler handler = new SSDPDiscoverResponseHandler(null){ 92 | @Override 93 | public void handle(String message) throws Exception { 94 | countDown.countDown(); 95 | super.handle(message); 96 | }}; 97 | 98 | try { 99 | handler.handle(null); 100 | handler.handle(SSDPMessageHelper.createSSDPAliveMessage(deviceInfo).toString()); 101 | handler.handle(SSDPMessageHelper.createSSDPByeByeMessage(deviceInfo).toString()); 102 | handler.handle(SSDPMessageHelper.createSSDPUpdateMessage(deviceInfo).toString()); 103 | handler.handle(SSDPMessageHelper.createSSDPDiscoverMessage(SSDPContants.DEFAULT_IP, SSDPContants.DEFAULT_PORT, 3, "upnp:rootdevice", null).toString()); 104 | 105 | StringBuffer sb = new StringBuffer(); 106 | 107 | sb.append("HTTP/1.1 200 OK").append("\n"); 108 | sb.append("CACHE-CONTROL: max-age=1200").append("\n"); 109 | sb.append("DATE: Tue, 05 May 2009 13:31:51 GMT").append("\n"); 110 | sb.append("LOCATION: http://142.225.35.55:5001/description/fetch").append("\n"); 111 | sb.append("SERVER: Windows_XP-x86-5.1, UPnP/1.0, PMS/1.11").append("\n"); 112 | sb.append("ST: upnp:rootdevice").append("\n"); 113 | sb.append("EXT: ").append("\n"); 114 | sb.append("USN: uuid:9dcf6222-fc4b-33eb-bf49-e54643b4f416::upnp:rootdevice").append("\n"); 115 | sb.append("Content-Length: 0").append("\n"); 116 | 117 | handler.handle( SSDPMessageHelper.getSSDPMessage(sb.toString()).toString()); 118 | } catch (Exception e) { 119 | fail("Should not throws Exception"); 120 | } 121 | 122 | assertEquals(0, countDown.getCount()); 123 | 124 | } 125 | 126 | } 127 | -------------------------------------------------------------------------------- /ssdp-core/src/test/java/com/jerabi/ssdp/listener/SSDPDefaultMessageListenerTest.java: -------------------------------------------------------------------------------- 1 | package com.jerabi.ssdp.listener; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import java.util.concurrent.CountDownLatch; 6 | 7 | import org.junit.After; 8 | import org.junit.Before; 9 | import org.junit.BeforeClass; 10 | import org.junit.Test; 11 | 12 | import com.jerabi.ssdp.handler.SSDPDefaultMessageHandler; 13 | import com.jerabi.ssdp.message.AliveMessage; 14 | import com.jerabi.ssdp.message.ByeByeMessage; 15 | import com.jerabi.ssdp.message.DiscoverMessage; 16 | import com.jerabi.ssdp.message.DiscoverResponseMessage; 17 | import com.jerabi.ssdp.message.UpdateMessage; 18 | import com.jerabi.ssdp.message.helper.SSDPMessageHelper; 19 | import com.jerabi.ssdp.message.helper.SSDPMessageHelperTest; 20 | 21 | public class SSDPDefaultMessageListenerTest { 22 | 23 | @BeforeClass 24 | public static void setUpBeforeClass() throws Exception { 25 | } 26 | 27 | @Before 28 | public void setUp() throws Exception { 29 | } 30 | 31 | @After 32 | public void tearDown() throws Exception { 33 | } 34 | 35 | @Test 36 | public void testProcessSSDPAliveMessage() { 37 | 38 | final CountDownLatch latch = new CountDownLatch(1); 39 | 40 | SSDPDefaultMessageHandler listener = new SSDPDefaultMessageHandler(){ 41 | @Override 42 | public void processSSDPAliveMessage(AliveMessage ssdpMessage) 43 | throws Exception { 44 | latch.countDown(); 45 | } 46 | }; 47 | 48 | try { 49 | listener.processSSDPAliveMessage((AliveMessage)SSDPMessageHelper.getSSDPMessage(SSDPMessageHelperTest.createAliveMessage())); 50 | } catch (Exception e) { 51 | fail("Shouldn't throw Exception"); 52 | } 53 | 54 | try { 55 | listener.processSSDPByeByeMessage((ByeByeMessage)SSDPMessageHelper.getSSDPMessage(SSDPMessageHelperTest.createByeByeMessage())); 56 | } catch (Exception e) { 57 | fail("Shouldn't throw Exception"); 58 | } 59 | 60 | try { 61 | listener.processSSDPUpdateMessage((UpdateMessage)SSDPMessageHelper.getSSDPMessage(SSDPMessageHelperTest.createUpdateMessage())); 62 | } catch (Exception e) { 63 | fail("Shouldn't throw Exception"); 64 | } 65 | 66 | try { 67 | listener.processSSDPDiscoverMessage(null, -1, (DiscoverMessage)SSDPMessageHelper.getSSDPMessage(SSDPMessageHelperTest.createDiscoverMessage())); 68 | } catch (Exception e) { 69 | fail("Shouldn't throw Exception"); 70 | } 71 | 72 | try { 73 | listener.processSSDPDiscoverResponseMessage((DiscoverResponseMessage)SSDPMessageHelper.getSSDPMessage(SSDPMessageHelperTest.createDiscoverResponseMessage())); 74 | } catch (Exception e) { 75 | fail("Shouldn't throw Exception"); 76 | } 77 | 78 | assertEquals(0, latch.getCount()); 79 | 80 | } 81 | 82 | @Test 83 | public void testProcessSSDPByeByeMessage() { 84 | final CountDownLatch latch = new CountDownLatch(1); 85 | 86 | SSDPDefaultMessageHandler listener = new SSDPDefaultMessageHandler(){ 87 | @Override 88 | public void processSSDPByeByeMessage(ByeByeMessage ssdpMessage) 89 | throws Exception { 90 | latch.countDown(); 91 | } 92 | }; 93 | 94 | try { 95 | listener.processSSDPByeByeMessage((ByeByeMessage)SSDPMessageHelper.getSSDPMessage(SSDPMessageHelperTest.createByeByeMessage())); 96 | } catch (Exception e) { 97 | fail("Shouldn't throw Exception"); 98 | } 99 | 100 | try { 101 | listener.processSSDPAliveMessage((AliveMessage)SSDPMessageHelper.getSSDPMessage(SSDPMessageHelperTest.createAliveMessage())); 102 | } catch (Exception e) { 103 | fail("Shouldn't throw Exception"); 104 | } 105 | 106 | assertEquals(0, latch.getCount()); 107 | } 108 | 109 | @Test 110 | public void testProcessSSDPDiscoverMessage() { 111 | final CountDownLatch latch = new CountDownLatch(1); 112 | 113 | SSDPDefaultMessageHandler listener = new SSDPDefaultMessageHandler(){ 114 | @Override 115 | public void processSSDPDiscoverMessage(String remoteAddr, 116 | int remotePort, DiscoverMessage ssdpMessage) 117 | throws Exception { 118 | latch.countDown(); 119 | } 120 | }; 121 | 122 | try { 123 | listener.processSSDPDiscoverMessage(null, -1, (DiscoverMessage)SSDPMessageHelper.getSSDPMessage(SSDPMessageHelperTest.createDiscoverMessage())); 124 | } catch (Exception e) { 125 | fail("Shouldn't throw Exception"); 126 | } 127 | 128 | try { 129 | listener.processSSDPAliveMessage((AliveMessage)SSDPMessageHelper.getSSDPMessage(SSDPMessageHelperTest.createAliveMessage())); 130 | } catch (Exception e) { 131 | fail("Shouldn't throw Exception"); 132 | } 133 | 134 | assertEquals(0, latch.getCount()); 135 | } 136 | 137 | @Test 138 | public void testProcessSSDPDiscoverResponseMessage() { 139 | final CountDownLatch latch = new CountDownLatch(1); 140 | 141 | SSDPDefaultMessageHandler listener = new SSDPDefaultMessageHandler(){ 142 | @Override 143 | public void processSSDPDiscoverResponseMessage( 144 | DiscoverResponseMessage ssdpMessage) throws Exception { 145 | latch.countDown(); 146 | } 147 | }; 148 | 149 | try { 150 | listener.processSSDPDiscoverResponseMessage((DiscoverResponseMessage)SSDPMessageHelper.getSSDPMessage(SSDPMessageHelperTest.createDiscoverResponseMessage())); 151 | } catch (Exception e) { 152 | fail("Shouldn't throw Exception"); 153 | } 154 | 155 | try { 156 | listener.processSSDPAliveMessage((AliveMessage)SSDPMessageHelper.getSSDPMessage(SSDPMessageHelperTest.createAliveMessage())); 157 | } catch (Exception e) { 158 | fail("Shouldn't throw Exception"); 159 | } 160 | 161 | assertEquals(0, latch.getCount()); 162 | } 163 | 164 | @Test 165 | public void testProcessSSDPUpdateMessage() { 166 | final CountDownLatch latch = new CountDownLatch(1); 167 | 168 | SSDPDefaultMessageHandler listener = new SSDPDefaultMessageHandler(){ 169 | @Override 170 | public void processSSDPUpdateMessage(UpdateMessage ssdpMessage) 171 | throws Exception { 172 | latch.countDown(); 173 | } 174 | }; 175 | 176 | try { 177 | listener.processSSDPUpdateMessage((UpdateMessage)SSDPMessageHelper.getSSDPMessage(SSDPMessageHelperTest.createUpdateMessage())); 178 | } catch (Exception e) { 179 | fail("Shouldn't throw Exception"); 180 | } 181 | 182 | try { 183 | listener.processSSDPAliveMessage((AliveMessage)SSDPMessageHelper.getSSDPMessage(SSDPMessageHelperTest.createAliveMessage())); 184 | } catch (Exception e) { 185 | fail("Shouldn't throw Exception"); 186 | } 187 | 188 | assertEquals(0, latch.getCount()); 189 | } 190 | 191 | } 192 | -------------------------------------------------------------------------------- /ssdp-core/src/test/java/com/jerabi/ssdp/message/ServiceInfoTest.java: -------------------------------------------------------------------------------- 1 | package com.jerabi.ssdp.message; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import java.util.HashMap; 6 | import java.util.Map; 7 | import java.util.TreeMap; 8 | 9 | import org.junit.Before; 10 | import org.junit.BeforeClass; 11 | import org.junit.Test; 12 | 13 | import com.jerabi.ssdp.message.ServiceInfo; 14 | import com.jerabi.ssdp.message.USNInfo; 15 | 16 | public class ServiceInfoTest { 17 | 18 | @BeforeClass 19 | public static void setUpBeforeClass() throws Exception { 20 | } 21 | 22 | @Before 23 | public void setUp() throws Exception { 24 | } 25 | 26 | @Test 27 | public void testServiceInfo() { 28 | 29 | String host = "host"; 30 | int port = 10; 31 | String nt = "nt"; 32 | String location = "http://location:xxxx/path"; 33 | USNInfo usn = new USNInfo("uuid", "urn"); 34 | 35 | ServiceInfo serviceInfo = new ServiceInfo(host, port, nt, location, usn); 36 | 37 | assertEquals(host, serviceInfo.getHost()); 38 | assertEquals(port, serviceInfo.getPort()); 39 | assertEquals(nt, serviceInfo.getNt()); 40 | assertEquals(location, serviceInfo.getLocation()); 41 | assertEquals("/path", serviceInfo.getLocationPath()); 42 | assertEquals(usn, serviceInfo.getUsn()); 43 | 44 | ServiceInfo serviceInfo2 = new ServiceInfo(); 45 | 46 | serviceInfo2.setHost(serviceInfo.getHost()); 47 | serviceInfo2.setLocation(serviceInfo.getLocation()); 48 | assertEquals("/path", serviceInfo2.getLocationPath()); 49 | serviceInfo2.setNt(serviceInfo.getNt()); 50 | serviceInfo2.setPort(serviceInfo.getPort()); 51 | serviceInfo2.setUsn(usn); 52 | 53 | assertEquals(serviceInfo, serviceInfo2); 54 | 55 | assertNotNull(serviceInfo.toString()); 56 | 57 | } 58 | 59 | @Test 60 | public void testLocationPath() { 61 | ServiceInfo serviceInfo = new ServiceInfo(); 62 | 63 | assertNull(serviceInfo.getLocationPath()); 64 | 65 | serviceInfo.setLocation("/path"); 66 | assertNull(serviceInfo.getLocationPath()); 67 | 68 | serviceInfo.setLocation("http://localhost:1111/path"); 69 | assertEquals("/path", serviceInfo.getLocationPath()); 70 | 71 | serviceInfo.setLocation("http://localhost/path"); 72 | assertEquals("/path", serviceInfo.getLocationPath()); 73 | 74 | serviceInfo.setLocation("http://localhost"); 75 | assertEquals("", serviceInfo.getLocationPath()); 76 | 77 | serviceInfo.setLocation("http://localhost/"); 78 | assertEquals("/", serviceInfo.getLocationPath()); 79 | 80 | } 81 | 82 | @Test 83 | public void testEquals() { 84 | String host = "host"; 85 | int port = 10; 86 | String nt = "nt"; 87 | String location = "http://location:xxxx/path"; 88 | USNInfo usn = new USNInfo("uuid", "urn"); 89 | 90 | try { 91 | 92 | ServiceInfo serviceInfo1 = new ServiceInfo(host, port, nt, location, usn); 93 | ServiceInfo serviceInfo2 = new ServiceInfo(host, port, nt, location, usn); 94 | ServiceInfo serviceInfo3 = new ServiceInfo(); 95 | 96 | assertEquals(serviceInfo1, serviceInfo1); 97 | assertEquals(serviceInfo1, serviceInfo2); 98 | assertEquals(serviceInfo2, serviceInfo1); 99 | 100 | assertTrue(serviceInfo3.equals(new ServiceInfo(null, 0, null, null, null))); 101 | 102 | } catch (Exception e) { 103 | fail(); 104 | } 105 | 106 | } 107 | 108 | @Test 109 | public void testNotEquals() { 110 | String host = "host"; 111 | int port = 10; 112 | String nt = "nt"; 113 | String location = "http://location:xxxx/path"; 114 | USNInfo usn = new USNInfo("uuid", "urn"); 115 | 116 | try { 117 | ServiceInfo serviceInfo1 = new ServiceInfo(host, port, nt, location, usn); 118 | ServiceInfo serviceInfo2 = new ServiceInfo(); 119 | 120 | assertFalse(serviceInfo1.equals(null)); 121 | assertFalse(serviceInfo2.equals("string")); 122 | 123 | ServiceInfo serviceInfo3 = new ServiceInfo(); 124 | assertFalse(serviceInfo3.equals(serviceInfo1)); 125 | 126 | assertFalse(serviceInfo1.equals(serviceInfo3)); 127 | 128 | assertFalse(serviceInfo2.equals(new ServiceInfo(host, 0, null, null, null))); 129 | assertFalse(serviceInfo2.equals(new ServiceInfo(null, 0, null, "", null))); 130 | 131 | assertFalse(serviceInfo2.equals(new ServiceInfo(null, 0, null, null, usn))); 132 | 133 | assertFalse(serviceInfo2.equals(new ServiceInfo(null, 0, "", null, null))); 134 | 135 | assertFalse(serviceInfo2.equals(new ServiceInfo(null, port, null, null, null))); 136 | assertFalse(serviceInfo1.equals(new ServiceInfo(host, port, "", null, null))); 137 | assertFalse(serviceInfo1.equals(new ServiceInfo(host, port, nt, location, null))); 138 | assertFalse(serviceInfo1.equals(new ServiceInfo(host, port, null, location, null))); 139 | 140 | assertFalse(serviceInfo2.equals(new ServiceInfo(null, port, "", null, usn))); 141 | assertFalse(serviceInfo2.equals(new ServiceInfo(null, port, "", null, new USNInfo("uuid1", "urn1")))); 142 | 143 | 144 | } catch (Exception e) { 145 | fail(); 146 | } 147 | } 148 | 149 | @Test 150 | public void testCompare() { 151 | String host = "host"; 152 | int port = 10; 153 | String nt = "nt"; 154 | String location = "http://location:xxxx/path"; 155 | USNInfo usn = new USNInfo("uuid", "urn"); 156 | 157 | try { 158 | ServiceInfo serviceInfo1 = new ServiceInfo(host+1, port, nt, location, usn); 159 | ServiceInfo serviceInfo2 = new ServiceInfo(host+4, port, nt, location, usn); 160 | ServiceInfo serviceInfo3 = new ServiceInfo(host+3, port, nt, location, usn); 161 | ServiceInfo serviceInfo4 = new ServiceInfo(host+2, port, nt, location, usn); 162 | ServiceInfo serviceInfo5 = new ServiceInfo(host+0, port, nt, location, usn); 163 | 164 | Map map = new TreeMap(); 165 | 166 | map.put(serviceInfo1, serviceInfo1); 167 | map.put(serviceInfo2, serviceInfo2); 168 | map.put(serviceInfo3, serviceInfo3); 169 | map.put(serviceInfo4, serviceInfo4); 170 | map.put(serviceInfo5, serviceInfo5); 171 | 172 | // the order should be 5,1,4,3,2 173 | int i=0; 174 | for (ServiceInfo item : map.values()) { 175 | 176 | switch (i) { 177 | case 0: 178 | assertEquals(serviceInfo5, item); 179 | break; 180 | case 1: 181 | assertEquals(serviceInfo1, item); 182 | break; 183 | case 2: 184 | assertEquals(serviceInfo4, item); 185 | break; 186 | case 3: 187 | assertEquals(serviceInfo3, item); 188 | break; 189 | case 4: 190 | assertEquals(serviceInfo2, item); 191 | break; 192 | } 193 | i++; 194 | } 195 | 196 | } catch (Exception e) { 197 | fail(); 198 | } 199 | } 200 | 201 | @Test 202 | public void testHashCode() { 203 | String host = "host"; 204 | int port = 10; 205 | String nt = "nt"; 206 | String location = "http://location:xxxx/path"; 207 | USNInfo usn = new USNInfo("uuid", "urn"); 208 | 209 | try { 210 | ServiceInfo serviceInfo1 = new ServiceInfo(host, port, nt, location, usn); 211 | ServiceInfo serviceInfo2 = new ServiceInfo(host+2, port, nt, location, usn); 212 | ServiceInfo serviceInfo3 = new ServiceInfo(); 213 | 214 | Map map = new HashMap(); 215 | 216 | map.put(serviceInfo1, serviceInfo1); 217 | map.put(serviceInfo1, serviceInfo1); 218 | map.put(serviceInfo1, serviceInfo1); 219 | map.put(serviceInfo2, serviceInfo2); 220 | map.put(serviceInfo3, serviceInfo3); 221 | 222 | assertEquals(3, map.size()); 223 | 224 | } catch (Exception e) { 225 | fail(); 226 | } 227 | } 228 | 229 | } 230 | -------------------------------------------------------------------------------- /ssdp-core/src/test/java/com/jerabi/ssdp/message/USNInfoTest.java: -------------------------------------------------------------------------------- 1 | package com.jerabi.ssdp.message; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import java.util.HashMap; 6 | import java.util.Map; 7 | import java.util.TreeMap; 8 | 9 | import org.junit.Before; 10 | import org.junit.Test; 11 | 12 | import com.jerabi.ssdp.message.USNInfo; 13 | 14 | public class USNInfoTest { 15 | 16 | 17 | @Before 18 | public void setUp() throws Exception { 19 | } 20 | 21 | @Test 22 | @SuppressWarnings("unused") 23 | public void testUSNInfoNullUSN() { 24 | 25 | boolean exception = false; 26 | 27 | try { 28 | USNInfo usnInfo = new USNInfo(null); 29 | } catch (Exception e) { 30 | exception = true; 31 | } 32 | 33 | if(!exception){ 34 | fail("Should had thrown Exception"); 35 | } 36 | } 37 | 38 | @Test 39 | @SuppressWarnings("unused") 40 | public void testUSNInfoInvalidUSN() { 41 | 42 | boolean exception = false; 43 | 44 | try { 45 | USNInfo usnInfo = new USNInfo(""); 46 | } catch (Exception e) { 47 | exception = true; 48 | } 49 | 50 | if(!exception){ 51 | fail("Should had thrown Exception"); 52 | } 53 | 54 | exception = false; 55 | 56 | try { 57 | USNInfo usnInfo = new USNInfo("uuid:abc:urn:def"); 58 | } catch (Exception e) { 59 | exception = true; 60 | } 61 | 62 | if(!exception){ 63 | fail("Should had thrown Exception"); 64 | } 65 | 66 | } 67 | 68 | @Test 69 | @SuppressWarnings("unused") 70 | public void testUSNInfoValidUSN() { 71 | 72 | String usn = "uuid:9dcf6222-fc4b-33eb-bf49-e54643b4f416::urn:schemas-upnp-org:service:ContentDirectory:1"; 73 | 74 | boolean exception = false; 75 | 76 | try { 77 | USNInfo usnInfo = new USNInfo(usn); 78 | } catch (Exception e) { 79 | exception = true; 80 | } 81 | 82 | if(exception){ 83 | fail(); 84 | } 85 | 86 | exception = false; 87 | 88 | try { 89 | USNInfo usnInfo = new USNInfo("::"); 90 | } catch (Exception e) { 91 | exception = true; 92 | } 93 | 94 | if(exception){ 95 | fail(); 96 | } 97 | 98 | try { 99 | USNInfo usnInfo = new USNInfo("abc::"); 100 | } catch (Exception e) { 101 | exception = true; 102 | } 103 | 104 | if(exception){ 105 | fail(); 106 | } 107 | 108 | try { 109 | USNInfo usnInfo = new USNInfo("abc","def"); 110 | } catch (Exception e) { 111 | exception = true; 112 | } 113 | 114 | if(exception){ 115 | fail(); 116 | } 117 | 118 | try { 119 | USNInfo usnInfo = new USNInfo(null, null); 120 | } catch (Exception e) { 121 | exception = true; 122 | } 123 | 124 | if(exception){ 125 | fail(); 126 | } 127 | 128 | try { 129 | USNInfo usnInfo = new USNInfo(null, null); 130 | usnInfo.setUuid("uuid1"); 131 | usnInfo.setUrn("urn1"); 132 | 133 | assertEquals("uuid:uuid1::urn1", usnInfo.toString()); 134 | } catch (Exception e) { 135 | exception = true; 136 | } 137 | 138 | if(exception){ 139 | fail(); 140 | } 141 | } 142 | 143 | @Test 144 | public void testToString() { 145 | 146 | String usn = "uuid:9dcf6222-fc4b-33eb-bf49-e54643b4f416::urn:schemas-upnp-org:service:ContentDirectory:1"; 147 | 148 | 149 | try { 150 | USNInfo usnInfo = new USNInfo(usn); 151 | 152 | assertEquals(usn, usnInfo.toString()); 153 | assertEquals("uuid:9dcf6222-fc4b-33eb-bf49-e54643b4f416", usnInfo.getUuid()); 154 | assertEquals("urn:schemas-upnp-org:service:ContentDirectory:1", usnInfo.getUrn()); 155 | 156 | } catch (Exception e) { 157 | fail(); 158 | } 159 | 160 | try { 161 | USNInfo usnInfo = new USNInfo("uuid:uuid1", null); 162 | 163 | assertEquals("uuid:uuid1", usnInfo.toString()); 164 | assertEquals("uuid:uuid1", usnInfo.getUuid()); 165 | assertEquals(null, usnInfo.getUrn()); 166 | 167 | } catch (Exception e) { 168 | fail(); 169 | } 170 | 171 | } 172 | 173 | @Test 174 | public void testEquals() { 175 | String usn1 = "uuid:uuid1::urn:urn1"; 176 | String usn2 = "uuid:uuid1::urn:urn1"; 177 | 178 | try { 179 | USNInfo usnInfo1 = new USNInfo(usn1); 180 | USNInfo usnInfo2 = new USNInfo(usn2); 181 | 182 | assertEquals(usnInfo1, usnInfo1); 183 | assertEquals(usnInfo1, usnInfo2); 184 | assertEquals(usnInfo2, usnInfo1); 185 | 186 | assertFalse(usnInfo1.equals(null)); 187 | assertFalse(usnInfo1.equals("string")); 188 | 189 | USNInfo usnInfo3 = new USNInfo(null, "urn1"); 190 | assertTrue(usnInfo3.equals(new USNInfo(null, "urn1"))); 191 | 192 | 193 | } catch (Exception e) { 194 | fail(); 195 | } 196 | 197 | } 198 | 199 | @Test 200 | public void testNotEquals() { 201 | String usn1 = "uuid:uuid1::urn:urn1"; 202 | String usn2 = "uuid:uuid2::urn:urn2"; 203 | 204 | try { 205 | USNInfo usnInfo1 = new USNInfo(usn1); 206 | USNInfo usnInfo2 = new USNInfo(usn2); 207 | 208 | assertFalse(usnInfo1.equals(usnInfo2)); 209 | assertFalse(usnInfo2.equals(usnInfo1)); 210 | 211 | USNInfo usnInfo3 = new USNInfo(null, null); 212 | assertFalse(usnInfo3.equals(usnInfo1)); 213 | 214 | USNInfo usnInfo4 = new USNInfo(null, "urn"); 215 | assertFalse(usnInfo4.equals(usnInfo1)); 216 | 217 | USNInfo usnInfo5 = new USNInfo(null, "urn1"); 218 | assertFalse(usnInfo5.equals(usnInfo1)); 219 | 220 | USNInfo usnInfo6 = new USNInfo("uuid1", null); 221 | assertFalse(usnInfo6.equals(usnInfo1)); 222 | 223 | USNInfo usnInfo7 = new USNInfo("uuid1", null); 224 | assertFalse(usnInfo7.equals(new USNInfo("uuid2", null))); 225 | 226 | USNInfo usnInfo8 = new USNInfo(null, "urn1"); 227 | assertFalse(usnInfo8.equals(new USNInfo("uuid2", "urn1"))); 228 | 229 | USNInfo usnInfo9 = new USNInfo(null, "urn1"); 230 | assertFalse(usnInfo9.equals(new USNInfo(null, "urn2"))); 231 | 232 | USNInfo usnInfo10 = new USNInfo(null, "urn1"); 233 | assertFalse(usnInfo10.equals(new USNInfo(null, null))); 234 | 235 | } catch (Exception e) { 236 | fail(); 237 | } 238 | } 239 | 240 | @Test 241 | public void testCompare() { 242 | 243 | try { 244 | USNInfo usnInfo1 = new USNInfo("uuid:uuid1::urn:urn1"); 245 | USNInfo usnInfo2 = new USNInfo("uuid:uuid3::urn:urn2"); 246 | USNInfo usnInfo3 = new USNInfo("uuid:uuid2::urn:urn2"); 247 | USNInfo usnInfo4 = new USNInfo("uuid:uuid2::urn:urn1"); 248 | USNInfo usnInfo5 = new USNInfo("uuid:uuid1::urn:urn0"); 249 | 250 | Map map = new TreeMap(); 251 | 252 | map.put(usnInfo1, usnInfo1); 253 | map.put(usnInfo2, usnInfo2); 254 | map.put(usnInfo3, usnInfo3); 255 | map.put(usnInfo4, usnInfo4); 256 | map.put(usnInfo5, usnInfo5); 257 | 258 | // the order should be 5,1,4,3,2 259 | int i=0; 260 | for (USNInfo item : map.values()) { 261 | 262 | switch (i) { 263 | case 0: 264 | assertEquals(usnInfo5, item); 265 | break; 266 | case 1: 267 | assertEquals(usnInfo1, item); 268 | break; 269 | case 2: 270 | assertEquals(usnInfo4, item); 271 | break; 272 | case 3: 273 | assertEquals(usnInfo3, item); 274 | break; 275 | case 4: 276 | assertEquals(usnInfo2, item); 277 | break; 278 | } 279 | i++; 280 | } 281 | 282 | } catch (Exception e) { 283 | fail(); 284 | } 285 | } 286 | 287 | @Test 288 | public void testHashCode() { 289 | 290 | try { 291 | USNInfo usnInfo1 = new USNInfo("uuid:uuid1::urn:urn1"); 292 | USNInfo usnInfo2 = new USNInfo("uuid:uuid3::urn:urn2"); 293 | USNInfo usnInfo3 = new USNInfo(null,null); 294 | 295 | Map map = new HashMap(); 296 | 297 | map.put(usnInfo1, usnInfo1); 298 | map.put(usnInfo1, usnInfo1); 299 | map.put(usnInfo1, usnInfo1); 300 | map.put(usnInfo2, usnInfo2); 301 | map.put(usnInfo3, usnInfo3); 302 | 303 | assertEquals(3, map.size()); 304 | 305 | } catch (Exception e) { 306 | fail(); 307 | } 308 | } 309 | 310 | } 311 | -------------------------------------------------------------------------------- /ssdp-core/src/test/java/com/jerabi/ssdp/util/StateHolderTest.java: -------------------------------------------------------------------------------- 1 | package com.jerabi.ssdp.util; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import java.util.concurrent.CountDownLatch; 6 | 7 | import org.junit.After; 8 | import org.junit.Before; 9 | import org.junit.BeforeClass; 10 | import org.junit.Test; 11 | 12 | import com.jerabi.ssdp.util.IStateListener; 13 | import com.jerabi.ssdp.util.State; 14 | import com.jerabi.ssdp.util.StateHolder; 15 | 16 | public class StateHolderTest { 17 | 18 | private static StateHolder stateHolder = null; 19 | 20 | @BeforeClass 21 | public static void setUpBeforeClass() throws Exception { 22 | } 23 | 24 | @Before 25 | public void setUp() throws Exception { 26 | stateHolder = new StateHolder(); 27 | } 28 | 29 | @After 30 | public void tearDown() throws Exception { 31 | } 32 | 33 | @Test 34 | public void testStateHolderChangeStates() { 35 | 36 | assertNull(stateHolder.getState()); 37 | 38 | stateHolder.setState(State.STARTED); 39 | assertEquals(State.STARTED, stateHolder.getState()); 40 | 41 | stateHolder.setState(State.STARTED); 42 | assertEquals(State.STARTED, stateHolder.getState()); 43 | 44 | stateHolder.setState(State.STOPPED); 45 | assertEquals(State.STOPPED, stateHolder.getState()); 46 | 47 | stateHolder.setState(State.SUSPENDED); 48 | assertEquals(State.SUSPENDED, stateHolder.getState()); 49 | 50 | final CountDownLatch latch = new CountDownLatch(2); 51 | 52 | IStateListener listener = new IStateListener() { 53 | 54 | public void notifyStateChange(State state) { 55 | latch.countDown(); 56 | } 57 | }; 58 | 59 | stateHolder.addStateListener(listener); 60 | 61 | stateHolder.setState(State.STOPPED); 62 | stateHolder.setState(State.STARTED); 63 | 64 | assertEquals(0, latch.getCount()); 65 | 66 | stateHolder.removeStateListener(listener); 67 | 68 | stateHolder.setState(State.SLEEP); 69 | 70 | stateHolder.addStateListener(null); 71 | stateHolder.removeStateListener(null); 72 | 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /ssdp-core/src/test/java/com/jerabi/ssdp/util/UUIDGeneratorTest.java: -------------------------------------------------------------------------------- 1 | package com.jerabi.ssdp.util; 2 | 3 | import static org.junit.Assert.*; 4 | import static org.junit.Assert.assertEquals; 5 | import static org.junit.Assert.assertNotNull; 6 | import static org.junit.Assert.fail; 7 | 8 | import java.net.InetAddress; 9 | import java.net.NetworkInterface; 10 | import java.util.HashMap; 11 | import java.util.Map; 12 | 13 | import org.junit.After; 14 | import org.junit.Before; 15 | import org.junit.BeforeClass; 16 | import org.junit.Test; 17 | 18 | import com.jerabi.ssdp.util.UUIDGenerator; 19 | 20 | public class UUIDGeneratorTest { 21 | 22 | @BeforeClass 23 | public static void setUpBeforeClass() throws Exception { 24 | } 25 | 26 | @Before 27 | public void setUp() throws Exception { 28 | } 29 | 30 | @After 31 | public void tearDown() throws Exception { 32 | } 33 | 34 | @Test 35 | public void testGetUUID() { 36 | 37 | Map map = new HashMap(); 38 | 39 | for(int i=0;i<100;i++){ 40 | String uuid = UUIDGenerator.getUUID(); 41 | if(map.containsKey(uuid)){ 42 | fail("UUID already exist"); 43 | } 44 | map.put(uuid, uuid); 45 | } 46 | 47 | 48 | } 49 | 50 | @Test 51 | public void testGetUUIDWithMAC() { 52 | 53 | String initialUUID = null; 54 | 55 | try { 56 | initialUUID = UUIDGenerator.getUUID(NetworkInterface.getByInetAddress(InetAddress.getLocalHost())); 57 | } catch (Exception e) { 58 | fail("Should not throws Exception"); 59 | } 60 | 61 | for(int i=0;i<100;i++){ 62 | String uuid = null; 63 | try { 64 | uuid = UUIDGenerator.getUUID(NetworkInterface.getByInetAddress(InetAddress.getLocalHost())); 65 | } catch (Exception e) { 66 | fail("Should not throws Exception"); 67 | } 68 | 69 | assertNotNull(uuid); 70 | assertEquals(initialUUID, uuid); 71 | } 72 | 73 | } 74 | 75 | @Test 76 | public void testGetUUIDWithNullNetworkInterface() { 77 | 78 | String initialUUID = null; 79 | 80 | try { 81 | initialUUID = UUIDGenerator.getUUID(null); 82 | } catch (Exception e) { 83 | fail("Should not throws Exception"); 84 | } 85 | 86 | assertNull(initialUUID); 87 | 88 | } 89 | 90 | } 91 | -------------------------------------------------------------------------------- /ssdp-demo/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | ssdp 4 | com.jerabi 5 | 0.0.1-SNAPSHOT 6 | 7 | 4.0.0 8 | com.jerabi 9 | ssdp-demo 10 | ssdp-demo 11 | 0.0.1-SNAPSHOT 12 | ssdp demo 13 | 14 | 15 | 16 | org.apache.maven.plugins 17 | maven-compiler-plugin 18 | 19 | 1.6 20 | 1.6 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | com.jerabi 29 | ssdp-core 30 | 0.0.1-SNAPSHOT 31 | 32 | 33 | com.jerabi.ssdp-network 34 | default-impl 35 | 0.0.1-SNAPSHOT 36 | 37 | 38 | -------------------------------------------------------------------------------- /ssdp-demo/src/main/java/com/jerabi/ssdp/demo/Multihome.java: -------------------------------------------------------------------------------- 1 | package com.jerabi.ssdp.demo; 2 | 3 | /** 4 | * Demonstrate multi-homed multicast listening 5 | * 6 | * usage: java Multihome eth0 eth1 lo 7 | */ 8 | 9 | import java.io.IOException; 10 | import java.net.DatagramPacket; 11 | import java.net.InetAddress; 12 | import java.net.InetSocketAddress; 13 | import java.net.MulticastSocket; 14 | import java.net.NetworkInterface; 15 | import java.net.SocketException; 16 | import java.util.Enumeration; 17 | import java.util.HashSet; 18 | import java.util.Set; 19 | 20 | public class Multihome { 21 | // SDP constants 22 | public static final String MULTICAST_ADDRESS = "239.255.255.250"; 23 | public static final int MULTICAST_PORT = 1900; 24 | 25 | // args: each arg is the name of an interface. 26 | public void doMain(Set args) 27 | throws Exception 28 | { 29 | InetSocketAddress socketAddress = 30 | new InetSocketAddress(MULTICAST_ADDRESS, MULTICAST_PORT); 31 | MulticastSocket socket = new MulticastSocket(MULTICAST_PORT); 32 | Enumeration ifs = 33 | NetworkInterface.getNetworkInterfaces(); 34 | 35 | while (ifs.hasMoreElements()) { 36 | NetworkInterface xface = ifs.nextElement(); 37 | Enumeration addrs = xface.getInetAddresses(); 38 | String name = xface.getName(); 39 | 40 | while (addrs.hasMoreElements()) { 41 | InetAddress addr = addrs.nextElement(); 42 | 43 | System.out.println(name + " ... has addr " + addr); 44 | } 45 | 46 | if (args.contains(name)) { 47 | System.out.println("Adding " + name + " to our interface set"); 48 | socket.joinGroup(socketAddress, xface); 49 | } 50 | } 51 | 52 | byte[] buffer = new byte[1500]; 53 | DatagramPacket packet = new DatagramPacket(buffer, buffer.length); 54 | 55 | while (true) { 56 | try { 57 | packet.setData(buffer, 0, buffer.length); 58 | socket.receive(packet); 59 | System.out.println("Received pkt from " + packet.getAddress() + 60 | " of length " + packet.getLength() + new String(packet.getData())); 61 | } catch (IOException ex) { 62 | ex.printStackTrace(); 63 | } 64 | } 65 | } 66 | 67 | public static void main(String[] args) 68 | throws Exception 69 | { 70 | Set argSet = new HashSet(); 71 | Multihome multi = new Multihome(); 72 | 73 | for (String arg : args) { 74 | argSet.add(arg); 75 | } 76 | 77 | multi.doMain(argSet); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /ssdp-demo/src/main/java/com/jerabi/ssdp/demo/SSDPClient.java: -------------------------------------------------------------------------------- 1 | package com.jerabi.ssdp.demo; 2 | 3 | import java.net.NetworkInterface; 4 | import java.util.ArrayList; 5 | import java.util.List; 6 | import java.util.logging.Logger; 7 | 8 | import com.jerabi.ssdp.SSDPControler; 9 | import com.jerabi.ssdp.handler.SSDPDefaultMessageHandler; 10 | import com.jerabi.ssdp.handler.SSDPDefaultResponseHandler; 11 | import com.jerabi.ssdp.handler.SSDPDiscoverResponseHandler; 12 | 13 | public class SSDPClient { 14 | 15 | private static final Logger s_logger = Logger.getLogger(SSDPClient.class.getName()); 16 | 17 | public SSDPControler controler = null; 18 | 19 | public void start() throws Exception { 20 | 21 | // will dispatch the responses from the handlers to the listener 22 | controler = new SSDPControler(); 23 | 24 | // pas besoin pour le client 25 | controler.setPeriodicSenderEnabled(false); 26 | 27 | // on cherche les serveurs 28 | controler.setDiscoverSenderEnabled(true); 29 | 30 | // le client peut-etre interesse par les alive des serveurs et byebye 31 | controler.setMulticastListenerEnabled(false); 32 | 33 | // will handle the responses 34 | controler.addMessageHandler(new SSDPDefaultMessageHandler()); 35 | 36 | // this will handle the messages received by the multicastListener 37 | controler.getMulticastListener().setSSDPResponseHandler(new SSDPDefaultResponseHandler(controler)); 38 | 39 | // this will handle discover response 40 | controler.getDiscoverSender().setSSDPResponseHandler(new SSDPDiscoverResponseHandler(controler)); 41 | 42 | 43 | controler.getDiscoverSender().setDelay(5000); 44 | 45 | s_logger.fine("starting controler"); 46 | 47 | controler.start(); 48 | } 49 | 50 | public void stop() throws Exception { 51 | controler.stop(); 52 | } 53 | 54 | /** 55 | * @param args 56 | */ 57 | public static void main(String[] args) throws Exception { 58 | 59 | SSDPClient client = new SSDPClient(); 60 | 61 | client.start(); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /ssdp-demo/src/main/java/com/jerabi/ssdp/demo/SSDPMulticastSniffer.java: -------------------------------------------------------------------------------- 1 | package com.jerabi.ssdp.demo; 2 | 3 | 4 | import java.net.InetSocketAddress; 5 | import java.net.NetworkInterface; 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | import com.jerabi.ssdp.handler.SSDPDefaultResponseHandler; 10 | import com.jerabi.ssdp.listener.SSDPMulticastListener; 11 | import com.jerabi.ssdp.util.SSDPContants; 12 | 13 | public class SSDPMulticastSniffer { 14 | 15 | /** 16 | * @param args 17 | */ 18 | public static void main(String[] args) throws Exception { 19 | 20 | //SSDPMulticastListener listener = new SSDPMulticastListener(SSDPContants.DEFAULT_IP, SSDPContants.DEFAULT_PORT); 21 | 22 | List networkInterfaceList = new ArrayList(); 23 | 24 | networkInterfaceList.add(NetworkInterface.getByName("net5")); 25 | networkInterfaceList.add(NetworkInterface.getByName("eth13")); 26 | 27 | SSDPMulticastListener listener = new SSDPMulticastListener(new InetSocketAddress(SSDPContants.DEFAULT_IP, SSDPContants.DEFAULT_PORT), networkInterfaceList); 28 | listener.setSSDPResponseHandler(new SSDPDefaultResponseHandler(null)); 29 | listener.setBlocking(false); 30 | 31 | System.out.println("Starting MulticastListener"); 32 | new Thread(listener).start(); 33 | 34 | //System.out.println("Waiting 30 sec. before quitting"); 35 | //Thread.sleep(30000); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /ssdp-demo/src/main/java/com/jerabi/ssdp/demo/SSDPServer.java: -------------------------------------------------------------------------------- 1 | package com.jerabi.ssdp.demo; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.logging.Logger; 6 | 7 | import com.jerabi.ssdp.SSDPControler; 8 | import com.jerabi.ssdp.handler.SSDPDefaultResponseHandler; 9 | import com.jerabi.ssdp.handler.SSDPDefaultMessageHandler; 10 | import com.jerabi.ssdp.handler.SSDPDiscoverResponseHandler; 11 | import com.jerabi.ssdp.message.AliveMessage; 12 | import com.jerabi.ssdp.message.ServiceInfo; 13 | import com.jerabi.ssdp.message.ISSDPMessage; 14 | import com.jerabi.ssdp.message.USNInfo; 15 | import com.jerabi.ssdp.message.helper.SSDPMessageHelper; 16 | import com.jerabi.ssdp.sender.SSDPPeriodicMessageSender; 17 | import com.jerabi.ssdp.util.SSDPContants; 18 | 19 | public class SSDPServer { 20 | 21 | private static final Logger s_logger = Logger.getLogger(SSDPServer.class.getName()); 22 | 23 | public SSDPControler controler = null; 24 | 25 | 26 | public void start() throws Exception { 27 | // will dispatch the responses from the handlers to the listener 28 | controler = new SSDPControler(); 29 | 30 | // pas besoin pour le client 31 | controler.setPeriodicSenderEnabled(true); 32 | 33 | // on cherche les serveurs 34 | controler.setDiscoverSenderEnabled(false); 35 | 36 | // le client peut-etre interesse par les alive des serveurs et byebye 37 | controler.setMulticastListenerEnabled(true); 38 | 39 | // will handle the responses 40 | controler.addMessageHandler(new SSDPDefaultMessageHandler()); 41 | 42 | // this will handle the messages received by the multicastListener 43 | controler.getMulticastListener().setSSDPResponseHandler(new SSDPDefaultResponseHandler(controler)); 44 | 45 | // this will handle discover response 46 | controler.getDiscoverSender().setSSDPResponseHandler(new SSDPDiscoverResponseHandler(controler)); 47 | 48 | 49 | controler.setPeriodicMessageSender(new SSDPPeriodicMessageSender(controler, SSDPContants.DEFAULT_IP, SSDPContants.DEFAULT_PORT) { 50 | 51 | @Override 52 | public List getSSDPMessagesToSend() { 53 | List list = new ArrayList(); 54 | 55 | for (ServiceInfo deviceInfo : controler.getServiceInfoList()) { 56 | 57 | AliveMessage message = SSDPMessageHelper.createSSDPAliveMessage(deviceInfo); 58 | 59 | message.setCacheControl("max-age=1800"); 60 | message.setServer("Sebastien Dionne SSDP Demo"); 61 | 62 | list.add(message); 63 | } 64 | 65 | return list; 66 | } 67 | }); 68 | 69 | controler.getPeriodicMessageSender().setDelay(30000); 70 | 71 | // add device 72 | controler.getServiceInfoList().add(new ServiceInfo(SSDPContants.DEFAULT_IP, SSDPContants.DEFAULT_PORT, "upnp:rootdevice","http://142.225.35.55:5001/description/fetch", new USNInfo("9dcf6222-fc4b-33eb-bf49-e54643b4f416","upnp:rootdevice"))); 73 | controler.getServiceInfoList().add(new ServiceInfo(SSDPContants.DEFAULT_IP, SSDPContants.DEFAULT_PORT, "urn:schemas-upnp-org:service:ConnectionManager:1","http://142.225.35.55:5001/description/fetch", new USNInfo("9dcf6222-fc4b-33eb-bf49-e54643b4f416","schemas-upnp-org:service:ConnectionManager:1"))); 74 | controler.getServiceInfoList().add(new ServiceInfo(SSDPContants.DEFAULT_IP, SSDPContants.DEFAULT_PORT, "urn:schemas-upnp-org:service:ContentDirectory:1","http://142.225.35.55:5001/description/fetch", new USNInfo("9dcf6222-fc4b-33eb-bf49-e54643b4f416","schemas-upnp-org:service:ContentDirectory:1"))); 75 | controler.getServiceInfoList().add(new ServiceInfo(SSDPContants.DEFAULT_IP, SSDPContants.DEFAULT_PORT, "urn:schemas-upnp-org:device:MediaServer:1","http://142.225.35.55:5001/description/fetch", new USNInfo("9dcf6222-fc4b-33eb-bf49-e54643b4f416","schemas-upnp-org:device:MediaServer:1"))); 76 | 77 | 78 | 79 | s_logger.fine("starting controler"); 80 | 81 | controler.start(); 82 | } 83 | 84 | public void stop() throws Exception { 85 | controler.stop(); 86 | } 87 | 88 | /** 89 | * @param args 90 | */ 91 | public static void main(String[] args) throws Exception { 92 | 93 | SSDPServer server = new SSDPServer(); 94 | server.start(); 95 | 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /ssdp-network/default-impl/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | com.jerabi.ssdp-network 4 | ssdp-network 5 | 0.0.1-SNAPSHOT 6 | 7 | 4.0.0 8 | com.jerabi.ssdp-network 9 | default-impl 10 | default-impl 11 | 0.0.1-SNAPSHOT 12 | ssdp default network UDP impl 13 | 14 | 15 | 16 | org.apache.maven.plugins 17 | maven-compiler-plugin 18 | 19 | 1.6 20 | 1.6 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | com.jerabi 29 | ssdp-core 30 | 0.0.1-SNAPSHOT 31 | 32 | 33 | -------------------------------------------------------------------------------- /ssdp-network/default-impl/src/main/java/com/jerabi/ssdp/network/impl/MulticastListener.java: -------------------------------------------------------------------------------- 1 | package com.jerabi.ssdp.network.impl; 2 | 3 | import java.net.DatagramPacket; 4 | import java.net.InetAddress; 5 | import java.net.MulticastSocket; 6 | import java.net.NetworkInterface; 7 | import java.net.SocketAddress; 8 | 9 | import com.jerabi.ssdp.handler.ISSDPResponseHandler; 10 | import com.jerabi.ssdp.network.IMulticastListener; 11 | 12 | /** 13 | * 14 | * @author Sebastien Dionne 15 | * @see MulticastSocket 16 | */ 17 | public class MulticastListener implements IMulticastListener { 18 | 19 | private MulticastSocket ssdpUniSock = null; 20 | private ISSDPResponseHandler callbackHandler = null; 21 | private int timeout = 3000; 22 | 23 | public MulticastListener(int port, ISSDPResponseHandler callbackHandler) throws Exception { 24 | ssdpUniSock = new MulticastSocket(port); 25 | this.callbackHandler = callbackHandler; 26 | } 27 | 28 | public MulticastListener(SocketAddress bindAddress, ISSDPResponseHandler callbackHandler) throws Exception { 29 | ssdpUniSock = new MulticastSocket(bindAddress); 30 | this.callbackHandler = callbackHandler; 31 | } 32 | 33 | public MulticastListener(SocketAddress bindAddress, ISSDPResponseHandler callbackHandler, NetworkInterface ni) throws Exception { 34 | ssdpUniSock = new MulticastSocket(bindAddress); 35 | this.callbackHandler = callbackHandler; 36 | ssdpUniSock.setNetworkInterface(ni); 37 | } 38 | 39 | @Override 40 | public void joinGroup(InetAddress group) throws Exception { 41 | ssdpUniSock.joinGroup(group); 42 | 43 | } 44 | 45 | @Override 46 | public void joinGroup(SocketAddress socketAddress, NetworkInterface ni) throws Exception { 47 | ssdpUniSock.joinGroup(socketAddress, ni); 48 | } 49 | 50 | @Override 51 | public void leaveGroup(SocketAddress socketAddress, NetworkInterface ni) throws Exception { 52 | ssdpUniSock.leaveGroup(socketAddress, ni); 53 | } 54 | 55 | @Override 56 | public void leaveGroup(InetAddress group) throws Exception { 57 | ssdpUniSock.leaveGroup(group); 58 | } 59 | 60 | @Override 61 | public void receive() throws Exception { 62 | receive(false); 63 | } 64 | 65 | @Override 66 | public void receive(boolean blocking) throws Exception { 67 | byte ssdvRecvBuf[] = new byte[1024]; 68 | DatagramPacket dgmPacket2 = new DatagramPacket(ssdvRecvBuf, 1024); 69 | 70 | if(!blocking){ 71 | ssdpUniSock.setSoTimeout(timeout); 72 | } 73 | ssdpUniSock.receive(dgmPacket2); 74 | 75 | int packetLen = dgmPacket2.getLength(); 76 | String packetData = new String(dgmPacket2.getData(), 0, packetLen); 77 | 78 | // TODO en gros.. si la taille retournee est la meme que le buffer, 79 | // il y a de grosse chance qu'il reste du data cote serveur.. 80 | // donc faire une boucle 81 | 82 | if(callbackHandler!=null){ 83 | callbackHandler.handle(dgmPacket2.getAddress().getHostAddress(), dgmPacket2.getPort(), packetData); 84 | } 85 | 86 | } 87 | 88 | @Override 89 | public int getTimeout() { 90 | return timeout; 91 | } 92 | 93 | @Override 94 | public void setTimeout(int timeout) { 95 | this.timeout = timeout; 96 | } 97 | 98 | } 99 | -------------------------------------------------------------------------------- /ssdp-network/default-impl/src/main/java/com/jerabi/ssdp/network/impl/SSDPNetworkImpl.java: -------------------------------------------------------------------------------- 1 | package com.jerabi.ssdp.network.impl; 2 | 3 | import java.net.DatagramPacket; 4 | import java.net.InetAddress; 5 | import java.net.MulticastSocket; 6 | import java.net.NetworkInterface; 7 | import java.net.SocketAddress; 8 | import java.util.logging.Logger; 9 | 10 | import com.jerabi.ssdp.handler.ISSDPResponseHandler; 11 | import com.jerabi.ssdp.network.IMulticastListener; 12 | import com.jerabi.ssdp.network.ISSDPNetwork; 13 | import com.jerabi.ssdp.network.IUDPSender; 14 | import com.jerabi.ssdp.network.impl.SSDPNetworkImpl; 15 | 16 | /** 17 | * test default implementation ssdp network 18 | * @author Sebastien Dionne 19 | * 20 | */ 21 | public class SSDPNetworkImpl implements ISSDPNetwork { 22 | 23 | private static final Logger logger = Logger.getLogger(SSDPNetworkImpl.class.getName()); 24 | 25 | // SSDPPeriodicMessageSender -> 26 | /** 27 | * {@inheritDoc} 28 | */ 29 | @Override 30 | public void sendMulticastMessage(String msg, SocketAddress address) throws Exception { 31 | try { 32 | 33 | MulticastSocket ssdpUniSock = new MulticastSocket(null); 34 | ssdpUniSock.setReuseAddress(true); 35 | 36 | logger.info("sending message \n" + msg); 37 | 38 | DatagramPacket dgmPacket = new DatagramPacket(msg.getBytes(), msg.length(), address); 39 | 40 | ssdpUniSock.send(dgmPacket); 41 | 42 | ssdpUniSock.close(); 43 | 44 | } catch (Throwable e) { 45 | } 46 | 47 | } 48 | 49 | // SSDPPeriodicMessageSender -> 50 | /** 51 | * {@inheritDoc} 52 | */ 53 | @Override 54 | public void sendMulticastMessage(String msg, InetAddress address, int port) throws Exception { 55 | try { 56 | 57 | MulticastSocket ssdpUniSock = new MulticastSocket(null); 58 | ssdpUniSock.setReuseAddress(true); 59 | 60 | logger.info("sending message \n" + msg); 61 | 62 | DatagramPacket dgmPacket = new DatagramPacket(msg.getBytes(), msg.length(), address, port); 63 | 64 | ssdpUniSock.send(dgmPacket); 65 | 66 | ssdpUniSock.close(); 67 | 68 | } catch (Throwable e) { 69 | } 70 | 71 | } 72 | 73 | // SSDPPeriodicMessageSender -> 74 | /** 75 | * {@inheritDoc} 76 | */ 77 | @Override 78 | public void sendMulticastMessage(String message, SocketAddress address, ISSDPResponseHandler callbackHandler, int ttl) throws Exception { 79 | throw new RuntimeException("Not implemented"); 80 | } 81 | 82 | // SSDPPeriodicMessageSender -> 83 | /** 84 | * {@inheritDoc} 85 | */ 86 | @Override 87 | public void sendMulticastMessage(String message, InetAddress address, int port, ISSDPResponseHandler callbackHandler, int ttl) throws Exception { 88 | throw new RuntimeException("Not implemented"); 89 | } 90 | 91 | /** 92 | * {@inheritDoc} 93 | */ 94 | @Override 95 | public IMulticastListener createMulticastListener(int port, ISSDPResponseHandler callbackHandler) throws Exception { 96 | MulticastListener listener = new MulticastListener(port, callbackHandler); 97 | return listener; 98 | } 99 | 100 | /** 101 | * {@inheritDoc} 102 | */ 103 | @Override 104 | public IMulticastListener createMulticastListener(SocketAddress bindAddress, ISSDPResponseHandler callbackHandler) throws Exception { 105 | MulticastListener listener = new MulticastListener(bindAddress, callbackHandler); 106 | return listener; 107 | } 108 | 109 | /** 110 | * {@inheritDoc} 111 | */ 112 | @Override 113 | public IUDPSender createUDPSender(int port) throws Exception { 114 | UDPSender sender = new UDPSender(port); 115 | return sender; 116 | } 117 | 118 | /** 119 | * {@inheritDoc} 120 | */ 121 | @Override 122 | public IUDPSender createUDPSender() throws Exception { 123 | UDPSender sender = new UDPSender(); 124 | return sender; 125 | } 126 | 127 | @Override 128 | public IMulticastListener createMulticastListener(SocketAddress bindAddress, ISSDPResponseHandler callbackHandler, NetworkInterface ni) throws Exception { 129 | throw new RuntimeException("Not implemented"); 130 | } 131 | 132 | @Override 133 | public void sendMulticastMessage(String message, SocketAddress address, NetworkInterface ni) throws Exception { 134 | throw new RuntimeException("Not implemented"); 135 | } 136 | 137 | 138 | } 139 | -------------------------------------------------------------------------------- /ssdp-network/default-impl/src/main/java/com/jerabi/ssdp/network/impl/UDPSender.java: -------------------------------------------------------------------------------- 1 | package com.jerabi.ssdp.network.impl; 2 | 3 | import java.net.DatagramPacket; 4 | import java.net.DatagramSocket; 5 | import java.net.InetAddress; 6 | import java.net.InetSocketAddress; 7 | import java.net.SocketAddress; 8 | import java.net.SocketTimeoutException; 9 | import java.util.logging.Logger; 10 | 11 | import com.jerabi.ssdp.handler.ISSDPResponseHandler; 12 | import com.jerabi.ssdp.network.IUDPSender; 13 | 14 | /** 15 | * 16 | * @author Sebastien Dionne 17 | * 18 | */ 19 | public class UDPSender implements IUDPSender { 20 | private static final Logger logger = Logger.getLogger(UDPSender.class.getName()); 21 | 22 | private DatagramSocket ssdpUniSock = null; 23 | 24 | public UDPSender() throws Exception { 25 | 26 | ssdpUniSock = new DatagramSocket(null); 27 | ssdpUniSock.setReuseAddress(true); 28 | } 29 | 30 | public UDPSender(int port) throws Exception { 31 | 32 | ssdpUniSock = new DatagramSocket(null); 33 | ssdpUniSock.setReuseAddress(true); 34 | ssdpUniSock.bind(new InetSocketAddress(port)); 35 | } 36 | 37 | /** 38 | * {@inheritDoc} 39 | */ 40 | @Override 41 | public void sendMessage(String msg, SocketAddress address, ISSDPResponseHandler callbackHandler, int ttl) throws Exception { 42 | 43 | DatagramPacket dgmPacket = new DatagramPacket(msg.getBytes(), msg.length(), address); 44 | 45 | ssdpUniSock.send(dgmPacket); 46 | 47 | ssdpUniSock.setSoTimeout(ttl*1000); // convert to seconds 48 | 49 | byte buf[] = new byte[1024]; 50 | DatagramPacket dgmPacket2 = new DatagramPacket(buf, buf.length); 51 | ssdpUniSock.receive(dgmPacket2); 52 | 53 | int packetLen = dgmPacket2.getLength(); 54 | String packetData = new String(dgmPacket2.getData(), 0, packetLen); 55 | 56 | logger.finest("discover response : \n" + packetData); 57 | 58 | if(callbackHandler!=null){ 59 | callbackHandler.handle(dgmPacket2.getAddress().getHostAddress(), dgmPacket2.getPort(), packetData); 60 | } 61 | 62 | } 63 | 64 | /** 65 | * {@inheritDoc} 66 | */ 67 | @Override 68 | public void sendMessage(String msg, InetAddress address, int port, ISSDPResponseHandler callbackHandler, int ttl) throws Exception { 69 | 70 | DatagramPacket dgmPacket = new DatagramPacket(msg.getBytes(), msg.length(), address, port); 71 | 72 | ssdpUniSock.setSoTimeout(ttl*1000); // convert to seconds 73 | ssdpUniSock.send(dgmPacket); 74 | 75 | try { 76 | byte buf[] = new byte[1024]; 77 | DatagramPacket dgmPacket2 = new DatagramPacket(buf, buf.length); 78 | ssdpUniSock.receive(dgmPacket2); 79 | 80 | int packetLen = dgmPacket2.getLength(); 81 | String packetData = new String(dgmPacket2.getData(), 0, packetLen); 82 | 83 | logger.finest("discover response : \n" + packetData); 84 | 85 | if(callbackHandler!=null){ 86 | callbackHandler.handle(dgmPacket2.getAddress().getHostAddress(), dgmPacket2.getPort(), packetData); 87 | } 88 | } catch (SocketTimeoutException e) { 89 | // does nothing 90 | } 91 | 92 | } 93 | 94 | } 95 | -------------------------------------------------------------------------------- /ssdp-network/default-impl/src/test/java/com/jerabi/ssdp/listener/SSDPMulticastListenerTest.java: -------------------------------------------------------------------------------- 1 | package com.jerabi.ssdp.listener; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import java.io.IOException; 6 | import java.net.DatagramPacket; 7 | import java.net.DatagramSocket; 8 | import java.net.InetAddress; 9 | import java.net.NetworkInterface; 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | import java.util.concurrent.CountDownLatch; 13 | import java.util.concurrent.TimeUnit; 14 | 15 | import org.junit.*; 16 | 17 | import com.jerabi.ssdp.handler.SSDPDefaultResponseHandler; 18 | import com.jerabi.ssdp.listener.SSDPMulticastListener; 19 | import com.jerabi.ssdp.network.IMulticastListener; 20 | import com.jerabi.ssdp.network.SSDPNetworkFactory; 21 | import com.jerabi.ssdp.network.impl.SSDPNetworkImpl; 22 | import com.jerabi.ssdp.util.SSDPContants; 23 | import com.jerabi.ssdp.util.State; 24 | 25 | public class SSDPMulticastListenerTest { 26 | 27 | private static SSDPMulticastListener listener = null; 28 | private static Thread t = null; 29 | 30 | @BeforeClass 31 | public static void setUpBeforeClass() throws Exception { 32 | 33 | } 34 | 35 | @Before 36 | public void setUp() throws Exception { 37 | listener = new SSDPMulticastListener(SSDPContants.DEFAULT_IP, SSDPContants.DEFAULT_PORT, SSDPContants.DEFAULT_DELAY); 38 | t = new Thread(listener); 39 | } 40 | 41 | @After 42 | public void tearDown() throws Exception { 43 | if (t != null) { 44 | try { 45 | t.interrupt(); 46 | } catch (Exception e) { 47 | } 48 | } 49 | 50 | } 51 | 52 | private void sendUDP(String msg) throws IOException { 53 | DatagramSocket ssdpUniSock = new DatagramSocket(null); 54 | 55 | ssdpUniSock.setReuseAddress(true); 56 | 57 | //InetAddress inetAddr = InetAddress.getByAddress("239.255.255.250".getBytes()); 58 | InetAddress inetAddr = InetAddress.getByName("239.255.255.250"); 59 | 60 | DatagramPacket dgmPacket = new DatagramPacket(msg.getBytes(), msg.length(), inetAddr, 1900); 61 | 62 | ssdpUniSock.send(dgmPacket); 63 | ssdpUniSock.close(); 64 | } 65 | 66 | @Test 67 | public void testSSDPMulticastSetter() throws IOException { 68 | listener.setSSDPResponseHandler(null); 69 | 70 | assertNull(listener.getSSDPResponseHandler()); 71 | assertEquals(SSDPContants.DEFAULT_IP, listener.getHost()); 72 | assertEquals(SSDPContants.DEFAULT_PORT, listener.getPort()); 73 | assertEquals(SSDPContants.DEFAULT_DELAY, listener.getTimeout()); 74 | 75 | listener.setHost("127.0.0.1"); 76 | listener.setPort(12); 77 | listener.setTimeout(1234); 78 | listener.setBlocking(false); 79 | 80 | assertEquals("127.0.0.1", listener.getHost()); 81 | assertEquals(12, listener.getPort()); 82 | assertEquals(1234, listener.getTimeout()); 83 | assertEquals(false, listener.getBlocking()); 84 | 85 | listener.setBlocking(true); 86 | assertEquals(true, listener.getBlocking()); 87 | 88 | try { 89 | IMulticastListener listener2 = SSDPNetworkFactory.getInstance().createMulticastListener(11, null); 90 | listener2.setTimeout(1122); 91 | assertEquals(1122, listener2.getTimeout()); 92 | } catch (Exception e) { 93 | fail("Shouldn't throw Exception"); 94 | } 95 | } 96 | 97 | @Test 98 | public void testSSDPMulticastInvalidHost() throws IOException { 99 | listener.setSSDPResponseHandler(new SSDPDefaultResponseHandler(null) { 100 | @Override 101 | public void handle(String message) throws Exception { 102 | } 103 | 104 | @Override 105 | public void handle(String remoteAddr, int remotePort, String message) 106 | throws Exception { 107 | } 108 | 109 | }); 110 | 111 | assertNotNull(listener.getSSDPResponseHandler()); 112 | 113 | listener.setHost("-1"); 114 | 115 | t.start(); 116 | 117 | try { 118 | Thread.sleep(1000); 119 | } catch (InterruptedException e1) { 120 | e1.printStackTrace(); 121 | } 122 | } 123 | 124 | @Test 125 | public void testSSDPMulticastListenerHelloMessage() throws IOException { 126 | 127 | final String msg = "Hello from SSPDMulticastListenerTest"; 128 | final CountDownLatch countDown = new CountDownLatch(2); 129 | 130 | listener.setSSDPResponseHandler(null); 131 | 132 | assertNull(listener.getSSDPResponseHandler()); 133 | assertEquals(SSDPContants.DEFAULT_IP, listener.getHost()); 134 | assertEquals(SSDPContants.DEFAULT_PORT, listener.getPort()); 135 | assertEquals(SSDPContants.DEFAULT_DELAY, listener.getTimeout()); 136 | 137 | 138 | 139 | listener.setSSDPResponseHandler(new SSDPDefaultResponseHandler(null) { 140 | @Override 141 | public void handle(String message) throws Exception { 142 | if (msg.equals(message)) { 143 | countDown.countDown(); 144 | } 145 | } 146 | 147 | @Override 148 | public void handle(String remoteAddr, int remotePort, String message) 149 | throws Exception { 150 | if (msg.equals(message)) { 151 | countDown.countDown(); 152 | } 153 | } 154 | 155 | }); 156 | 157 | assertNotNull(listener.getSSDPResponseHandler()); 158 | 159 | t.start(); 160 | 161 | try { 162 | Thread.sleep(2000); 163 | } catch (InterruptedException e1) { 164 | e1.printStackTrace(); 165 | } 166 | 167 | sendUDP(msg); 168 | sendUDP(msg); 169 | 170 | try { 171 | countDown.await(10, TimeUnit.SECONDS); 172 | } catch (InterruptedException e) { 173 | e.printStackTrace(); 174 | } 175 | 176 | t.interrupt(); 177 | 178 | try { 179 | countDown.await(1, TimeUnit.SECONDS); 180 | } catch (InterruptedException e) { 181 | e.printStackTrace(); 182 | } 183 | 184 | assertEquals(0, countDown.getCount()); 185 | 186 | } 187 | 188 | @Test 189 | public void testSSDPMulticastListenerSSDPHandlerNull() throws IOException { 190 | 191 | final String msg = "Hello from SSPDMulticastListenerTest"; 192 | final CountDownLatch countDown = new CountDownLatch(2); 193 | 194 | listener.setSSDPResponseHandler(null); 195 | 196 | assertNull(listener.getSSDPResponseHandler()); 197 | 198 | t.start(); 199 | 200 | try { 201 | Thread.sleep(1000); 202 | } catch (InterruptedException e1) { 203 | e1.printStackTrace(); 204 | } 205 | 206 | sendUDP(msg); 207 | sendUDP(msg); 208 | 209 | try { 210 | countDown.await(10, TimeUnit.SECONDS); 211 | } catch (InterruptedException e) { 212 | e.printStackTrace(); 213 | } 214 | 215 | assertEquals(2, countDown.getCount()); 216 | 217 | } 218 | 219 | @Test 220 | public void testSSDPMulticastListenerInvalidHost() throws IOException { 221 | 222 | final String msg = "Hello from SSPDMulticastListenerTest"; 223 | final CountDownLatch countDown = new CountDownLatch(2); 224 | 225 | listener.setHost(null); 226 | listener.setSSDPResponseHandler(null); 227 | 228 | assertNull(listener.getSSDPResponseHandler()); 229 | 230 | t.start(); 231 | 232 | try { 233 | Thread.sleep(1000); 234 | } catch (InterruptedException e1) { 235 | e1.printStackTrace(); 236 | } 237 | 238 | sendUDP(msg); 239 | sendUDP(msg); 240 | 241 | try { 242 | countDown.await(10, TimeUnit.SECONDS); 243 | } catch (InterruptedException e) { 244 | e.printStackTrace(); 245 | } 246 | 247 | assertEquals(2, countDown.getCount()); 248 | 249 | } 250 | 251 | @Test 252 | public void testSSDPMulticastListenerIMulticastListenerNull() throws IOException { 253 | 254 | final String msg = "Hello from SSPDMulticastListenerTest"; 255 | final CountDownLatch countDown = new CountDownLatch(2); 256 | 257 | listener.setSSDPResponseHandler(new SSDPDefaultResponseHandler(null) { 258 | @Override 259 | public void handle(String message) throws Exception { 260 | if (msg.equals(message)) { 261 | countDown.countDown(); 262 | } 263 | } 264 | 265 | @Override 266 | public void handle(String remoteAddr, int remotePort, String message) 267 | throws Exception { 268 | if (msg.equals(message)) { 269 | countDown.countDown(); 270 | } 271 | } 272 | 273 | }); 274 | 275 | assertNotNull(listener.getSSDPResponseHandler()); 276 | 277 | t.start(); 278 | 279 | try { 280 | Thread.sleep(1000); 281 | } catch (InterruptedException e1) { 282 | e1.printStackTrace(); 283 | } 284 | 285 | sendUDP(msg); 286 | sendUDP(msg); 287 | 288 | try { 289 | countDown.await(10, TimeUnit.SECONDS); 290 | } catch (InterruptedException e) { 291 | e.printStackTrace(); 292 | } 293 | 294 | assertEquals(0, countDown.getCount()); 295 | 296 | //fail(); 297 | 298 | } 299 | 300 | @Test 301 | public void testSSDPMulticastListenerInterrupted() throws IOException { 302 | 303 | final CountDownLatch countDown = new CountDownLatch(2); 304 | 305 | SSDPMulticastListener listener2 = new SSDPMulticastListener(SSDPContants.DEFAULT_IP, SSDPContants.DEFAULT_PORT, SSDPContants.DEFAULT_DELAY); 306 | listener2.setSSDPResponseHandler(null); 307 | listener2.setBlocking(false); 308 | listener2.setTimeout(10); 309 | 310 | Thread t2 = new Thread(listener2); 311 | 312 | t2.start(); 313 | 314 | try { 315 | countDown.await(3, TimeUnit.SECONDS); 316 | } catch (InterruptedException e) { 317 | e.printStackTrace(); 318 | } 319 | 320 | t2.interrupt(); 321 | 322 | try { 323 | countDown.await(5, TimeUnit.SECONDS); 324 | } catch (InterruptedException e) { 325 | e.printStackTrace(); 326 | } 327 | 328 | assertEquals(State.STOPPED, listener2.getState()); 329 | 330 | } 331 | 332 | @Test 333 | public void testSSDPMulticastListenerNetworkInterface() throws IOException { 334 | 335 | fail("Not yet implemented"); 336 | 337 | List list = new ArrayList(); 338 | 339 | while (NetworkInterface.getNetworkInterfaces().hasMoreElements()) { 340 | NetworkInterface ni = (NetworkInterface) NetworkInterface.getNetworkInterfaces().nextElement(); 341 | 342 | SSDPMulticastListener listenerTmp = new SSDPMulticastListener(SSDPContants.DEFAULT_IP, SSDPContants.DEFAULT_PORT, SSDPContants.DEFAULT_DELAY); 343 | 344 | } 345 | 346 | final CountDownLatch countDown = new CountDownLatch(2); 347 | 348 | SSDPMulticastListener listener2 = new SSDPMulticastListener(SSDPContants.DEFAULT_IP, SSDPContants.DEFAULT_PORT, SSDPContants.DEFAULT_DELAY); 349 | listener2.setSSDPResponseHandler(null); 350 | listener2.setBlocking(false); 351 | listener2.setTimeout(10); 352 | 353 | Thread t2 = new Thread(listener2); 354 | 355 | t2.start(); 356 | 357 | try { 358 | countDown.await(3, TimeUnit.SECONDS); 359 | } catch (InterruptedException e) { 360 | e.printStackTrace(); 361 | } 362 | 363 | t2.interrupt(); 364 | 365 | try { 366 | countDown.await(5, TimeUnit.SECONDS); 367 | } catch (InterruptedException e) { 368 | e.printStackTrace(); 369 | } 370 | 371 | assertEquals(State.STOPPED, listener2.getState()); 372 | 373 | } 374 | 375 | } 376 | -------------------------------------------------------------------------------- /ssdp-network/default-impl/src/test/java/com/jerabi/ssdp/network/impl/UDPSenderTest.java: -------------------------------------------------------------------------------- 1 | package com.jerabi.ssdp.network.impl; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import java.net.InetAddress; 6 | import java.net.InetSocketAddress; 7 | import java.net.SocketAddress; 8 | import java.net.SocketTimeoutException; 9 | import java.net.UnknownHostException; 10 | import java.util.concurrent.CountDownLatch; 11 | import java.util.concurrent.TimeUnit; 12 | 13 | import org.junit.After; 14 | import org.junit.Before; 15 | import org.junit.BeforeClass; 16 | import org.junit.Test; 17 | 18 | 19 | import com.jerabi.ssdp.ISSDPControler; 20 | import com.jerabi.ssdp.handler.ISSDPResponseHandler; 21 | import com.jerabi.ssdp.handler.SSDPDefaultResponseHandler; 22 | import com.jerabi.ssdp.network.impl.MulticastListener; 23 | import com.jerabi.ssdp.network.impl.UDPSender; 24 | import com.jerabi.ssdp.util.SSDPContants; 25 | 26 | public class UDPSenderTest { 27 | 28 | private static UDPSender sender = null; 29 | private static UDPSender sender2 = null; 30 | 31 | private static final String HOST = SSDPContants.DEFAULT_IP; 32 | private static final int PORT = 5009; 33 | private static InetAddress group = null; 34 | 35 | 36 | @BeforeClass 37 | public static void setUpBeforeClass() throws Exception { 38 | try { 39 | sender = new UDPSender(); 40 | sender2 = new UDPSender(PORT); 41 | 42 | group = InetAddress.getByName(HOST); 43 | } catch (Exception e) { 44 | e.printStackTrace(); 45 | fail("Shouldn't throw Exception"); 46 | } 47 | } 48 | 49 | @Before 50 | public void setUp() throws Exception { 51 | } 52 | 53 | @After 54 | public void tearDown() throws Exception { 55 | } 56 | 57 | @Test 58 | public void testUDPSender() { 59 | MulticastListener listener = null; 60 | MulticastListener listener2 = null; 61 | MulticastListener listener3 = null; 62 | 63 | final CountDownLatch latch1 = new CountDownLatch(1); 64 | final CountDownLatch latch2 = new CountDownLatch(1); 65 | 66 | try { 67 | listener = new MulticastListener(PORT, new SSDPDefaultResponseHandler(null) { 68 | 69 | @Override 70 | public void handle(String remoteAddr, int remotePort, String message) 71 | throws Exception { 72 | latch1.countDown(); 73 | new UDPSender().sendMessage(message, InetAddress.getByName(remoteAddr), remotePort, null, 2); 74 | } 75 | }); 76 | 77 | listener.joinGroup(group); 78 | 79 | listener2 = new MulticastListener(new InetSocketAddress(PORT), new SSDPDefaultResponseHandler(null) { 80 | 81 | @Override 82 | public void handle(String remoteAddr, int remotePort, String message) 83 | throws Exception { 84 | latch2.countDown(); 85 | new UDPSender().sendMessage(message, InetAddress.getByName(remoteAddr), remotePort, null, 2); 86 | } 87 | }); 88 | 89 | listener2.joinGroup(group); 90 | 91 | listener3 = new MulticastListener(new InetSocketAddress(PORT), null); 92 | listener3.joinGroup(group); 93 | } catch (Exception e) { 94 | e.printStackTrace(); 95 | fail("Shouldn't throw Exception"); 96 | } 97 | 98 | Thread t1 = new Thread(new UDPServer(listener, true)); 99 | Thread t2 = new Thread(new UDPServer(listener2, true)); 100 | Thread t3 = new Thread(new UDPServer(listener3, false)); 101 | 102 | t1.start(); 103 | t2.start(); 104 | t3.start(); 105 | 106 | String msg = "UDP sent"; 107 | 108 | try { 109 | sender.sendMessage(msg, InetAddress.getByName(HOST), PORT, new SSDPDefaultResponseHandler(null) {}, 5); 110 | sender.sendMessage(msg, InetAddress.getByName(HOST), PORT, null, 5); 111 | } catch (SocketTimeoutException e) { 112 | 113 | } catch (Exception e) { 114 | e.printStackTrace(); 115 | fail("Shouldn't throw Exception"); 116 | } 117 | 118 | try { 119 | latch1.await(5, TimeUnit.SECONDS); 120 | } catch (InterruptedException e) { 121 | } 122 | 123 | t1.interrupt(); 124 | t2.interrupt(); 125 | t3.interrupt(); 126 | 127 | assertEquals(0, latch1.getCount()); 128 | assertEquals(0, latch2.getCount()); 129 | 130 | try { 131 | latch1.await(2, TimeUnit.SECONDS); 132 | } catch (InterruptedException e) { 133 | } 134 | } 135 | 136 | @Test 137 | public void testUDPSenderUsingINetAddress() { 138 | MulticastListener listener = null; 139 | MulticastListener listener2 = null; 140 | 141 | final CountDownLatch latch1 = new CountDownLatch(1); 142 | final CountDownLatch latch2 = new CountDownLatch(1); 143 | 144 | try { 145 | listener = new MulticastListener(PORT, new SSDPDefaultResponseHandler(null) { 146 | 147 | @Override 148 | public void handle(String remoteAddr, int remotePort, String message) 149 | throws Exception { 150 | latch1.countDown(); 151 | new UDPSender().sendMessage(message, InetAddress.getByName(remoteAddr), remotePort, null, 2); 152 | } 153 | }); 154 | 155 | listener.joinGroup(group); 156 | 157 | listener2 = new MulticastListener(new InetSocketAddress(PORT), new SSDPDefaultResponseHandler(null) { 158 | 159 | @Override 160 | public void handle(String remoteAddr, int remotePort, String message) 161 | throws Exception { 162 | latch2.countDown(); 163 | new UDPSender().sendMessage(message, InetAddress.getByName(remoteAddr), remotePort, null, 2); 164 | } 165 | }); 166 | 167 | listener2.joinGroup(group); 168 | } catch (Exception e) { 169 | e.printStackTrace(); 170 | fail("Shouldn't throw Exception"); 171 | } 172 | 173 | Thread t1 = new Thread(new UDPServer(listener, true)); 174 | Thread t2 = new Thread(new UDPServer(listener2, true)); 175 | 176 | t1.start(); 177 | t2.start(); 178 | 179 | String msg = "UDP sent with InetAddress"; 180 | 181 | try { 182 | sender2.sendMessage(msg, InetAddress.getByName(HOST), PORT, new SSDPDefaultResponseHandler(null) {}, 5); 183 | sender2.sendMessage(msg, InetAddress.getByName(HOST), PORT, null, 5); 184 | } catch (SocketTimeoutException e) { 185 | 186 | } catch (Exception e) { 187 | e.printStackTrace(); 188 | fail("Shouldn't throw Exception"); 189 | } 190 | 191 | try { 192 | latch1.await(5, TimeUnit.SECONDS); 193 | } catch (InterruptedException e) { 194 | } 195 | 196 | t1.interrupt(); 197 | t2.interrupt(); 198 | 199 | assertEquals(0, latch1.getCount()); 200 | assertEquals(0, latch2.getCount()); 201 | 202 | try { 203 | latch1.await(2, TimeUnit.SECONDS); 204 | } catch (InterruptedException e) { 205 | } 206 | 207 | } 208 | 209 | @Test 210 | public void testUDPSenderUsingSocketAddress() { 211 | MulticastListener listener = null; 212 | MulticastListener listener2 = null; 213 | 214 | final CountDownLatch latch1 = new CountDownLatch(1); 215 | final CountDownLatch latch2 = new CountDownLatch(1); 216 | 217 | try { 218 | listener = new MulticastListener(PORT+1, new SSDPDefaultResponseHandler(null) { 219 | 220 | @Override 221 | public void handle(String remoteAddr, int remotePort, String message) 222 | throws Exception { 223 | latch1.countDown(); 224 | new UDPSender().sendMessage(message, new InetSocketAddress(InetAddress.getByName(remoteAddr), remotePort), null, 2); 225 | } 226 | }); 227 | 228 | listener.joinGroup(group); 229 | 230 | listener2 = new MulticastListener(new InetSocketAddress(PORT+1), new SSDPDefaultResponseHandler(null) { 231 | 232 | @Override 233 | public void handle(String remoteAddr, int remotePort, String message) 234 | throws Exception { 235 | latch2.countDown(); 236 | new UDPSender().sendMessage(message, new InetSocketAddress(InetAddress.getByName(remoteAddr), remotePort), null, 2); 237 | } 238 | }); 239 | 240 | listener2.joinGroup(group); 241 | } catch (Exception e) { 242 | e.printStackTrace(); 243 | fail("Shouldn't throw Exception"); 244 | } 245 | 246 | Thread t1 = new Thread(new UDPServer(listener, true)); 247 | Thread t2 = new Thread(new UDPServer(listener2, true)); 248 | 249 | t1.start(); 250 | t2.start(); 251 | 252 | String msg = "UDP sent with SocketAddress"; 253 | 254 | final CountDownLatch callbackLatch = new CountDownLatch(1); 255 | try { 256 | sender.sendMessage(msg, new InetSocketAddress(InetAddress.getByName(HOST), PORT+1) , new SSDPDefaultResponseHandler(null) { 257 | @Override 258 | public void handle(String message) throws Exception { 259 | callbackLatch.countDown(); 260 | } 261 | @Override 262 | public void handle(String remoteAddr, int remotePort, 263 | String message) throws Exception { 264 | callbackLatch.countDown(); 265 | } 266 | }, 4); 267 | sender.sendMessage(msg, new InetSocketAddress(InetAddress.getByName(HOST), PORT+1) , null, 4); 268 | } catch (SocketTimeoutException e) { 269 | e.printStackTrace(); 270 | fail("Shouldn't throw Exception"); 271 | } catch (Exception e) { 272 | e.printStackTrace(); 273 | fail("Shouldn't throw Exception"); 274 | } 275 | 276 | try { 277 | latch1.await(5, TimeUnit.SECONDS); 278 | } catch (InterruptedException e) { 279 | } 280 | 281 | t1.interrupt(); 282 | t2.interrupt(); 283 | 284 | assertEquals(0, latch1.getCount()); 285 | assertEquals(0, latch2.getCount()); 286 | 287 | try { 288 | latch1.await(2, TimeUnit.SECONDS); 289 | } catch (InterruptedException e) { 290 | } 291 | 292 | } 293 | 294 | } 295 | -------------------------------------------------------------------------------- /ssdp-network/default-impl/src/test/java/com/jerabi/ssdp/network/impl/UDPServer.java: -------------------------------------------------------------------------------- 1 | package com.jerabi.ssdp.network.impl; 2 | 3 | import com.jerabi.ssdp.network.impl.MulticastListener; 4 | 5 | public class UDPServer implements Runnable { 6 | 7 | private MulticastListener listener = null; 8 | private boolean blocking = false; 9 | 10 | public UDPServer(MulticastListener listener, boolean blocking){ 11 | this.listener = listener; 12 | this.blocking = blocking; 13 | } 14 | 15 | @Override 16 | public void run() { 17 | 18 | while(!Thread.interrupted()){ 19 | try { 20 | if(blocking){ 21 | listener.receive(blocking); 22 | } else { 23 | listener.receive(); 24 | } 25 | } catch (Exception e) { 26 | 27 | } 28 | } 29 | 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /ssdp-network/default-impl/src/test/java/com/jerabi/ssdp/sender/SSDPDiscoverSenderTest.java: -------------------------------------------------------------------------------- 1 | package com.jerabi.ssdp.sender; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | import static org.junit.Assert.assertNotNull; 5 | import static org.junit.Assert.assertNull; 6 | import static org.junit.Assert.assertTrue; 7 | import static org.junit.Assert.fail; 8 | 9 | import java.net.InetAddress; 10 | import java.util.concurrent.CountDownLatch; 11 | import java.util.concurrent.ExecutorService; 12 | import java.util.concurrent.Executors; 13 | import java.util.concurrent.TimeUnit; 14 | 15 | import org.junit.Before; 16 | import org.junit.BeforeClass; 17 | import org.junit.Test; 18 | 19 | import com.jerabi.ssdp.handler.SSDPDiscoverResponseHandler; 20 | import com.jerabi.ssdp.network.impl.MulticastListener; 21 | import com.jerabi.ssdp.network.impl.UDPSender; 22 | import com.jerabi.ssdp.network.impl.UDPServer; 23 | import com.jerabi.ssdp.sender.SSDPDiscoverSender; 24 | import com.jerabi.ssdp.util.SSDPContants; 25 | 26 | public class SSDPDiscoverSenderTest { 27 | 28 | private static SSDPDiscoverSender discoverSender = null; 29 | private static SSDPDiscoverSender discoverSender2 = null; 30 | private static ExecutorService threadPool = null; 31 | 32 | @BeforeClass 33 | public static void setUpBeforeClass() throws Exception { 34 | discoverSender = new SSDPDiscoverSender(null, SSDPContants.DEFAULT_IP, SSDPContants.DEFAULT_PORT); 35 | discoverSender2 = new SSDPDiscoverSender(null, SSDPContants.DEFAULT_IP, SSDPContants.DEFAULT_PORT, SSDPContants.DEFAULT_DELAY); 36 | 37 | threadPool = Executors.newFixedThreadPool(5); 38 | 39 | threadPool.execute(discoverSender); 40 | threadPool.execute(discoverSender2); 41 | 42 | CountDownLatch latch = new CountDownLatch(1); 43 | latch.await(1, TimeUnit.SECONDS); 44 | } 45 | 46 | @Before 47 | public void setUp() throws Exception { 48 | } 49 | 50 | @Test 51 | public void testSendMessageISSDPMessage() { 52 | 53 | try { 54 | discoverSender.sendMessage("DiscoverMessage"); 55 | 56 | } catch (Exception e) { 57 | fail("Shouldn't throws Exception"); 58 | } 59 | 60 | } 61 | 62 | @Test 63 | public void testGetSSDPMessagesToSend() { 64 | assertNotNull(discoverSender.getSSDPMessagesToSend()); 65 | assertTrue(discoverSender.getSSDPMessagesToSend().size()>0); 66 | } 67 | 68 | @Test 69 | public void testInvalidPort() { 70 | 71 | boolean exception = false; 72 | 73 | try { 74 | SSDPDiscoverSender sender1 = new SSDPDiscoverSender(null, SSDPContants.DEFAULT_IP, -1); 75 | sender1.sendMessage("invalid port"); 76 | } catch(Exception e){ 77 | exception = true; 78 | } 79 | 80 | assertTrue(exception); 81 | 82 | exception = false; 83 | try { 84 | SSDPDiscoverSender sender1 = new SSDPDiscoverSender(null, SSDPContants.DEFAULT_IP, -1, SSDPContants.DEFAULT_DELAY); 85 | sender1.sendMessage("invalid port"); 86 | } catch(Exception e){ 87 | exception = true; 88 | } 89 | 90 | assertTrue(exception); 91 | 92 | } 93 | 94 | @Test 95 | /* 96 | * to complete this test, we need to have a listener that will response to this M_SEARCH 97 | */ 98 | public void testSendNull() { 99 | 100 | assertNull(discoverSender.getSSDPResponseHandler()); 101 | 102 | discoverSender.setSSDPResponseHandler(new SSDPDiscoverResponseHandler(null){ 103 | @Override 104 | public void handle(String message) throws Exception { 105 | } 106 | }); 107 | 108 | assertNotNull(discoverSender.getSSDPResponseHandler()); 109 | 110 | try { 111 | discoverSender.sendMessage(null); 112 | 113 | } catch (Exception e) { 114 | e.printStackTrace(); 115 | fail("Shouldn't throws Exception"); 116 | } 117 | 118 | } 119 | 120 | @Test 121 | /* 122 | * to complete this test, we need to have a listener that will response to this M_SEARCH 123 | */ 124 | public void testSSDPHandler() { 125 | 126 | MulticastListener listener = null; 127 | 128 | try { 129 | listener = new MulticastListener(SSDPContants.DEFAULT_PORT, new SSDPDiscoverResponseHandler(null) { 130 | 131 | @Override 132 | public void handle(String remoteAddr, int remotePort, String message) 133 | throws Exception { 134 | UDPSender sender = new UDPSender(); 135 | sender.sendMessage(message, InetAddress.getByName(remoteAddr), remotePort, null, 1); 136 | } 137 | }); 138 | 139 | listener.joinGroup(InetAddress.getByName(SSDPContants.DEFAULT_IP)); 140 | 141 | } catch(Exception e){ 142 | 143 | } 144 | 145 | Thread t1 = new Thread(new UDPServer(listener, false)); 146 | t1.start(); 147 | 148 | final CountDownLatch latch = new CountDownLatch(1); 149 | 150 | discoverSender.setSSDPResponseHandler(new SSDPDiscoverResponseHandler(null){ 151 | @Override 152 | public void handle(String message) throws Exception { 153 | if(message!=null && message.equals("testSetSSDPHandler")){ 154 | latch.countDown(); 155 | } 156 | } 157 | }); 158 | 159 | assertNotNull(discoverSender.getSSDPResponseHandler()); 160 | 161 | try { 162 | discoverSender.sendMessage("testSetSSDPHandler"); 163 | 164 | } catch (Exception e) { 165 | fail("Shouldn't throws Exception"); 166 | } 167 | 168 | try { 169 | latch.await(5, TimeUnit.SECONDS); 170 | } catch (InterruptedException e) { 171 | } 172 | 173 | assertEquals(0, latch.getCount()); 174 | 175 | t1.interrupt(); 176 | fail("Need a DiscoverResponseServer"); 177 | } 178 | 179 | } 180 | -------------------------------------------------------------------------------- /ssdp-network/default-impl/src/test/java/com/jerabi/ssdp/sender/SSDPPeriodicMessageSenderTest.java: -------------------------------------------------------------------------------- 1 | package com.jerabi.ssdp.sender; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | import static org.junit.Assert.assertNotNull; 5 | import static org.junit.Assert.assertTrue; 6 | import static org.junit.Assert.fail; 7 | 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | import java.util.concurrent.CountDownLatch; 11 | import java.util.concurrent.ExecutorService; 12 | import java.util.concurrent.Executors; 13 | import java.util.concurrent.TimeUnit; 14 | 15 | import org.junit.BeforeClass; 16 | import org.junit.Test; 17 | 18 | import com.jerabi.ssdp.message.ISSDPMessage; 19 | import com.jerabi.ssdp.sender.SSDPDefaultPeriodicMessageSender; 20 | import com.jerabi.ssdp.util.SSDPContants; 21 | import com.jerabi.ssdp.util.State; 22 | 23 | public class SSDPPeriodicMessageSenderTest { 24 | 25 | private static SSDPDefaultPeriodicMessageSender sender = null; 26 | private static ExecutorService threadPool = null; 27 | 28 | @BeforeClass 29 | public static void setUpBeforeClass() throws Exception { 30 | sender = new SSDPDefaultPeriodicMessageSender(null, SSDPContants.DEFAULT_IP, SSDPContants.DEFAULT_PORT, SSDPContants.DEFAULT_DELAY) { 31 | @Override 32 | public List getSSDPMessagesToSend() { 33 | List list = new ArrayList(); 34 | 35 | for(int i=0;i<5;i++){ 36 | list.add(new ISSDPMessage(){ 37 | @Override 38 | public String toString() { 39 | return "messagetosend"; 40 | }}); 41 | } 42 | 43 | return list; 44 | } 45 | }; 46 | threadPool = Executors.newFixedThreadPool(5); 47 | 48 | threadPool.execute(sender); 49 | 50 | CountDownLatch latch = new CountDownLatch(1); 51 | latch.await(1, TimeUnit.SECONDS); 52 | } 53 | 54 | @Test 55 | public void testGetState() { 56 | assertNotNull(sender.getState()); 57 | 58 | } 59 | 60 | @Test 61 | public void testSetState() { 62 | sender.setState(State.SUSPENDED); 63 | assertEquals(State.SUSPENDED, sender.getState()); 64 | 65 | sender.setState(State.STOPPED); 66 | assertEquals(State.STOPPED, sender.getState()); 67 | } 68 | 69 | @Test 70 | public void testGetDelay() { 71 | assertTrue(sender.getDelay() > -1); 72 | } 73 | 74 | @Test 75 | public void testSetDelay() { 76 | sender.setDelay(1234); 77 | 78 | assertEquals(1234, sender.getDelay()); 79 | } 80 | 81 | @Test 82 | public void testGetSSDPHost() { 83 | assertEquals(SSDPContants.DEFAULT_IP, sender.getSSDPHost()); 84 | } 85 | 86 | @Test 87 | public void testSetSSDPHost() { 88 | sender.setSSDPHost("localhost"); 89 | assertEquals("localhost", sender.getSSDPHost()); 90 | } 91 | 92 | @Test 93 | public void testGetSSDPPort() { 94 | assertEquals(SSDPContants.DEFAULT_PORT, sender.getSSDPPort()); 95 | } 96 | 97 | @Test 98 | public void testSetSSDPPort() { 99 | sender.setSSDPPort(1234); 100 | assertEquals(1234, sender.getSSDPPort()); 101 | } 102 | 103 | @Test 104 | public void testSendMessage() { 105 | try { 106 | sender.sendMessage("message1"); 107 | sender.sendMessage((String)null); 108 | } catch (Exception e) { 109 | fail("Shouldn't throws Exception"); 110 | } 111 | } 112 | 113 | @Test 114 | public void testSendMessageInvalidHost() { 115 | SSDPDefaultPeriodicMessageSender sender2 = new SSDPDefaultPeriodicMessageSender(null, "-1", -1, SSDPContants.DEFAULT_DELAY) { 116 | @Override 117 | public List getSSDPMessagesToSend() { 118 | List list = new ArrayList(); 119 | 120 | for(int i=0;i<5;i++){ 121 | list.add(new ISSDPMessage(){ 122 | @Override 123 | public String toString() { 124 | return "messagetosend"; 125 | }}); 126 | } 127 | 128 | return list; 129 | } 130 | }; 131 | threadPool = Executors.newFixedThreadPool(5); 132 | 133 | threadPool.execute(sender2); 134 | 135 | CountDownLatch latch = new CountDownLatch(1); 136 | try { 137 | latch.await(2, TimeUnit.SECONDS); 138 | } catch (InterruptedException e) { 139 | } 140 | 141 | threadPool.shutdownNow(); 142 | 143 | } 144 | 145 | } 146 | -------------------------------------------------------------------------------- /ssdp-network/dummy-impl/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | com.jerabi.ssdp-network 4 | ssdp-network 5 | 0.0.1-SNAPSHOT 6 | 7 | 4.0.0 8 | com.jerabi.ssdp-network 9 | dummy-impl 10 | dummy-impl 11 | 0.0.1-SNAPSHOT 12 | ssdp dummy network UDP impl 13 | 14 | 15 | 16 | org.apache.maven.plugins 17 | maven-compiler-plugin 18 | 19 | 1.6 20 | 1.6 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | com.jerabi 29 | ssdp-core 30 | 0.0.1-SNAPSHOT 31 | 32 | 33 | -------------------------------------------------------------------------------- /ssdp-network/dummy-impl/src/main/java/com/jerabi/ssdp/network/impl/SSDPNetwork.java: -------------------------------------------------------------------------------- 1 | package com.jerabi.ssdp.network.impl; 2 | 3 | import java.net.InetAddress; 4 | import java.net.NetworkInterface; 5 | import java.net.SocketAddress; 6 | 7 | import com.jerabi.ssdp.handler.ISSDPResponseHandler; 8 | import com.jerabi.ssdp.network.IMulticastListener; 9 | import com.jerabi.ssdp.network.ISSDPNetwork; 10 | import com.jerabi.ssdp.network.IUDPSender; 11 | 12 | /** 13 | * 14 | * Provides API for sending and receiving messages over network. 15 | * 16 | * This class is a dummy that doesn't implements any methods. 17 | * It used for compilation purpose. An implementation must be 18 | * available in another package. 19 | * 20 | * @author Sebastien Dionne 21 | * 22 | */ 23 | public class SSDPNetwork implements ISSDPNetwork { 24 | 25 | /** 26 | * Private Constructor. You need to use getInstance() 27 | * @see #getInstance() 28 | */ 29 | private SSDPNetwork(){} 30 | 31 | /** 32 | * {@inheritDoc} 33 | */ 34 | @Override 35 | public IMulticastListener createMulticastListener(int port, ISSDPResponseHandler callbackHandler) throws Exception { 36 | throw new RuntimeException("Not implemented"); 37 | } 38 | 39 | /** 40 | * {@inheritDoc} 41 | */ 42 | @Override 43 | public IMulticastListener createMulticastListener(SocketAddress bindAddress, ISSDPResponseHandler callbackHandler) throws Exception { 44 | throw new RuntimeException("Not implemented"); 45 | } 46 | 47 | /** 48 | * {@inheritDoc} 49 | */ 50 | @Override 51 | public IMulticastListener createMulticastListener(SocketAddress bindAddress, ISSDPResponseHandler callbackHandler, NetworkInterface ni) throws Exception { 52 | throw new RuntimeException("Not implemented"); 53 | } 54 | 55 | /** 56 | * {@inheritDoc} 57 | */ 58 | @Override 59 | public IUDPSender createUDPSender() throws Exception { 60 | throw new RuntimeException("Not implemented"); 61 | } 62 | 63 | /** 64 | * {@inheritDoc} 65 | */ 66 | @Override 67 | public IUDPSender createUDPSender(int port) throws Exception { 68 | throw new RuntimeException("Not implemented"); 69 | } 70 | 71 | /** 72 | * {@inheritDoc} 73 | */ 74 | @Override 75 | public void sendMulticastMessage(String message, SocketAddress address) throws Exception { 76 | throw new RuntimeException("Not implemented"); 77 | 78 | } 79 | 80 | /** 81 | * {@inheritDoc} 82 | */ 83 | @Override 84 | public void sendMulticastMessage(String message, InetAddress address, int port) throws Exception { 85 | throw new RuntimeException("Not implemented"); 86 | 87 | } 88 | 89 | /** 90 | * {@inheritDoc} 91 | */ 92 | @Override 93 | public void sendMulticastMessage(String message, SocketAddress address, ISSDPResponseHandler callbackHandler, int ttl) throws Exception { 94 | throw new RuntimeException("Not implemented"); 95 | 96 | } 97 | 98 | /** 99 | * {@inheritDoc} 100 | */ 101 | @Override 102 | public void sendMulticastMessage(String message, InetAddress address, int port, ISSDPResponseHandler callbackHandler, int ttl) throws Exception { 103 | throw new RuntimeException("Not implemented"); 104 | 105 | } 106 | 107 | /** 108 | * {@inheritDoc} 109 | */ 110 | @Override 111 | public void sendMulticastMessage(String message, SocketAddress address, NetworkInterface ni) throws Exception { 112 | throw new RuntimeException("Not implemented"); 113 | } 114 | 115 | /** 116 | * Returns a ISSDPNetwork instance. 117 | * 118 | * The implementation class must implements this method. 119 | * 120 | * @return ISSDPNetwork 121 | */ 122 | public static ISSDPNetwork getInstance() { 123 | throw new RuntimeException("Not implemented"); 124 | } 125 | 126 | } 127 | -------------------------------------------------------------------------------- /ssdp-network/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | com.jerabi 5 | ssdp 6 | 0.0.1-SNAPSHOT 7 | 8 | 9 | 4.0.0 10 | com.jerabi.ssdp-network 11 | ssdp-network 12 | 0.0.1-SNAPSHOT 13 | pom 14 | ssdp-network 15 | https://github.com/jerabi/jerabi-ssdp 16 | 17 | 18 | dummy-impl 19 | default-impl 20 | 21 | 22 | --------------------------------------------------------------------------------