├── .gitignore ├── .travis.yml ├── .vscode └── settings.json ├── LICENSE ├── LICENSE.md ├── README.md ├── Red5ProDeploy.md ├── build.sh ├── doc ├── configuration.md └── nio-configuration.md ├── ice4j.code-workspace ├── pom.xml └── src ├── main └── java │ └── org │ ├── apache │ └── mina │ │ └── transport │ │ └── socket │ │ └── nio │ │ └── IceDatagramAcceptor.java │ └── ice4j │ ├── AbstractResponseCollector.java │ ├── BaseStunMessageEvent.java │ ├── ResponseCollector.java │ ├── StackProperties.java │ ├── StunException.java │ ├── StunFailureEvent.java │ ├── StunMessageEvent.java │ ├── StunResponseEvent.java │ ├── StunTimeoutEvent.java │ ├── Transport.java │ ├── TransportAddress.java │ ├── attribute │ ├── AddressAttribute.java │ ├── AlternateServerAttribute.java │ ├── Attribute.java │ ├── AttributeDecoder.java │ ├── AttributeFactory.java │ ├── ChangeRequestAttribute.java │ ├── ChangedAddressAttribute.java │ ├── ChannelNumberAttribute.java │ ├── ConnectionIdAttribute.java │ ├── ContentDependentAttribute.java │ ├── DataAttribute.java │ ├── DestinationAddressAttribute.java │ ├── DontFragmentAttribute.java │ ├── ErrorCodeAttribute.java │ ├── EvenPortAttribute.java │ ├── FingerprintAttribute.java │ ├── IceControlAttribute.java │ ├── IceControlledAttribute.java │ ├── IceControllingAttribute.java │ ├── LifetimeAttribute.java │ ├── MagicCookieAttribute.java │ ├── MappedAddressAttribute.java │ ├── MessageIntegrityAttribute.java │ ├── NonceAttribute.java │ ├── OptionalAttribute.java │ ├── PriorityAttribute.java │ ├── RealmAttribute.java │ ├── ReflectedFromAttribute.java │ ├── RemoteAddressAttribute.java │ ├── RequestedAddressFamilyAttribute.java │ ├── RequestedTransportAttribute.java │ ├── ReservationTokenAttribute.java │ ├── ResponseAddressAttribute.java │ ├── SoftwareAttribute.java │ ├── SourceAddressAttribute.java │ ├── UnknownAttributesAttribute.java │ ├── UseCandidateAttribute.java │ ├── UsernameAttribute.java │ ├── XorMappedAddressAttribute.java │ ├── XorOnlyAttribute.java │ ├── XorPeerAddressAttribute.java │ └── XorRelayedAddressAttribute.java │ ├── ice │ ├── Agent.java │ ├── Candidate.java │ ├── CandidateExtendedType.java │ ├── CandidatePair.java │ ├── CandidatePairState.java │ ├── CandidatePrioritizer.java │ ├── CandidateTcpType.java │ ├── CandidateType.java │ ├── CheckList.java │ ├── CheckListState.java │ ├── Component.java │ ├── ComponentSocket.java │ ├── ConnectivityCheckClient.java │ ├── ConnectivityCheckServer.java │ ├── DefaultNominator.java │ ├── FoundationsRegistry.java │ ├── HostCandidate.java │ ├── IceMediaStream.java │ ├── IceProcessingState.java │ ├── KeepAliveStrategy.java │ ├── LocalCandidate.java │ ├── NetworkUtils.java │ ├── NominationStrategy.java │ ├── PeerReflexiveCandidate.java │ ├── RelayedCandidate.java │ ├── RemoteCandidate.java │ ├── ServerReflexiveCandidate.java │ ├── TcpHostCandidate.java │ ├── harvest │ │ ├── AbstractCandidateHarvester.java │ │ ├── AbstractTcpListener.java │ │ ├── AbstractUdpListener.java │ │ ├── AddressRef.java │ │ ├── AwsCandidateHarvester.java │ │ ├── CandidateHarvester.java │ │ ├── CandidateHarvesterSet.java │ │ ├── CandidateHarvesterSetElement.java │ │ ├── CandidateHarvesterSetTask.java │ │ ├── HarvestStatistics.java │ │ ├── HostCandidateHarvester.java │ │ ├── MappingCandidateHarvester.java │ │ ├── MappingCandidateHarvesters.java │ │ ├── SinglePortUdpHarvester.java │ │ ├── StunCandidateHarvest.java │ │ ├── StunCandidateHarvester.java │ │ ├── StunMappingCandidateHarvester.java │ │ ├── TcpHarvester.java │ │ ├── TrickleCallback.java │ │ ├── TurnCandidateHarvest.java │ │ └── TurnCandidateHarvester.java │ └── nio │ │ ├── ExpirableAddressEntry.java │ │ ├── IceDecoder.java │ │ ├── IceEncoder.java │ │ ├── IceHandler.java │ │ ├── IceTcpTransport.java │ │ ├── IceTransport.java │ │ └── IceUdpTransport.java │ ├── message │ ├── ChannelData.java │ ├── Indication.java │ ├── Message.java │ ├── MessageFactory.java │ ├── Request.java │ └── Response.java │ ├── security │ ├── CredentialsAuthority.java │ ├── CredentialsManager.java │ ├── LongTermCredential.java │ └── LongTermCredentialSession.java │ ├── socket │ ├── IceSocketWrapper.java │ ├── IceTcpSocketWrapper.java │ ├── IceUdpSocketWrapper.java │ ├── RelayedCandidateConnection.java │ ├── SizeTrackedLinkedTransferQueue.java │ ├── SocketClosedException.java │ └── filter │ │ ├── DataFilter.java │ │ └── HttpDemuxFilter.java │ ├── stack │ ├── Connector.java │ ├── EventDispatcher.java │ ├── MessageEventHandler.java │ ├── NetAccessManager.java │ ├── PacketLogger.java │ ├── RawMessage.java │ ├── RequestListener.java │ ├── StunClientTransaction.java │ ├── StunServerTransaction.java │ ├── StunStack.java │ └── TransactionID.java │ ├── stunclient │ ├── BlockingRequestSender.java │ ├── NetworkConfigurationDiscoveryProcess.java │ ├── SimpleAddressDetector.java │ └── StunDiscoveryReport.java │ └── util │ ├── DatagramUtil.java │ ├── QueueStatistics.java │ ├── RateStatistics.java │ └── Utils.java └── test ├── java ├── org │ └── ice4j │ │ ├── MessageEventDispatchingTest.java │ │ ├── MsgFixture.java │ │ ├── StunTestSuite.java │ │ ├── TransactionSupportTests.java │ │ ├── attribute │ │ ├── AddressAttributeTest.java │ │ ├── AttributeDecoderTest.java │ │ ├── ChangeRequestAttributeTest.java │ │ ├── ConnectionIdAttributeTest.java │ │ ├── ErrorCodeAttributeTest.java │ │ ├── NonceAttributeTest.java │ │ ├── OptionalAttributeAttributeTest.java │ │ ├── RealmAttributeTest.java │ │ ├── RequestedAddressFamilyAttributeTest.java │ │ ├── SoftwareAttributeTest.java │ │ ├── UnknownAttributesAttributeTest.java │ │ ├── UsernameAttributeTest.java │ │ └── XorOnlyTest.java │ │ ├── ice │ │ ├── NetworkUtilsTest.java │ │ ├── RoleConflictResolutionTest.java │ │ └── nio │ │ │ ├── IceDecoderTest.java │ │ │ └── IceTransportTest.java │ │ ├── message │ │ ├── ChannelDataTest.java │ │ ├── MessageFactoryTest.java │ │ └── MessageTest.java │ │ ├── stack │ │ ├── DatagramCollector.java │ │ └── ShallowStackTest.java │ │ └── stunclient │ │ ├── ResponseSequenceServer.java │ │ ├── StunAddressDiscovererTest.java │ │ ├── StunAddressDiscovererTest_v4v6.java │ │ └── StunAddressDiscovererTest_v6.java └── test │ ├── AwsTest.java │ ├── Ice.java │ ├── PortUtil.java │ ├── PublicIPTest.java │ └── signalling │ ├── Signalling.java │ └── SignallingCallback.java └── resources ├── logback-test.xml └── logging.properties /.gitignore: -------------------------------------------------------------------------------- 1 | /classes/ 2 | /classes-test/ 3 | /junit-reports/ 4 | /target/ 5 | /ice4j.jar 6 | .classpath 7 | .project 8 | .settings/ 9 | bin/ 10 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | jdk: 3 | - oraclejdk8 4 | 5 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "java.configuration.updateBuildConfiguration": "automatic" 3 | } -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | This project is licensed under the [Apache License Version 2.0](http://www.apache.org/licenses/) additionally the following copyrights and attributions are attached 2 | * [Copyright @ 2015 Atlassian Pty Ltd](https://developer.atlassian.com/platform/open-source/) 3 | * [Copyright @ 2017-18 Infrared5, Inc.](https://infrared5.com/) 4 | 5 | Lastly, the `NioServer` class was copied to this project from its source as found at [iHarder.net](http://iharder.net). There is no licensing of `NioServer`, Robert Harder has released it into the Public Domain. 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![TravisCI](https://travis-ci.org/Red5/ice4j.svg?branch=master) 2 | 3 | # ice4j 4 | 5 | The Interactive Connectivity Establishment (ICE) protocol combines various NAT traversal utilities such as the STUN and TURN protocols in order to offer a powerful mechanism that allows Offer/Answer based protocols such as SIP and XMPP to traverse NATs. 6 | 7 | This project provides a Java implementation of the ICE protocol that would be usable by both SIP and XMPP applications. The project also provides features such as socket sharing and support for Pseudo TCP. 8 | 9 | This fork of ice4j is maintained by the [Red5 Pro](https://www.red5pro.com/) and originated from work done by [Jitsi](https://jitsi.org/) community. 10 | 11 | ## Features 12 | 13 | mDNS support via [jmdns](https://github.com/jmdns/jmdns) 14 | -------------------------------------------------------------------------------- /Red5ProDeploy.md: -------------------------------------------------------------------------------- 1 | Deploy the artifact with the proper classifier to denote it as a Red5 Pro build. 2 | 3 | Update the `file` and `version` as needed, the `file` is the jar which was output in the `target` directory of the build. 4 | The `version` is the version we want to be stored in artifactory. 5 | 6 | ```sh 7 | mvn deploy:deploy-file -DgeneratePom=true -DrepositoryId=red5pro-ext-snapshot \ 8 | -Durl=https://red5pro.jfrog.io/red5pro/ext-snapshot-local \ 9 | -Dfile=ice4j-2.5-SNAPSHOT.jar -DgroupId=org.jitsi -DartifactId=ice4j \ 10 | -Dclassifier=red5pro \ 11 | -Dversion=2.5.1-SNAPSHOT 12 | ``` 13 | This will use your existing credentials for artifactory to do the deploy. 14 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | MVN_OPTS="-Dmaven.test.skip=true" 4 | export MVN_OPTS 5 | 6 | mvn $MVN_OPTS clean install 7 | 8 | -------------------------------------------------------------------------------- /doc/configuration.md: -------------------------------------------------------------------------------- 1 | # General 2 | This file describes some of the java properties which ```ice4j``` uses 3 | to configure itself. 4 | 5 | ## Interfaces and IP addresses 6 | 7 | ### *org.ice4j.ice.harvest.ALLOWED_INTERFACES* 8 | Default: all interfaces are allowed. 9 | 10 | This property can be used to specify a ";"-separated list of interfaces which are 11 | allowed to be used for candidate allocations. If not specified, all interfaces are 12 | considered allowed, unless they are explicitly blocked (see below). 13 | 14 | ### *org.ice4j.ice.harvest.BLOCKED_INTERFACES* 15 | Default: no interfaces are blocked. 16 | 17 | This property can be used to specify a ";"-separated list of interfaces which are 18 | not allowed to be used for candidate allocations. 19 | 20 | ### *org.ice4j.ice.harvest.ALLOWED_ADDRESSES* 21 | Default: all addresses are allowed. 22 | 23 | This property can be used to specify a ";"-separated list of IP addresses which 24 | are allowed to be used for candidate allocations. If not specified, all addresses 25 | are considered allowed, unless they are explicitly blocked (see below). 26 | 27 | ### *org.ice4j.ice.harvest.BLOCKED_ADDRESSES* 28 | Default: no addresses are blocked. 29 | 30 | This property can be used to specify a ";"-separated list of IP addresses which 31 | are not allowed to be used for candidate allocations. 32 | 33 | ### *org.ice4j.ipv6.DISABLED* 34 | Type: boolean 35 | 36 | Default: false 37 | 38 | This property can be used to disable binding on IPv6 addresses. 39 | 40 | 41 | ## Mapping harvesters 42 | Ice4j uses the concept of "mapping harvesters" to handle known IP address 43 | mappings. A set of mapping harvesters is configured once when the library 44 | initializes, and each of them contains a pair of IP addresses (local and public). 45 | 46 | When an ICE Agent gathers candidates, it uses the set of mapping harvesters 47 | to obtain ```srflx``` candidates without the use to e.g. a STUN server dynamically. 48 | 49 | Mapping harvesters preserve the port number of the original candidate, so they should 50 | only be used when port numbers are preserved. 51 | 52 | Ice4j implements three types of mapping harvesters: one with a pre-configured pair of 53 | addresses, one two which discover addresses dynamically using the AWS API and STUN. 54 | 55 | 56 | ### *org.ice4j.ice.harvest.NAT_HARVESTER_LOCAL_ADDRESS* 57 | ### *org.ice4j.ice.harvest.NAT_HARVESTER_PUBLIC_ADDRESS* 58 | Default: none 59 | 60 | Configures the addresses of the pre-configured mapping harvester. 61 | 62 | ### *org.ice4j.ice.harvest.DISABLE_AWS_HARVESTER* 63 | Default: false 64 | 65 | Explicitly disables the AWS mapping harvester. By default the harvester 66 | is enabled if ice4j detects that it is running in the AWS network. 67 | 68 | ### *org.ice4j.ice.harvest.FORCE_AWS_HARVESTER* 69 | Default: false 70 | 71 | Force the use of the AWS mapping harvester, even if ice4j did not detect 72 | that it is running in the AWS network. 73 | 74 | ### *org.ice4j.ice.harvest.STUN_MAPPING_HARVESTER_ADDRESSES* 75 | Default: none 76 | 77 | A comma-separated list of STUN server addresses to use for mapping harvesters. 78 | Each STUN server address is an ip_address:port pair. 79 | Example: `stun1.example.com:12345,stun2.example.com:23456` 80 | 81 | ### *SKIP_REMOTE_PRIVATE_HOSTS* 82 | Whether or not to skip remote candidates originating from private network hosts; default is to allow them. 83 | 84 | ### *org.ice4j.TERMINATION_DELAY* 85 | Waits the specified period of time or the default of three seconds and then moves an Agent into the terminated state and frees all non-nominated candidates. 86 | 87 | ### *org.ice4j.ice.TA_PACE_TIMER* 88 | Ta pace timer in milliseconds. RFC 5245 says that Ta is: Ta_i = (stun_packet_size / rtp_packet_size) * rtp_ptime. 89 | 90 | -------------------------------------------------------------------------------- /doc/nio-configuration.md: -------------------------------------------------------------------------------- 1 | # NIO Configuration 2 | 3 | The following ice4j adjustments are available in the NIO version via environmental / system properties. 4 | 5 | ## Shared NIO acceptor or per-instance acceptor 6 | 7 | To utilize an instance of `IoAcceptor` for each `StunStack`, the `NIO_SHARED_MODE` property must be configured as `false`, to spawn a single static `IoAcceptor` for all `StunStack` instances, use the default value of `true`. 8 | 9 | ## Send buffer 10 | 11 | Configuration of the send buffer is handled via the `SO_SNDBUF` property. The default is 1500 and any target amount should take MTU size ~1500 into account. 12 | 13 | ## Receive buffer 14 | 15 | Configuration of the receive buffer is handled via the `SO_RCVBUF` property. The default is 1500 and any target amount should take MTU size ~1500 into account. 16 | 17 | ## QoS / Traffic class 18 | 19 | The traffic class setting for the internal sockets is handled via the `TRAFFIC_CLASS` property. The default is 0, which mean no configuration. RFC 1349 defines the values as follows: 20 | * IPTOS_LOWCOST (0x02) 21 | * IPTOS_RELIABILITY (0x04) 22 | * IPTOS_THROUGHPUT (0x08) 23 | * IPTOS_LOWDELAY (0x10) 24 | 25 | [Click here for additional details](https://docs.oracle.com/javase/8/docs/api/java/net/Socket.html#setTrafficClass-int-) 26 | 27 | ## Send and Receive idle timeout 28 | 29 | Send or receive may be detected as idle if they exceed the configured (in seconds) `SO_TIMEOUT` property which is defaulted to 30 seconds. 30 | 31 | ## Acceptor timeout 32 | 33 | Timeout in seconds to wait for a bind or unbind operation to complete, the `ACCEPTOR_TIMEOUT` property is modifiable from the default of 2 seconds. 34 | 35 | ## Aggressive Acceptor reset 36 | 37 | To prevent a possible deadlock caused by a failed bind or unbind event making the acceptor unresponsive, the `ACCEPTOR_RESET` option allows the acceptor to be reset on-the-fly. 38 | 39 | ## I/O thread count 40 | 41 | Setting the I/O thread count is handled via the `NIO_WORKERS` property. The default priority is 16 and should not exceed the CPU core count; lastly, this is only used for TCP. 42 | 43 | ## Blocking or Non-blocking I/O 44 | 45 | Setting the `IO_BLOCKING` to `true` will configure the internal services to use blocking I/O with TCP, instead of the default non-blocking implementation. This does not affect UDP connections. 46 | 47 | ## Private network host candidate handling 48 | 49 | To skip the addition of `RemoteCandidate` instances originating on private networks on a `Component`, set `SKIP_REMOTE_PRIVATE_HOSTS` to `true`; otherwise the default value `false` or not-to-skip will be used. 50 | 51 | # Server Startup 52 | 53 | To add the options to your Red5 / Red5 Pro server startup, update the `JAVA_OPTS` line like so: 54 | 55 | ``` 56 | export JAVA_OPTS="$SECURITY_OPTS $JAVA_OPTS $JVM_OPTS $TOMCAT_OPTS $NATIVE -DSO_RCVBUF=3000 -DIO_THREAD_PRIORITY=6 -DNIO_SELECTOR_SLEEP_MS=10" 57 | ``` 58 | 59 | # IceDatagram Acceptor bind/unbind timeout 60 | 61 | Timeout in seconds to wait for a bind or unbind "request" to complete for UDP, the `BIND_REQUEST_TIMEOUT` property is modifiable from the default of 3 seconds. 62 | 63 | # Socket linger for TCP sockets 64 | 65 | Specify a linger-on-close timeout. This option disables/enables immediate return from a `close()` of a TCP Socket. Enabling this option with a non-zero Integer timeout means that a `close()` will block pending the transmission and acknowledgement of all data written to the peer, at which point the socket is closed gracefully. Upon reaching the linger timeout, the socket is closed forcefully, with a TCP RST. Enabling the option with a timeout of zero does a forceful close immediately. If the specified timeout value exceeds 65,535 it will be reduced to 65,535. Valid only for *TCP*; linger time is in seconds, the default is -1 (disabled) 66 | 67 | The `SO_LINGER` property is modifiable from the default of -1. 68 | 69 | [Additional Info](https://stackoverflow.com/questions/3757289/when-is-tcp-option-so-linger-0-required#13088864) 70 | -------------------------------------------------------------------------------- /ice4j.code-workspace: -------------------------------------------------------------------------------- 1 | { 2 | "folders": [ 3 | { 4 | "path": "." 5 | } 6 | ], 7 | "settings": { 8 | "java.configuration.updateBuildConfiguration": "automatic" 9 | } 10 | } -------------------------------------------------------------------------------- /src/main/java/org/ice4j/AbstractResponseCollector.java: -------------------------------------------------------------------------------- 1 | /* 2 | * ice4j, the OpenSource Java Solution for NAT and Firewall Traversal. Copyright @ 2015 Atlassian Pty Ltd Licensed under the Apache License, Version 2.0 (the "License"); you may 3 | * not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or 4 | * agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 5 | * License for the specific language governing permissions and limitations under the License. 6 | */ 7 | package org.ice4j; 8 | 9 | /** 10 | * @author Lubomir Marinov 11 | */ 12 | public abstract class AbstractResponseCollector implements ResponseCollector { 13 | 14 | /** 15 | * Notifies this ResponseCollector that a transaction described by 16 | * the specified BaseStunMessageEvent has failed. The possible 17 | * reasons for the failure include timeouts, unreachable destination, etc. 18 | * 19 | * @param event the BaseStunMessageEvent which describes the failed 20 | * transaction and the runtime type of which specifies the failure reason 21 | */ 22 | protected abstract void processFailure(BaseStunMessageEvent event); 23 | 24 | /** 25 | * Notifies this collector that no response had been received after repeated 26 | * retransmissions of the original request (as described by rfc3489) and 27 | * that the request should be considered unanswered. 28 | * 29 | * @param event the StunTimeoutEvent containing a reference to the 30 | * transaction that has just failed. 31 | */ 32 | public void processTimeout(StunTimeoutEvent event) { 33 | processFailure(event); 34 | } 35 | 36 | /** 37 | * Notifies this collector that the destination of the request has been 38 | * determined to be unreachable and that the request should be considered 39 | * unanswered. 40 | * 41 | * @param event the StunFailureEvent containing the 42 | * PortUnreachableException that has just occurred. 43 | */ 44 | public void processUnreachable(StunFailureEvent event) { 45 | processFailure(event); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/org/ice4j/BaseStunMessageEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * ice4j, the OpenSource Java Solution for NAT and Firewall Traversal. Copyright @ 2015 Atlassian Pty Ltd Licensed under the Apache License, Version 2.0 (the "License"); you may 3 | * not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or 4 | * agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 5 | * License for the specific language governing permissions and limitations under the License. 6 | */ 7 | package org.ice4j; 8 | 9 | import java.util.EventObject; 10 | 11 | import org.ice4j.message.Message; 12 | import org.ice4j.stack.StunStack; 13 | import org.ice4j.stack.TransactionID; 14 | 15 | /** 16 | * Represents an EventObject which notifies of an event associated with a specific STUN Message. 17 | * 18 | * @author Lyubomir Marinov 19 | */ 20 | public class BaseStunMessageEvent extends EventObject { 21 | 22 | //private static final Logger logger = LoggerFactory.getLogger(BaseStunMessageEvent.class); 23 | 24 | /** 25 | * A dummy version UID to suppress warnings. 26 | */ 27 | private static final long serialVersionUID = 1L; 28 | 29 | /** 30 | * The STUN Message associated with this event. 31 | */ 32 | private final Message message; 33 | 34 | /** 35 | * The StunStack associated with this instance. 36 | */ 37 | private final StunStack stunStack; 38 | 39 | /** 40 | * The ID of the transaction related to {@link #message}. 41 | */ 42 | private TransactionID transactionID; 43 | 44 | /** 45 | * Initializes a new BaseStunMessageEvent associated with a 46 | * specific STUN Message. 47 | * 48 | * @param stunStack the StunStack to be associated with the new 49 | * instance 50 | * @param sourceAddress the TransportAddress which is to be 51 | * reported as the source of the new event 52 | * @param message the STUN Message associated with the new event 53 | */ 54 | public BaseStunMessageEvent(StunStack stunStack, TransportAddress sourceAddress, Message message) { 55 | super(sourceAddress); 56 | this.stunStack = stunStack; 57 | this.message = message; 58 | } 59 | 60 | /** 61 | * Gets the STUN Message associated with this event. 62 | * 63 | * @return the STUN Message associated with this event 64 | */ 65 | public Message getMessage() { 66 | return message; 67 | } 68 | 69 | /** 70 | * Gets the TransportAddress which is the source of this event. 71 | * 72 | * @return the TransportAddress which is the source of this event 73 | */ 74 | protected TransportAddress getSourceAddress() { 75 | return (TransportAddress) getSource(); 76 | } 77 | 78 | /** 79 | * Gets the StunStack associated with this instance. 80 | * 81 | * @return the StunStack associated with this instance 82 | */ 83 | public StunStack getStunStack() { 84 | return stunStack; 85 | } 86 | 87 | /** 88 | * Gets the ID of the transaction related to the STUN Message associated with this event. 89 | * 90 | * @return the ID of the transaction related to the STUN Message associated with this event 91 | */ 92 | public TransactionID getTransactionID() { 93 | //logger.debug("getTransactionID: {}", String.valueOf(transactionID)); 94 | if (transactionID == null) { 95 | transactionID = TransactionID.createTransactionID(getStunStack(), getMessage().getTransactionID()); 96 | } 97 | return transactionID; 98 | } 99 | 100 | /** 101 | * Allows descendants of this class to set the transaction ID so that we don't need to look it up later. This is not mandatory. 102 | * 103 | * @param tranID the ID of the transaction associated with this event. 104 | */ 105 | protected void setTransactionID(TransactionID tranID) { 106 | //logger.debug("setTransactionID: {}", String.valueOf(tranID)); 107 | this.transactionID = tranID; 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/main/java/org/ice4j/ResponseCollector.java: -------------------------------------------------------------------------------- 1 | /* 2 | * ice4j, the OpenSource Java Solution for NAT and Firewall Traversal. Copyright @ 2015 Atlassian Pty Ltd Licensed under the Apache License, Version 2.0 (the "License"); you may 3 | * not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or 4 | * agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 5 | * License for the specific language governing permissions and limitations under the License. 6 | */ 7 | package org.ice4j; 8 | 9 | /** 10 | * The interface is used as a callback when sending a request. The response 11 | * collector is then used as a means of dispatching the response. 12 | * 13 | * @author Emil Ivov 14 | */ 15 | public interface ResponseCollector { 16 | /** 17 | * Dispatch the specified response. 18 | * 19 | * @param event the response to dispatch. 20 | */ 21 | public void processResponse(StunResponseEvent event); 22 | 23 | /** 24 | * Notifies this collector that no response had been received after repeated 25 | * retransmissions of the original request (as described by rfc3489) and 26 | * that the request should be considered unanswered. 27 | * 28 | * @param event the StunTimeoutEvent containing a reference to the 29 | * transaction that has just failed. 30 | */ 31 | public void processTimeout(StunTimeoutEvent event); 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/org/ice4j/StunFailureEvent.java: -------------------------------------------------------------------------------- 1 | /* See LICENSE.md for license information */ 2 | package org.ice4j; 3 | 4 | import org.ice4j.message.Message; 5 | import org.ice4j.stack.StunStack; 6 | 7 | /** 8 | * The class is used to dispatch events that occur when a STUN transaction 9 | * fails asynchronously for reasons like a port unreachable exception for 10 | * example. 11 | * 12 | * @author Emil Ivov 13 | */ 14 | public class StunFailureEvent extends BaseStunMessageEvent { 15 | /** 16 | * Serial version UID for this Serializable class. 17 | */ 18 | private static final long serialVersionUID = 41232541L; 19 | 20 | /** 21 | * The Exception that caused this failure. 22 | */ 23 | private final Throwable cause; 24 | 25 | /** 26 | * Constructs a StunFailureEvent according to the specified 27 | * message. 28 | * 29 | * @param stunStack the StunStack to be associated with the new 30 | * instance 31 | * @param message the message itself 32 | * @param localAddress the local address that the message was sent from. 33 | * @param cause the Exception that caused this failure or 34 | * null if there's no Exception associated with this 35 | * failure 36 | */ 37 | public StunFailureEvent(StunStack stunStack, Message message, TransportAddress localAddress, Throwable cause) { 38 | super(stunStack, localAddress, message); 39 | 40 | this.cause = cause; 41 | } 42 | 43 | /** 44 | * Returns the TransportAddress that the message was supposed to 45 | * leave from. 46 | * 47 | * @return the TransportAddress that the message was supposed to 48 | * leave from. 49 | */ 50 | public TransportAddress getLocalAddress() { 51 | return getSourceAddress(); 52 | } 53 | 54 | /** 55 | * Returns the Exception that cause this failure or null 56 | * if the failure is not related to an Exception. 57 | * 58 | * @return the Exception that cause this failure or null 59 | * if the failure is not related to an Exception. 60 | */ 61 | public Throwable getCause() { 62 | return cause; 63 | } 64 | 65 | /** 66 | * Returns a String representation of this event, containing the 67 | * corresponding message, and local address. 68 | * 69 | * @return a String representation of this event, containing the 70 | * corresponding message, and local address. 71 | */ 72 | @Override 73 | public String toString() { 74 | StringBuilder buff = new StringBuilder("StunFailureEvent:\n\tMessage="); 75 | buff.append(getMessage()); 76 | buff.append(" localAddr=").append(getLocalAddress()); 77 | return buff.toString(); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/org/ice4j/StunMessageEvent.java: -------------------------------------------------------------------------------- 1 | /* See LICENSE.md for license information */ 2 | package org.ice4j; 3 | 4 | import org.ice4j.message.Message; 5 | import org.ice4j.stack.RawMessage; 6 | import org.ice4j.stack.StunStack; 7 | 8 | /** 9 | * The class is used to dispatch incoming stun messages. Apart from the message 10 | * itself one could also obtain the address from where the message is coming 11 | * (used by a server implementation to determine the mapped address) 12 | * as well as the Descriptor of the NetAccessPoint that received it (In case the 13 | * stack is used on more than one ports/addresses). 14 | * 15 | * @author Emil Ivov 16 | */ 17 | public class StunMessageEvent extends BaseStunMessageEvent { 18 | /** 19 | * Serial version UID for this Serializable class. 20 | */ 21 | private static final long serialVersionUID = 41267843L; 22 | 23 | /** 24 | * The message as we got it off the wire. 25 | */ 26 | private final RawMessage rawMessage; 27 | 28 | /** 29 | * Constructs a StunMessageEvent according to the specified message. 30 | * 31 | * @param stunStack the StunStack to be associated with the new 32 | * instance 33 | * @param rawMessage the crude message we got off the wire. 34 | * @param parsedMessage the message itself 35 | */ 36 | public StunMessageEvent(StunStack stunStack, RawMessage rawMessage, Message parsedMessage) { 37 | super(stunStack, rawMessage.getLocalAddress(), parsedMessage); 38 | this.rawMessage = rawMessage; 39 | } 40 | 41 | /** 42 | * Returns a TransportAddress referencing the access point where 43 | * the message was received. 44 | * 45 | * @return a descriptor of the access point where the message arrived. 46 | */ 47 | public TransportAddress getLocalAddress() { 48 | return getSourceAddress(); 49 | } 50 | 51 | /** 52 | * Returns the address that sent the message. 53 | * 54 | * @return the address that sent the message. 55 | */ 56 | public TransportAddress getRemoteAddress() { 57 | return rawMessage.getRemoteAddress(); 58 | } 59 | 60 | /** 61 | * Returns a String representation of this event, containing the 62 | * corresponding message, remote and local addresses. 63 | * 64 | * @return a String representation of this event, containing the 65 | * corresponding message, remote and local addresses. 66 | */ 67 | @Override 68 | public String toString() { 69 | StringBuilder buff = new StringBuilder("StunMessageEvent:\n\tMessage="); 70 | buff.append(getMessage()); 71 | buff.append(" remoteAddr=").append(getRemoteAddress()); 72 | buff.append(" localAddr=").append(getLocalAddress()); 73 | return buff.toString(); 74 | } 75 | 76 | /** 77 | * Returns the raw message that caused this event. 78 | * 79 | * @return the {@link RawMessage} that caused this event. 80 | */ 81 | public RawMessage getRawMessage() { 82 | return rawMessage; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/main/java/org/ice4j/StunResponseEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * ice4j, the OpenSource Java Solution for NAT and Firewall Traversal. 3 | * 4 | * Copyright @ 2015 Atlassian Pty Ltd 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.ice4j; 19 | 20 | import org.ice4j.message.*; 21 | import org.ice4j.stack.*; 22 | 23 | /** 24 | * The class is used to dispatch incoming STUN {@link Response}s. Apart from 25 | * the {@link Response} itself this event also carries a reference to the 26 | * {@link Request} that started the corresponding transaction as well as other 27 | * useful things. 28 | * 29 | * @author Emil Ivov 30 | */ 31 | public class StunResponseEvent 32 | extends StunMessageEvent 33 | { 34 | /** 35 | * Serial version UID for this Serializable class. 36 | */ 37 | private static final long serialVersionUID = -1L; 38 | 39 | /** 40 | * The original {@link Request} that started the client transaction that 41 | * the {@link Response} carried in this event belongs to. 42 | */ 43 | private final Request request; 44 | 45 | /** 46 | * Creates a new instance of this event. 47 | * 48 | * @param stunStack the StunStack to be associated with the new 49 | * instance 50 | * @param rawMessage the crude message we got off the wire. 51 | * @param response the STUN {@link Response} that we've just received. 52 | * @param request the message itself 53 | * @param transactionID a reference to the exact {@link TransactionID} 54 | * instance that represents the corresponding client transaction. 55 | */ 56 | public StunResponseEvent( 57 | StunStack stunStack, 58 | RawMessage rawMessage, 59 | Response response, 60 | Request request, 61 | TransactionID transactionID) 62 | { 63 | super(stunStack, rawMessage, response); 64 | this.request = request; 65 | super.setTransactionID(transactionID); 66 | } 67 | 68 | /** 69 | * Returns the {@link Request} that started the transaction that this 70 | * {@link Response} has just arrived in. 71 | * 72 | * @return the {@link Request} that started the transaction that this 73 | * {@link Response} has just arrived in. 74 | */ 75 | public Request getRequest() 76 | { 77 | return request; 78 | } 79 | 80 | /** 81 | * Returns the {@link Response} that has just arrived and that caused this 82 | * event. 83 | * 84 | * @return the {@link Response} that has just arrived and that caused this 85 | * event. 86 | */ 87 | public Response getResponse() 88 | { 89 | return (Response)getMessage(); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/main/java/org/ice4j/StunTimeoutEvent.java: -------------------------------------------------------------------------------- 1 | /* See LICENSE.md for license information */ 2 | package org.ice4j; 3 | 4 | import org.ice4j.message.Message; 5 | import org.ice4j.stack.StunStack; 6 | import org.ice4j.stack.TransactionID; 7 | 8 | /** 9 | * The class is used to dispatch events that occur when a STUN transaction 10 | * expires. 11 | * 12 | * @author Emil Ivov 13 | */ 14 | public class StunTimeoutEvent extends BaseStunMessageEvent { 15 | /** 16 | * Serial version UID for this Serializable class. 17 | */ 18 | private static final long serialVersionUID = 41267841L; 19 | 20 | /** 21 | * Constructs a StunTimeoutEvent according to the specified 22 | * message. 23 | * 24 | * @param stunStack the StunStack to be associated with the new 25 | * instance 26 | * @param message the message itself 27 | * @param localAddress the local address that the message was sent from. 28 | * @param transactionID the ID of the associated with this event. 29 | */ 30 | public StunTimeoutEvent(StunStack stunStack, Message message, TransportAddress localAddress, TransactionID transactionID) { 31 | super(stunStack, localAddress, message); 32 | 33 | setTransactionID(transactionID); 34 | } 35 | 36 | /** 37 | * Returns the TransportAddress that the message was supposed to 38 | * leave from. 39 | * 40 | * @return the TransportAddress that the message was supposed to 41 | * leave from. 42 | */ 43 | public TransportAddress getLocalAddress() { 44 | return getSourceAddress(); 45 | } 46 | 47 | /** 48 | * Returns a String representation of this event, containing the 49 | * corresponding message, and local address. 50 | * 51 | * @return a String representation of this event, containing the 52 | * corresponding message, and local address. 53 | */ 54 | @Override 55 | public String toString() { 56 | StringBuilder buff = new StringBuilder("StunTimeoutEvent:\n\tMessage="); 57 | buff.append(getMessage()); 58 | buff.append(" localAddr=").append(getLocalAddress()); 59 | return buff.toString(); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/org/ice4j/Transport.java: -------------------------------------------------------------------------------- 1 | /* See LICENSE.md for license information */ 2 | package org.ice4j; 3 | 4 | /** 5 | * The Transport enumeration contains all currently known transports 6 | * that ICE may be interacting with (but not necessarily support). 7 | * 8 | * @author Emil Ivov 9 | */ 10 | public enum Transport { 11 | 12 | /** 13 | * Represents a TCP transport. 14 | */ 15 | TCP("tcp", (byte) 6), 16 | 17 | /** 18 | * Represents a UDP transport. 19 | */ 20 | UDP("udp", (byte) 17), 21 | 22 | /** 23 | * Represents a TLS transport. 24 | */ 25 | TLS("tls", (byte) 0), 26 | 27 | /** 28 | * Represents a datagram TLS (DTLS) transport. 29 | */ 30 | DTLS("dtls", (byte) 0), 31 | 32 | /** 33 | * Represents an SCTP transport. 34 | */ 35 | SCTP("sctp", (byte) 0), 36 | 37 | /** 38 | * Represents an Google's SSL TCP transport. 39 | */ 40 | SSLTCP("ssltcp", (byte) 0); 41 | 42 | /** 43 | * The name of this Transport. 44 | */ 45 | private final String transportName; 46 | 47 | /** 48 | * The protocol number; used in messages to differentiate between transports. 49 | */ 50 | private final byte protocolNumber; 51 | 52 | /** 53 | * Creates a Transport instance with the specified name. 54 | * 55 | * @param transportName the name of the Transport instance we'd like to create. 56 | */ 57 | private Transport(String transportName, byte protocolNumber) { 58 | this.transportName = transportName; 59 | this.protocolNumber = protocolNumber; 60 | } 61 | 62 | public String getTransportName() { 63 | return transportName; 64 | } 65 | 66 | public byte getProtocolNumber() { 67 | return protocolNumber; 68 | } 69 | 70 | /** 71 | * Returns the name of this Transport (e.g. "udp" or "tcp"). 72 | * 73 | * @return the name of this Transport (e.g. "udp" or "tcp"). 74 | */ 75 | @Override 76 | public String toString() { 77 | return transportName; 78 | } 79 | 80 | /** 81 | * Returns a Transport instance corresponding to the specified transportName. For example, for name "udp", this method 82 | * would return {@link #UDP}. 83 | * 84 | * @param transportName the name that we'd like to parse. 85 | * @return a Transport instance corresponding to the specified transportName. 86 | * 87 | * @throws IllegalArgumentException in case transportName is not a valid or currently supported transport. 88 | */ 89 | public static Transport parse(String transportName) throws IllegalArgumentException { 90 | if (UDP.toString().equals(transportName)) { 91 | return UDP; 92 | } 93 | if (TCP.toString().equals(transportName)) { 94 | return TCP; 95 | } 96 | if (TLS.toString().equals(transportName)) { 97 | return TLS; 98 | } 99 | if (SCTP.toString().equals(transportName)) { 100 | return SCTP; 101 | } 102 | if (DTLS.toString().equals(transportName)) { 103 | return DTLS; 104 | } 105 | if (SSLTCP.toString().equals(transportName)) { 106 | return SSLTCP; 107 | } 108 | throw new IllegalArgumentException(transportName + " is not a currently supported Transport"); 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /src/main/java/org/ice4j/attribute/AlternateServerAttribute.java: -------------------------------------------------------------------------------- 1 | /* 2 | * ice4j, the OpenSource Java Solution for NAT and Firewall Traversal. 3 | * 4 | * Copyright @ 2015 Atlassian Pty Ltd 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.ice4j.attribute; 19 | 20 | /** 21 | * The ALTERNATE-SERVER attribute indicates the IP address and 22 | * port of an alternate server the client could use. For example, 23 | * alternate servers may contains special capabilities. 24 | * 25 | * It consists of an eight bit address family, and a sixteen bit 26 | * port, followed by a fixed length value representing the IP address. 27 | * 28 | * 0 1 2 3 29 | * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 30 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 31 | * |x x x x x x x x| Family | Port | 32 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 33 | * | Address | 34 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 35 | * 36 | * The port is a network byte ordered representation of the mapped port. 37 | * The address family is always 0x01, corresponding to IPv4. The first 38 | * 8 bits of the ALTERNATE-SERVER are ignored, for the purposes of 39 | * aligning parameters on natural boundaries. The IPv4 address is 32 40 | * bits. 41 | * 42 | * @author Sebastien Vincent 43 | */ 44 | public class AlternateServerAttribute extends AddressAttribute 45 | { 46 | 47 | /** 48 | * Constructor. 49 | */ 50 | AlternateServerAttribute() 51 | { 52 | super(Attribute.Type.ALTERNATE_SERVER); 53 | } 54 | } 55 | 56 | -------------------------------------------------------------------------------- /src/main/java/org/ice4j/attribute/ChangedAddressAttribute.java: -------------------------------------------------------------------------------- 1 | /* See LICENSE.md for license information */ 2 | package org.ice4j.attribute; 3 | 4 | import org.ice4j.TransportAddress; 5 | 6 | /** 7 | * The CHANGED-ADDRESS attribute indicates the IP address and port where 8 | * responses would have been sent from if the "change IP" and "change 9 | * port" flags had been set in the CHANGE-REQUEST attribute of the 10 | * Binding Request. The attribute is always present in a Binding 11 | * Response, independent of the value of the flags. Its syntax is 12 | * identical to MAPPED-ADDRESS. 13 | * 14 | * @author Emil Ivov 15 | */ 16 | public class ChangedAddressAttribute extends AddressAttribute { 17 | 18 | /** 19 | * Creates a CHANGED_ADDRESS attribute 20 | */ 21 | public ChangedAddressAttribute() { 22 | super(Attribute.Type.CHANGED_ADDRESS); 23 | } 24 | 25 | public ChangedAddressAttribute(TransportAddress address) { 26 | super(Attribute.Type.CHANGED_ADDRESS, address); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/org/ice4j/attribute/ContentDependentAttribute.java: -------------------------------------------------------------------------------- 1 | /* 2 | * ice4j, the OpenSource Java Solution for NAT and Firewall Traversal. 3 | * 4 | * Copyright @ 2015 Atlassian Pty Ltd 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.ice4j.attribute; 19 | 20 | import org.ice4j.stack.*; 21 | 22 | /** 23 | * ContentDependentAttributes have a value that depend on the content 24 | * of the message. The {@link MessageIntegrityAttribute} and {@link 25 | * FingerprintAttribute} are two such attributes. 26 | *

27 | * Rather than encoding them via the standard {@link Attribute#encode()} method, 28 | * the stack would use the one from this interface. 29 | *

30 | * 31 | * @author Emil Ivov 32 | */ 33 | public interface ContentDependentAttribute 34 | { 35 | /** 36 | * Returns a binary representation of this attribute. 37 | * 38 | * @param stunStack the StunStack in the context of which the 39 | * request to encode this ContentDependentAttribute is being made 40 | * @param content the content of the message that this attribute will be 41 | * transported in 42 | * @param offset the content-related offset where the actual 43 | * content starts. 44 | * @param length the length of the content in the content array. 45 | * 46 | * @return a binary representation of this attribute valid for the message 47 | * with the specified content. 48 | */ 49 | public byte[] encode( 50 | StunStack stunStack, 51 | byte[] content, int offset, int length); 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/org/ice4j/attribute/DestinationAddressAttribute.java: -------------------------------------------------------------------------------- 1 | /* See LICENSE.md for license information */ 2 | package org.ice4j.attribute; 3 | 4 | import org.ice4j.TransportAddress; 5 | 6 | /** 7 | * The DESTINATION-ADDRESS is present in Send Requests of old TURN versions. 8 | * It specifies the address and port where the data is to be sent. It is encoded 9 | * in the same way as MAPPED-ADDRESS. 10 | * 11 | * @author Sebastien Vincent 12 | */ 13 | public class DestinationAddressAttribute extends AddressAttribute { 14 | 15 | /** 16 | * Constructor. 17 | */ 18 | DestinationAddressAttribute() { 19 | super(Attribute.Type.DESTINATION_ADDRESS); 20 | } 21 | 22 | public DestinationAddressAttribute(TransportAddress address) { 23 | super(Attribute.Type.DESTINATION_ADDRESS, address); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/org/ice4j/attribute/DontFragmentAttribute.java: -------------------------------------------------------------------------------- 1 | /* See LICENSE.md for license information */ 2 | package org.ice4j.attribute; 3 | 4 | import org.ice4j.*; 5 | 6 | /** 7 | * The DONT-FRAGMENT attribute is used to inform TURN 8 | * server (if it supports this attribute) that it should set DF bit to 1 9 | * in IPv4 headers when relaying client data. 10 | * 11 | * @author Sebastien Vincent 12 | */ 13 | public class DontFragmentAttribute extends Attribute { 14 | 15 | /** 16 | * The length of the data contained by this attribute. 17 | */ 18 | public static final int DATA_LENGTH = 0; 19 | 20 | /** 21 | * Constructor. 22 | */ 23 | DontFragmentAttribute() { 24 | super(Attribute.Type.DONT_FRAGMENT); 25 | } 26 | 27 | /** 28 | * Compares two STUN Attributes. Attributes are considered equal when their 29 | * type, length, and all data are the same. 30 | * @param obj the object to compare this attribute with. 31 | * @return true if the attributes are equal and false otherwise. 32 | */ 33 | public boolean equals(Object obj) { 34 | if (!(obj instanceof DontFragmentAttribute)) 35 | return false; 36 | 37 | return true; 38 | } 39 | 40 | /** 41 | * Returns the length of this attribute's body. 42 | * @return the length of this attribute's value (8 bytes). 43 | */ 44 | public int getDataLength() { 45 | return DATA_LENGTH; 46 | } 47 | 48 | /** 49 | * Returns a binary representation of this attribute. 50 | * @return a binary representation of this attribute. 51 | */ 52 | public byte[] encode() { 53 | /* there is no data */ 54 | byte binValue[] = new byte[HEADER_LENGTH]; 55 | 56 | //Type 57 | int type = getAttributeType().getType(); 58 | binValue[0] = (byte) (type >> 8); 59 | binValue[1] = (byte) (type & 0x00FF); 60 | //Length 61 | binValue[2] = (byte) (getDataLength() >> 8); 62 | binValue[3] = (byte) (getDataLength() & 0x00FF); 63 | 64 | return binValue; 65 | } 66 | 67 | /** 68 | * Sets this attribute's fields according to attributeValue array. 69 | * @param attributeValue a binary array containing this attribute's field 70 | * values and NOT containing the attribute header. 71 | * @param offset the position where attribute values begin (most often 72 | * offset is equal to the index of the first byte after 73 | * length) 74 | * @param length the length of the binary array. 75 | * @throws StunException if attrubteValue contains invalid data. 76 | */ 77 | void decodeAttributeBody(byte[] attributeValue, int offset, int length) throws StunException { 78 | if (length != 0) { 79 | throw new StunException("length invalid"); 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/org/ice4j/attribute/EvenPortAttribute.java: -------------------------------------------------------------------------------- 1 | /* 2 | * ice4j, the OpenSource Java Solution for NAT and Firewall Traversal. 3 | * 4 | * Copyright @ 2015 Atlassian Pty Ltd 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.ice4j.attribute; 19 | 20 | import org.ice4j.*; 21 | 22 | /** 23 | * The EVEN-PORT attribute is used to ask the TURN 24 | * server to allocate an even port and optionally allocate 25 | * the next higher port number. 26 | * 27 | * There is one flag supported:
28 | * R : ask to reserve a second port. 29 | * 30 | * @author Sebastien Vincent 31 | */ 32 | public class EvenPortAttribute extends Attribute 33 | { 34 | 35 | /** 36 | * The length of the data contained by this attribute. 37 | */ 38 | public static final int DATA_LENGTH = 1; 39 | 40 | /** 41 | * R flag. 42 | */ 43 | boolean rFlag; 44 | 45 | /** 46 | * Constructor. 47 | */ 48 | EvenPortAttribute() 49 | { 50 | super(Attribute.Type.EVEN_PORT); 51 | } 52 | 53 | /** 54 | * Compares two STUN Attributes. Attributes are considered equal when their 55 | * type, length, and all data are the same. 56 | * @param obj the object to compare this attribute with. 57 | * @return true if the attributes are equal and false otherwise. 58 | */ 59 | public boolean equals(Object obj) 60 | { 61 | if (! (obj instanceof EvenPortAttribute)) 62 | return false; 63 | 64 | if (obj == this) 65 | return true; 66 | 67 | EvenPortAttribute att = (EvenPortAttribute) obj; 68 | if (att.getAttributeType() != getAttributeType() 69 | || att.getDataLength() != getDataLength() 70 | /* compare data */ 71 | || att.rFlag != rFlag 72 | ) 73 | return false; 74 | 75 | return true; 76 | } 77 | 78 | /** 79 | * Returns the length of this attribute's body. 80 | * @return the length of this attribute's value (8 bytes). 81 | */ 82 | public int getDataLength() 83 | { 84 | return DATA_LENGTH; 85 | } 86 | 87 | /** 88 | * Returns a binary representation of this attribute. 89 | * @return a binary representation of this attribute. 90 | */ 91 | public byte[] encode() 92 | { 93 | byte binValue[] = new byte[HEADER_LENGTH + DATA_LENGTH]; 94 | 95 | //Type 96 | int type = getAttributeType().getType(); 97 | binValue[0] = (byte)(type >> 8); 98 | binValue[1] = (byte)(type & 0x00FF); 99 | //Length 100 | binValue[2] = (byte)(getDataLength() >> 8); 101 | binValue[3] = (byte)(getDataLength() & 0x00FF); 102 | //Data 103 | binValue[4] = (byte)(rFlag ? 1 << 8 : 0); 104 | 105 | return binValue; 106 | } 107 | 108 | /** 109 | * Sets this attribute's fields according to attributeValue array. 110 | * @param attributeValue a binary array containing this attribute's field 111 | * values and NOT containing the attribute header. 112 | * @param offset the position where attribute values begin (most often 113 | * offset is equal to the index of the first byte after 114 | * length) 115 | * @param length the length of the binary array. 116 | * @throws StunException if attrubteValue contains invalid data. 117 | */ 118 | void decodeAttributeBody(byte[] attributeValue, int offset, int length) 119 | throws StunException 120 | { 121 | if(length != 4) 122 | { 123 | throw new StunException("length invalid"); 124 | } 125 | 126 | rFlag = (attributeValue[0] & 0x80) > 0; 127 | } 128 | 129 | /** 130 | * Set the R flag. 131 | * @param rFlag true of false 132 | */ 133 | public void setRFlag(boolean rFlag) 134 | { 135 | this.rFlag = rFlag; 136 | } 137 | 138 | /** 139 | * Is the R flag set 140 | * @return true if it is, false otherwise 141 | */ 142 | public boolean isRFlag() 143 | { 144 | return rFlag; 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /src/main/java/org/ice4j/attribute/IceControlledAttribute.java: -------------------------------------------------------------------------------- 1 | /* See LICENSE.md for license information */ 2 | package org.ice4j.attribute; 3 | 4 | /** 5 | * An {@link IceControlAttribute} implementation representing the 6 | * ICE-CONTROLLED ICE {@link Attribute}s. 7 | */ 8 | public final class IceControlledAttribute extends IceControlAttribute { 9 | /** 10 | * Constructs an ICE-CONTROLLING attribute. 11 | */ 12 | public IceControlledAttribute() { 13 | super(false); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/org/ice4j/attribute/IceControllingAttribute.java: -------------------------------------------------------------------------------- 1 | /* See LICENSE.md for license information */ 2 | package org.ice4j.attribute; 3 | 4 | /** 5 | * An {@link IceControlAttribute} implementation representing the 6 | * ICE-CONTROLLING ICE {@link Attribute}s. 7 | */ 8 | public final class IceControllingAttribute extends IceControlAttribute { 9 | /** 10 | * Constructs an ICE-CONTROLLING attribute. 11 | */ 12 | public IceControllingAttribute() { 13 | super(true); 14 | } 15 | 16 | @Override 17 | public String toString() { 18 | return "IceControllingAttribute [tieBreaker=" + tieBreaker + ", isControlling=" + isControlling + "]"; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/org/ice4j/attribute/LifetimeAttribute.java: -------------------------------------------------------------------------------- 1 | /* See LICENSE.md for license information */ 2 | package org.ice4j.attribute; 3 | 4 | import org.ice4j.StunException; 5 | 6 | /** 7 | * The LIFETIME attribute is used to know the lifetime 8 | * of TURN allocations. 9 | * 10 | * @author Sebastien Vincent 11 | * @author Aakash Garg 12 | */ 13 | public class LifetimeAttribute extends Attribute { 14 | 15 | /** 16 | * The length of the data contained by this attribute. 17 | */ 18 | public static final int DATA_LENGTH = 4; 19 | 20 | /** 21 | * Lifetime value. 22 | */ 23 | int lifetime = 0; 24 | 25 | /** 26 | * Constructor. 27 | */ 28 | LifetimeAttribute() { 29 | super(Attribute.Type.LIFETIME); 30 | } 31 | 32 | /** 33 | * Compares two STUN Attributes. Attributes are considered equal when their 34 | * type, length, and all data are the same. 35 | * @param obj the object to compare this attribute with. 36 | * @return true if the attributes are equal and false otherwise. 37 | */ 38 | @Override 39 | public boolean equals(Object obj) { 40 | if (!(obj instanceof LifetimeAttribute)) 41 | return false; 42 | 43 | if (obj == this) 44 | return true; 45 | 46 | LifetimeAttribute att = (LifetimeAttribute) obj; 47 | if (att.getAttributeType() != getAttributeType() || att.getDataLength() != getDataLength() 48 | /* compare data */ 49 | || att.lifetime != lifetime) 50 | return false; 51 | 52 | return true; 53 | } 54 | 55 | /** 56 | * Returns the length of this attribute's body. 57 | * @return the length of this attribute's value (8 bytes). 58 | */ 59 | @Override 60 | public int getDataLength() { 61 | return DATA_LENGTH; 62 | } 63 | 64 | /** 65 | * Returns a binary representation of this attribute. 66 | * @return a binary representation of this attribute. 67 | */ 68 | @Override 69 | public byte[] encode() { 70 | byte binValue[] = new byte[HEADER_LENGTH + DATA_LENGTH]; 71 | 72 | //Type 73 | int type = getAttributeType().getType(); 74 | binValue[0] = (byte) (type >> 8); 75 | binValue[1] = (byte) (type & 0x00FF); 76 | //Length 77 | binValue[2] = (byte) (getDataLength() >> 8); 78 | binValue[3] = (byte) (getDataLength() & 0x00FF); 79 | //Data 80 | binValue[4] = (byte) ((lifetime >> 24) & 0xff); 81 | binValue[5] = (byte) ((lifetime >> 16) & 0xff); 82 | binValue[6] = (byte) ((lifetime >> 8) & 0xff); 83 | binValue[7] = (byte) ((lifetime) & 0xff); 84 | 85 | return binValue; 86 | } 87 | 88 | /** 89 | * Sets this attribute's fields according to attributeValue array. 90 | * @param attributeValue a binary array containing this attribute's field 91 | * values and NOT containing the attribute header. 92 | * @param offset the position where attribute values begin (most often 93 | * offset is equal to the index of the first byte after 94 | * length) 95 | * @param length the length of the binary array. 96 | * @throws StunException if attrubteValue contains invalid data. 97 | */ 98 | @Override 99 | void decodeAttributeBody(byte[] attributeValue, int offset, int length) throws StunException { 100 | if (length != 4) { 101 | throw new StunException("length invalid"); 102 | } 103 | 104 | lifetime = ((attributeValue[offset] << 24) & 0xff000000) + ((attributeValue[offset + 1] << 16) & 0x00ff0000) + ((attributeValue[offset + 2] << 8) & 0x0000ff00) + (attributeValue[offset + 3] & 0x000000ff); 105 | } 106 | 107 | /** 108 | * Set the lifetime. 109 | * @param lifetime lifetime 110 | */ 111 | public void setLifetime(int lifetime) { 112 | this.lifetime = lifetime; 113 | } 114 | 115 | /** 116 | * Get the lifetime. 117 | * @return lifetime 118 | */ 119 | public int getLifetime() { 120 | return lifetime; 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /src/main/java/org/ice4j/attribute/MagicCookieAttribute.java: -------------------------------------------------------------------------------- 1 | /* 2 | * ice4j, the OpenSource Java Solution for NAT and Firewall Traversal. Copyright @ 2015 Atlassian Pty Ltd Licensed under the Apache License, Version 2.0 (the "License"); you may 3 | * not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or 4 | * agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 5 | * License for the specific language governing permissions and limitations under the License. 6 | */ 7 | package org.ice4j.attribute; 8 | 9 | import org.ice4j.*; 10 | 11 | /** 12 | * The MAGIC-COOKIE attribute. 13 | * 14 | * It is used with old version of TURN (Google, Live messenger variant, ...). 15 | * 16 | * @author Sebastien Vincent 17 | */ 18 | public class MagicCookieAttribute extends Attribute { 19 | 20 | /** 21 | * The length of the data contained by this attribute. 22 | */ 23 | public static final int DATA_LENGTH = 4; 24 | 25 | /** 26 | * Magic cookie value. 27 | */ 28 | private int value = 0x72c64bc6; 29 | 30 | /** 31 | * Constructor. 32 | */ 33 | MagicCookieAttribute() { 34 | super(Attribute.Type.MAGIC_COOKIE); 35 | } 36 | 37 | /** 38 | * Returns the length of this attribute's body. 39 | * 40 | * @return the length of this attribute's value (8 bytes). 41 | */ 42 | public int getDataLength() { 43 | return DATA_LENGTH; 44 | } 45 | 46 | /** 47 | * Compares two STUN Attributes. Attributes are considered equal when their 48 | * type, length, and all data are the same. 49 | * 50 | * @param obj the object to compare this attribute with. 51 | * @return true if the attributes are equal and false otherwise. 52 | */ 53 | public boolean equals(Object obj) { 54 | if (!(obj instanceof MagicCookieAttribute)) 55 | return false; 56 | 57 | if (obj == this) 58 | return true; 59 | 60 | MagicCookieAttribute att = (MagicCookieAttribute) obj; 61 | if (att.getAttributeType() != getAttributeType() || att.getDataLength() != getDataLength() 62 | /* compare data */ 63 | || att.value != value) 64 | return false; 65 | 66 | return true; 67 | } 68 | 69 | /** 70 | * Returns a binary representation of this attribute. 71 | * 72 | * @return a binary representation of this attribute. 73 | */ 74 | public byte[] encode() { 75 | byte binValue[] = new byte[HEADER_LENGTH + DATA_LENGTH]; 76 | 77 | //Type 78 | int type = getAttributeType().getType(); 79 | binValue[0] = (byte) (type >> 8); 80 | binValue[1] = (byte) (type & 0x00FF); 81 | //Length 82 | binValue[2] = (byte) (getDataLength() >> 8); 83 | binValue[3] = (byte) (getDataLength() & 0x00FF); 84 | //Data 85 | binValue[4] = (byte) ((value >> 24) & 0xff); 86 | binValue[5] = (byte) ((value >> 16) & 0xff); 87 | binValue[6] = (byte) ((value >> 8) & 0xff); 88 | binValue[7] = (byte) ((value) & 0xff); 89 | 90 | return binValue; 91 | } 92 | 93 | /** 94 | * Sets this attribute's fields according to attributeValue array. 95 | * 96 | * @param attributeValue a binary array containing this attribute's field 97 | * values and NOT containing the attribute header. 98 | * @param offset the position where attribute values begin (most often 99 | * offset is equal to the index of the first byte after 100 | * length) 101 | * @param length the length of the binary array. 102 | * @throws StunException if attrubteValue contains invalid data. 103 | */ 104 | void decodeAttributeBody(byte[] attributeValue, int offset, int length) throws StunException { 105 | if (length != 4) { 106 | throw new StunException("length invalid"); 107 | } 108 | 109 | value = ((attributeValue[0] << 24) & 0xff000000) + ((attributeValue[1] << 16) & 0x00ff0000) + ((attributeValue[2] << 8) & 0x0000ff00) + (attributeValue[3] & 0x000000ff); 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /src/main/java/org/ice4j/attribute/MappedAddressAttribute.java: -------------------------------------------------------------------------------- 1 | /* See LICENSE.md for license information */ 2 | package org.ice4j.attribute; 3 | 4 | import org.ice4j.TransportAddress; 5 | 6 | /** 7 | * The MAPPED-ADDRESS attribute indicates the mapped IP address and 8 | * port. It consists of an eight bit address family, and a sixteen bit 9 | * port, followed by a fixed length value representing the IP address. 10 | * 11 | * 0 1 2 3 12 | * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 13 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 14 | * |x x x x x x x x| Family | Port | 15 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 16 | * | Address | 17 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 18 | * 19 | * The port is a network byte ordered representation of the mapped port. 20 | * The address family is always 0x01, corresponding to IPv4. The first 21 | * 8 bits of the MAPPED-ADDRESS are ignored, for the purposes of 22 | * aligning parameters on natural boundaries. The IPv4 address is 32 23 | * bits. 24 | * 25 | * @author Emil Ivov 26 | */ 27 | public class MappedAddressAttribute extends AddressAttribute { 28 | 29 | /** 30 | * Constructor. 31 | */ 32 | MappedAddressAttribute() { 33 | super(Attribute.Type.MAPPED_ADDRESS); 34 | } 35 | 36 | public MappedAddressAttribute(TransportAddress address) { 37 | super(Attribute.Type.MAPPED_ADDRESS, address); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/org/ice4j/attribute/NonceAttribute.java: -------------------------------------------------------------------------------- 1 | /* 2 | * ice4j, the OpenSource Java Solution for NAT and Firewall Traversal. 3 | * 4 | * Copyright @ 2015 Atlassian Pty Ltd 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.ice4j.attribute; 19 | 20 | import java.util.*; 21 | 22 | import org.ice4j.*; 23 | 24 | /** 25 | * The NONCE attribute is used for authentication. 26 | * 27 | * @author Sebastien Vincent 28 | */ 29 | public class NonceAttribute extends Attribute 30 | { 31 | 32 | /** 33 | * Nonce value. 34 | */ 35 | private byte nonce[] = null; 36 | 37 | /** 38 | * Constructor. 39 | */ 40 | NonceAttribute() 41 | { 42 | super(Attribute.Type.NONCE); 43 | } 44 | 45 | /** 46 | * Copies the value of the nonce attribute from the specified 47 | * attributeValue. 48 | * @param attributeValue a binary array containing this attribute's 49 | * field values and NOT containing the attribute header. 50 | * @param offset the position where attribute values begin (most often 51 | * offset is equal to the index of the first byte after length) 52 | * @param length the length of the binary array. 53 | * @throws StunException if attributeValue contains invalid data. 54 | */ 55 | void decodeAttributeBody(byte[] attributeValue, int offset, int length) 56 | throws StunException 57 | { 58 | nonce = new byte[length]; 59 | System.arraycopy(attributeValue, offset, nonce, 0, length); 60 | } 61 | 62 | /** 63 | * Returns a binary representation of this attribute. 64 | * @return a binary representation of this attribute. 65 | */ 66 | public byte[] encode() 67 | { 68 | byte binValue[] 69 | = new byte[HEADER_LENGTH + getDataLength() + (getDataLength() % 4)]; 70 | 71 | //Type 72 | int type = getAttributeType().getType(); 73 | binValue[0] = (byte)(type >> 8); 74 | binValue[1] = (byte)(type & 0x00FF); 75 | 76 | //Length 77 | binValue[2] = (byte)(getDataLength() >> 8); 78 | binValue[3] = (byte)(getDataLength() & 0x00FF); 79 | 80 | /* nonce */ 81 | System.arraycopy(nonce, 0, binValue, 4, (int)getDataLength()); 82 | 83 | return binValue; 84 | } 85 | 86 | /** 87 | * Returns the length of this attribute's body. 88 | * @return the length of this attribute's value. 89 | */ 90 | public int getDataLength() 91 | { 92 | return nonce.length; 93 | } 94 | 95 | /** 96 | * Returns a (cloned) byte array containing the data value of the nonce 97 | * attribute. 98 | * @return the binary array containing the nonce. 99 | */ 100 | public byte[] getNonce() 101 | { 102 | return (nonce == null) ? null : nonce.clone(); 103 | } 104 | 105 | /** 106 | * Copies the specified binary array into the the data value of the nonce 107 | * attribute. 108 | * @param nonce the binary array containing the nonce. 109 | */ 110 | public void setNonce(byte[] nonce) 111 | { 112 | this.nonce = (nonce == null) ? null : nonce.clone(); 113 | } 114 | 115 | /** 116 | * Compares two STUN Attributes. Two attributes are considered equal when they 117 | * have the same type length and value. 118 | * @param obj the object to compare this attribute with. 119 | * @return true if the attributes are equal and false otherwise. 120 | */ 121 | public boolean equals(Object obj) 122 | { 123 | if (obj == this) 124 | return true; 125 | if (! (obj instanceof NonceAttribute)) 126 | return false; 127 | 128 | NonceAttribute att = (NonceAttribute) obj; 129 | 130 | return 131 | (att.getAttributeType() == getAttributeType() 132 | && att.getDataLength() == getDataLength() 133 | && Arrays.equals(att.nonce, nonce)); 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /src/main/java/org/ice4j/attribute/OptionalAttribute.java: -------------------------------------------------------------------------------- 1 | /* See LICENSE.md for license information */ 2 | package org.ice4j.attribute; 3 | 4 | import java.util.*; 5 | 6 | import org.ice4j.*; 7 | 8 | /** 9 | * This class is used for representing attributes not explicitly supported by 10 | * the stack. Such attributes will generally be kept in binary form and won't 11 | * be subdued to any processing by the stack. One could use this class for both 12 | * dealing with attributes in received messages, and generating messages 13 | * containing attributes not explicitly supported by the stack. 14 | * 15 | * @author Emil Ivov 16 | */ 17 | public class OptionalAttribute extends Attribute { 18 | 19 | byte[] attributeValue = null; 20 | 21 | int typeOverride = Integer.MIN_VALUE; 22 | 23 | protected OptionalAttribute() { 24 | super(Attribute.Type.UNKNOWN_OPTIONAL_ATTRIBUTE); 25 | } 26 | 27 | protected OptionalAttribute(int attributeType) { 28 | super(attributeType); 29 | if (attributeType != this.attributeType.type) { 30 | typeOverride = attributeType; 31 | } 32 | } 33 | 34 | /** 35 | * Sets this attribute's fields according to attributeValue array. 36 | * 37 | * @param attributeValue a binary array containing this attribute's 38 | * field values and NOT containing the attribute header. 39 | * @param offset the position where attribute values begin (most often 40 | * offset is equal to the index of the first byte after length) 41 | * @param length the length of the binary array. 42 | * @throws StunException if attrubteValue contains invalid data. 43 | */ 44 | void decodeAttributeBody(byte[] attributeValue, int offset, int length) throws StunException { 45 | this.attributeValue = new byte[length]; 46 | System.arraycopy(attributeValue, offset, this.attributeValue, 0, length); 47 | } 48 | 49 | /** 50 | * Returns a binary representation of this attribute. 51 | * 52 | * @return a binary representation of this attribute. 53 | */ 54 | public byte[] encode() { 55 | byte binValue[] = new byte[HEADER_LENGTH + attributeValue.length]; 56 | 57 | //Type 58 | int type = typeOverride != Integer.MIN_VALUE ? typeOverride : getAttributeType().getType(); 59 | binValue[0] = (byte) (type >> 8); 60 | binValue[1] = (byte) (type & 0x00FF); 61 | //Length 62 | binValue[2] = (byte) (getDataLength() >> 8); 63 | binValue[3] = (byte) (getDataLength() & 0x00FF); 64 | 65 | System.arraycopy(attributeValue, 0, binValue, HEADER_LENGTH, attributeValue.length); 66 | 67 | return binValue; 68 | } 69 | 70 | /** 71 | * Returns the length of this attribute's body. 72 | * 73 | * @return the length of this attribute's value. 74 | */ 75 | public int getDataLength() { 76 | return attributeValue.length; 77 | } 78 | 79 | /** 80 | * Returns a reference to the unparsed body of this attribute. 81 | * 82 | * @return a reference to this attribute's unparsed value. 83 | */ 84 | public byte[] getBody() { 85 | return attributeValue; 86 | } 87 | 88 | /** 89 | * Copies the specified byte array segment as the body of this attribute. 90 | * 91 | * @param body the body to copy 92 | * @param offset the position to start 93 | * @param length the length to copy 94 | */ 95 | public void setBody(byte[] body, int offset, int length) { 96 | this.attributeValue = new byte[length]; 97 | System.arraycopy(body, offset, this.attributeValue, 0, length); 98 | } 99 | 100 | /** 101 | * Compares two STUN Attributes. Two attributes are considered equal when they 102 | * have the same type length and value. 103 | * 104 | * @param obj the object to compare this attribute with. 105 | * @return true if the attributes are equal and false otherwise. 106 | */ 107 | public boolean equals(Object obj) { 108 | if (!(obj instanceof OptionalAttribute)) 109 | return false; 110 | 111 | return (obj == this || Arrays.equals(((OptionalAttribute) obj).attributeValue, attributeValue)); 112 | } 113 | 114 | @Override 115 | public String toString() { 116 | return "OptionalAttribute [attributeValue=" + Arrays.toString(attributeValue) + ", typeOverride=" + typeOverride + "]"; 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /src/main/java/org/ice4j/attribute/ReflectedFromAttribute.java: -------------------------------------------------------------------------------- 1 | /* See LICENSE.md for license information */ 2 | package org.ice4j.attribute; 3 | 4 | import org.ice4j.TransportAddress; 5 | 6 | /** 7 | * The REFLECTED-FROM attribute is present only in Binding Responses, 8 | * when the Binding Request contained a RESPONSE-ADDRESS attribute. The 9 | * attribute contains the identity (in terms of IP address) of the 10 | * source where the request came from. Its purpose is to provide 11 | * traceability, so that a STUN server cannot be used as a reflector for 12 | * denial-of-service attacks. 13 | * 14 | * Its syntax is identical to the MAPPED-ADDRESS attribute. 15 | * 16 | * @author Emil Ivov 17 | */ 18 | public class ReflectedFromAttribute extends AddressAttribute { 19 | 20 | /** 21 | * Creates a REFLECTED-FROM attribute 22 | */ 23 | public ReflectedFromAttribute() { 24 | super(Attribute.Type.REFLECTED_FROM); 25 | } 26 | 27 | public ReflectedFromAttribute(TransportAddress address) { 28 | super(Attribute.Type.REFLECTED_FROM, address); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/org/ice4j/attribute/RemoteAddressAttribute.java: -------------------------------------------------------------------------------- 1 | /* 2 | * ice4j, the OpenSource Java Solution for NAT and Firewall Traversal. 3 | * 4 | * Copyright @ 2015 Atlassian Pty Ltd 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.ice4j.attribute; 19 | 20 | /** 21 | * The REMOTE-ADDRESS is present in Data Indication of old TURN versions. 22 | * It specifies the address and port where the data is sent. It is encoded 23 | * in the same way as MAPPED-ADDRESS. 24 | * 25 | * @author Sebastien Vincent 26 | */ 27 | public class RemoteAddressAttribute extends AddressAttribute 28 | { 29 | 30 | /** 31 | * Constructor. 32 | */ 33 | RemoteAddressAttribute() 34 | { 35 | super(Attribute.Type.REMOTE_ADDRESS); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/org/ice4j/attribute/ResponseAddressAttribute.java: -------------------------------------------------------------------------------- 1 | /* See LICENSE.md for license information */ 2 | package org.ice4j.attribute; 3 | 4 | import org.ice4j.TransportAddress; 5 | 6 | /** 7 | * The RESPONSE-ADDRESS attribute indicates where the response to a 8 | * Binding Request should be sent. Its syntax is identical to MAPPED-ADDRESS. 9 | * 10 | * @author Emil Ivov 11 | */ 12 | public class ResponseAddressAttribute extends AddressAttribute { 13 | 14 | /** 15 | * Creates a RESPONSE_ADDRESS attribute 16 | */ 17 | public ResponseAddressAttribute() { 18 | super(Attribute.Type.RESPONSE_ADDRESS); 19 | } 20 | 21 | public ResponseAddressAttribute(TransportAddress address) { 22 | super(Attribute.Type.RESPONSE_ADDRESS, address); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/org/ice4j/attribute/SourceAddressAttribute.java: -------------------------------------------------------------------------------- 1 | /* See LICENSE.md for license information */ 2 | package org.ice4j.attribute; 3 | 4 | import org.ice4j.TransportAddress; 5 | 6 | /** 7 | * The SOURCE-ADDRESS attribute is present in Binding Responses. It 8 | * indicates the source IP address and port that the server is sending 9 | * the response from. Its syntax is identical to that of MAPPED-ADDRESS. 10 | * 11 | * @author Emil Ivov 12 | */ 13 | public class SourceAddressAttribute extends AddressAttribute { 14 | 15 | /** 16 | * Creates a SOURCE-ADDRESS attribute 17 | */ 18 | SourceAddressAttribute() { 19 | super(Attribute.Type.SOURCE_ADDRESS); 20 | } 21 | 22 | public SourceAddressAttribute(TransportAddress address) { 23 | super(Attribute.Type.SOURCE_ADDRESS, address); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/org/ice4j/attribute/UseCandidateAttribute.java: -------------------------------------------------------------------------------- 1 | /* See LICENSE.md for license information */ 2 | package org.ice4j.attribute; 3 | 4 | import org.ice4j.*; 5 | 6 | /** 7 | * This class implements the USE-CANDIDATE attribute 8 | * This attribute is an extension to the original STUN protocol 9 | * This is used only during an ICE implementation 10 | * 11 | * This attribute serves as only a flag, it does not have any data so the data length is zero 12 | */ 13 | public class UseCandidateAttribute extends Attribute { 14 | /** 15 | * Data length. 16 | */ 17 | private static final int DATA_LENGTH_USE_CANDIDATE = 0; 18 | 19 | /** 20 | * Constructor. 21 | */ 22 | protected UseCandidateAttribute() { 23 | super(Attribute.Type.USE_CANDIDATE); 24 | } 25 | 26 | /** 27 | * Decodes the USE-CANDIDATE attribute's body, which is empty 28 | * 29 | * @param attributeValue a binary array containing this attribute's 30 | * field values and NOT containing the attribute header. 31 | * @param offset the position where attribute values begin (most often 32 | * offset is equal to the index of the first byte after length) 33 | * @param length the length of the binary array. 34 | * @throws StunException if attrubteValue contains invalid data. 35 | */ 36 | void decodeAttributeBody(byte[] attributeValue, int offset, int length) throws StunException { 37 | // Do nothing, empty attribute body 38 | } 39 | 40 | /** 41 | * Returns a binary representation of this attribute. 42 | * 43 | * @return a binary representation of this attribute. 44 | */ 45 | public byte[] encode() { 46 | byte[] binValue = new byte[HEADER_LENGTH + DATA_LENGTH_USE_CANDIDATE]; 47 | // Type 48 | int type = getAttributeType().getType(); 49 | binValue[0] = (byte) (type >> 8); 50 | binValue[1] = (byte) (type & 0x00FF); 51 | // Length 52 | binValue[2] = (byte) (DATA_LENGTH_USE_CANDIDATE >> 8); 53 | binValue[3] = (byte) (DATA_LENGTH_USE_CANDIDATE & 0x00FF); 54 | return binValue; 55 | } 56 | 57 | /** 58 | * Compares two STUN Attributes. Two attributes are considered equal when 59 | * they have the same type, length and value. 60 | * 61 | * @param obj the object to compare this attribute with. 62 | * @return true if the attributes are equal and false otherwise. 63 | */ 64 | public boolean equals(Object obj) { 65 | if (!(obj instanceof UseCandidateAttribute)) 66 | return false; 67 | 68 | if (obj == this) 69 | return true; 70 | 71 | UseCandidateAttribute useCandidateAtt = (UseCandidateAttribute) obj; 72 | if (useCandidateAtt.getAttributeType() != getAttributeType() || useCandidateAtt.getDataLength() != getDataLength()) 73 | return false; 74 | 75 | return true; 76 | } 77 | 78 | /** 79 | * Returns the length of this attribute's body. 80 | * 81 | * @return the length of this attribute's value. 82 | */ 83 | public int getDataLength() { 84 | return DATA_LENGTH_USE_CANDIDATE; 85 | } 86 | 87 | } 88 | -------------------------------------------------------------------------------- /src/main/java/org/ice4j/attribute/XorOnlyAttribute.java: -------------------------------------------------------------------------------- 1 | /* 2 | * ice4j, the OpenSource Java Solution for NAT and Firewall Traversal. 3 | * 4 | * Copyright @ 2015 Atlassian Pty Ltd 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.ice4j.attribute; 19 | 20 | import org.ice4j.*; 21 | 22 | /** 23 | * This attribute is present in a Binding Request. It is used by a 24 | * client to request that a server compliant to this specification omit 25 | * the MAPPED-ADDRESS from a Binding Response, and include only the XOR- 26 | * MAPPED-ADDRESS. This is necessary in cases where a Binding Response 27 | * is failing integrity checks because a NAT is rewriting the contents 28 | * of a MAPPED-ADDRESS in the Binding Response. 29 | * 30 | * This attribute has a length of zero, and therefore contains no other 31 | * information past the common attribute header. 32 | * 33 | * @author Emil Ivov 34 | */ 35 | public class XorOnlyAttribute 36 | extends Attribute 37 | { 38 | /** 39 | * Constructor. 40 | */ 41 | protected XorOnlyAttribute() 42 | { 43 | super(Attribute.Type.XOR_ONLY); 44 | } 45 | 46 | /** 47 | * Sets this attribute's fields according to attributeValue array. 48 | * 49 | * @param attributeValue a binary array containing this attribute's 50 | * field values and NOT containing the attribute header. 51 | * @param offset the position where attribute values begin (most often 52 | * offset is equal to the index of the first byte after length) 53 | * @param length the length of the binary array. 54 | * @throws StunException if attrubteValue contains invalid data. 55 | */ 56 | void decodeAttributeBody(byte[] attributeValue, int offset, int length) 57 | throws StunException 58 | { 59 | //nothing to do cause we have 0 length 60 | } 61 | 62 | /** 63 | * Returns a binary representation of this attribute. 64 | * 65 | * @return a binary representation of this attribute. 66 | */ 67 | public byte[] encode() 68 | { 69 | byte binValue[] = new byte[HEADER_LENGTH + getDataLength()]; 70 | 71 | //Type 72 | int type = getAttributeType().getType(); 73 | binValue[0] = (byte)(type >> 8); 74 | binValue[1] = (byte)(type & 0x00FF); 75 | 76 | //Length 77 | binValue[2] = (byte)(getDataLength() >> 8); 78 | binValue[3] = (byte)(getDataLength() & 0x00FF); 79 | 80 | return binValue; 81 | } 82 | 83 | /** 84 | * Returns the length of this attribute's body. (Which in the case of the 85 | * XOR-ONLY attribute is 0); 86 | * 87 | * @return the length of this attribute's value. 88 | */ 89 | public int getDataLength() 90 | { 91 | return 0; 92 | } 93 | 94 | /** 95 | * Compares two STUN Attributes. Two attributes are considered equal when 96 | * they have the same type length and value. 97 | * 98 | * @param obj the object to compare this attribute with. 99 | * @return true if the attributes are equal and false otherwise. 100 | */ 101 | 102 | public boolean equals(Object obj) 103 | { 104 | if (! (obj instanceof XorOnlyAttribute)) 105 | return false; 106 | 107 | if (obj == this) 108 | return true; 109 | 110 | XorOnlyAttribute att = (XorOnlyAttribute) obj; 111 | if (att.getAttributeType() != getAttributeType() 112 | || att.getDataLength() != getDataLength()) 113 | return false; 114 | 115 | return true; 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /src/main/java/org/ice4j/attribute/XorPeerAddressAttribute.java: -------------------------------------------------------------------------------- 1 | /* See LICENSE.md for license information */ 2 | package org.ice4j.attribute; 3 | 4 | /** 5 | * The XOR-PEER-ADDRESS attribute is given by a TURN client to indicates the peer destination address of its relayed packet. 6 | * 7 | * It has the same format as XOR-MAPPED-ADDRESS. 8 | * 9 | * @author Sebastien Vincent 10 | */ 11 | public class XorPeerAddressAttribute extends XorMappedAddressAttribute { 12 | 13 | XorPeerAddressAttribute() { 14 | super(Attribute.Type.XOR_PEER_ADDRESS); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/org/ice4j/attribute/XorRelayedAddressAttribute.java: -------------------------------------------------------------------------------- 1 | /* 2 | * ice4j, the OpenSource Java Solution for NAT and Firewall Traversal. Copyright @ 2015 Atlassian Pty Ltd Licensed under the Apache License, Version 2.0 (the "License"); you may 3 | * not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or 4 | * agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 5 | * License for the specific language governing permissions and limitations under the License. 6 | */ 7 | package org.ice4j.attribute; 8 | 9 | /** 10 | * The XOR-RELAYED-ADDRESS attribute is given by a TURN server to indicates the client its relayed address. 11 | * 12 | * It has the same format as XOR-MAPPED-ADDRESS. 13 | * 14 | * @author Sebastien Vincent 15 | */ 16 | public class XorRelayedAddressAttribute extends XorMappedAddressAttribute { 17 | 18 | /** 19 | * Constructor. 20 | */ 21 | XorRelayedAddressAttribute() { 22 | super(Attribute.Type.XOR_RELAYED_ADDRESS); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/org/ice4j/ice/CandidatePairState.java: -------------------------------------------------------------------------------- 1 | /* 2 | * ice4j, the OpenSource Java Solution for NAT and Firewall Traversal. 3 | * 4 | * Copyright @ 2015 Atlassian Pty Ltd 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.ice4j.ice; 19 | 20 | /** 21 | * Each candidate pair in the a list has a CandidatePairState. It is 22 | * assigned once the check list for each media stream has been computed. There 23 | * are five potential values that the state can have and they are all 24 | * represented by this enumeration. 25 | * 26 | * @author Emil Ivov 27 | */ 28 | public enum CandidatePairState 29 | { 30 | /** 31 | * Indicates that the candidate pair is in a Waiting state which means that 32 | * a check has not been performed for this pair, and can be performed as 33 | * soon as it is the highest priority Waiting pair on the check list. 34 | */ 35 | WAITING("Waiting"), 36 | 37 | /** 38 | * Indicates that the candidate pair is in a "In-Progress" state which 39 | * means that a check has been sent for this pair, but the transaction is 40 | * in progress. 41 | */ 42 | IN_PROGRESS("In-Progress"), 43 | 44 | /** 45 | * Indicates that the candidate pair is in a "Succeeded" state which means 46 | * that a check for this pair was already done and produced a successful 47 | * result. 48 | */ 49 | SUCCEEDED("Succeeded"), 50 | 51 | /** 52 | * Indicates that the candidate pair is in a "Failed" state which means that 53 | * a check for this pair was already done and failed, either never producing 54 | * any response or producing an unrecoverable failure response. 55 | */ 56 | FAILED("Failed"), 57 | 58 | /** 59 | * Indicates that the candidate pair is in a "Frozen" state which means that 60 | * a check for this pair hasn't been performed, and it can't yet be 61 | * performed until some other check succeeds, allowing this pair to unfreeze 62 | * and move into the Waiting state. 63 | */ 64 | FROZEN("Frozen"); 65 | 66 | /** 67 | * The name of this CandidatePairState instance. 68 | */ 69 | private final String stateName; 70 | 71 | /** 72 | * Creates a CandidatePairState instance with the specified name. 73 | * 74 | * @param stateName the name of the CandidatePairState instance 75 | * we'd like to create. 76 | */ 77 | private CandidatePairState(String stateName) 78 | { 79 | this.stateName = stateName; 80 | } 81 | 82 | /** 83 | * Returns the name of this CandidatePairStae (e.g. "In-Progress", 84 | * "Waiting", "Succeeded", or "Failed"). 85 | * 86 | * @return the name of this Transport (e.g. "Waiting" or 87 | * "Frozen"). 88 | */ 89 | @Override 90 | public String toString() 91 | { 92 | return stateName; 93 | } 94 | 95 | } 96 | -------------------------------------------------------------------------------- /src/main/java/org/ice4j/ice/CandidatePrioritizer.java: -------------------------------------------------------------------------------- 1 | /* See LICENSE.md for license information */ 2 | package org.ice4j.ice; 3 | 4 | import java.util.Comparator; 5 | 6 | /** 7 | * Compares candidates based on their priority. 8 | * 9 | * @author Emil Ivov 10 | */ 11 | class CandidatePrioritizer implements Comparator> { 12 | /** 13 | * Compares the two Candidates based on their priority and 14 | * returns a negative integer, zero, or a positive integer as the first 15 | * Candidate has a lower, equal, or greater priority than the 16 | * second. 17 | * 18 | * @param c1 the first Candidate to compare. 19 | * @param c2 the second Candidate to compare. 20 | * 21 | * @return a negative integer, zero, or a positive integer as the first 22 | * Candidate has a lower, equal, 23 | * or greater priority than the 24 | * second. 25 | */ 26 | public static int compareCandidates(Candidate c1, Candidate c2) { 27 | if (c1.getPriority() < c2.getPriority()) { 28 | return 1; 29 | } else if (c1.getPriority() == c2.getPriority()) { 30 | return 0; 31 | } else { 32 | //if(c1.getPriority() > c2.getPriority()) 33 | return -1; 34 | } 35 | } 36 | 37 | /** 38 | * Compares the two Candidates based on their priority and 39 | * returns a negative integer, zero, or a positive integer as the first 40 | * Candidate has a lower, equal, or greater priority than the 41 | * second. 42 | * 43 | * @param c1 the first Candidate to compare. 44 | * @param c2 the second Candidate to compare. 45 | * 46 | * @return a negative integer, zero, or a positive integer as the first 47 | * Candidate has a lower, equal, 48 | * or greater priority than the 49 | * second. 50 | */ 51 | public int compare(Candidate c1, Candidate c2) { 52 | return CandidatePrioritizer.compareCandidates(c1, c2); 53 | } 54 | 55 | /** 56 | * Indicates whether some other object is "equal to" this 57 | * Comparator. This method must obey the general contract of 58 | * Object.equals(Object). Additionally, this method can return 59 | * true only if the specified Object is also a 60 | * comparator and it imposes the same ordering as this comparator. Thus, 61 | * comp1.equals(comp2) implies that 62 | * sgn(comp1.compare(o1, o2))==sgn(comp2.compare(o1, o2)) for 63 | * every object reference o1 and o2.

64 | *

65 | * Note that it is always safe not to override 66 | * Object.equals(Object). However, overriding this method may, 67 | * in some cases, improve performance by allowing programs to determine 68 | * that two distinct Comparators impose the same order. 69 | *
70 | * 71 | * @param obj the reference object with which to compare. 72 | * 73 | * @return true only if the specified object is also 74 | * a comparator and it imposes the same ordering as this 75 | * comparator. 76 | * 77 | * @see Object#equals(Object) 78 | * @see Object#hashCode() 79 | */ 80 | public boolean equals(Object obj) { 81 | return (obj instanceof CandidatePrioritizer); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/main/java/org/ice4j/ice/CandidateTcpType.java: -------------------------------------------------------------------------------- 1 | /* See LICENSE.md for license information */ 2 | package org.ice4j.ice; 3 | 4 | /** 5 | * Represents the TCP types for ICE TCP candidates. 6 | * See http://tools.ietf.org/html/rfc6544 7 | * 8 | * @author Boris Grozev 9 | */ 10 | public enum CandidateTcpType { 11 | /** 12 | * The "active" TCP candidate type. 13 | */ 14 | ACTIVE("active"), 15 | 16 | /** 17 | * The "passive" TCP candidate type. 18 | */ 19 | PASSIVE("passive"), 20 | 21 | /** 22 | * The "so" (simultaneous-open) TCP candidate type. 23 | */ 24 | SO("so"); 25 | 26 | /** 27 | * The name of this CandidateTcpType instance. 28 | */ 29 | private final String name; 30 | 31 | /** 32 | * Creates a CandidateTcpType instance with the specified name. 33 | * 34 | * @param name the name of the CandidateTcpType instance we'd 35 | * like to create. 36 | */ 37 | private CandidateTcpType(String name) { 38 | this.name = name; 39 | } 40 | 41 | /** 42 | * Returns the name of this CandidateTcpType (e.g. "active", 43 | * "passive", or "so"). 44 | * 45 | * @return the name of this CandidateTcpType (e.g. "active", 46 | * "passive", or "so"). 47 | */ 48 | @Override 49 | public String toString() { 50 | return name; 51 | } 52 | 53 | /** 54 | * 55 | * Parses the string candidateTcpTypeName and return the 56 | * corresponding CandidateTcpType instance. 57 | * 58 | * @param candidateTcpTypeName the string to parse 59 | * @return candidateTcpTypeName as an Enum 60 | * @throws IllegalArgumentException in case candidateTcpTypeName is 61 | * not a valid or currently supported candidate TCP type. 62 | */ 63 | public static CandidateTcpType parse(String candidateTcpTypeName) throws IllegalArgumentException { 64 | for (CandidateTcpType type : values()) 65 | if (type.toString().equals(candidateTcpTypeName)) 66 | return type; 67 | 68 | throw new IllegalArgumentException(candidateTcpTypeName + " is not a currently supported CandidateTcpType"); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/org/ice4j/ice/CheckListState.java: -------------------------------------------------------------------------------- 1 | /* See LICENSE.md for license information */ 2 | package org.ice4j.ice; 3 | 4 | /** 5 | * Ever CheckList is associated with a state, which captures the state of ICE checks for that media stream. There are three states: 6 | *
7 | * Running: In this state, ICE checks are still in progress for this media stream. 8 | *
9 | * Completed: In this state, ICE checks have produced nominated pairs for each component of the media stream. Consequently, ICE has succeeded and 10 | * media can be sent. 11 | *
12 | * Failed: In this state, the ICE checks have not completed successfully for this media stream. 13 | *
14 | * When a check list is first constructed as the consequence of an offer/answer exchange, it is placed in the Running state. 15 | * 16 | * @author Emil Ivov 17 | */ 18 | public enum CheckListState { 19 | /** 20 | * In this state, ICE checks are still in progress for this media stream. 21 | */ 22 | RUNNING("Running"), 23 | 24 | /** 25 | * In this state, ICE checks have produced nominated pairs for each component of the media stream. Consequently, ICE has succeeded and 26 | * media can be sent. 27 | */ 28 | COMPLETED("Completed"), 29 | 30 | /** 31 | * In this state, the ICE checks have not completed successfully for this media stream. 32 | */ 33 | FAILED("Failed"); 34 | 35 | /** 36 | * The name of this CheckListState instance. 37 | */ 38 | private final String stateName; 39 | 40 | /** 41 | * Creates a CheckListState instance with the specified name. 42 | * 43 | * @param stateName the name of the CheckListState instance we'd like to create 44 | */ 45 | private CheckListState(String stateName) { 46 | this.stateName = stateName; 47 | } 48 | 49 | /** 50 | * Returns the name of this CheckListState (i.e.. "Running", "Completed", or "Failed"). 51 | * 52 | * @return the name of this CheckListState 53 | */ 54 | @Override 55 | public String toString() { 56 | return stateName; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/org/ice4j/ice/FoundationsRegistry.java: -------------------------------------------------------------------------------- 1 | /* See LICENSE.md for license information */ 2 | package org.ice4j.ice; 3 | 4 | import java.util.concurrent.ConcurrentHashMap; 5 | import java.util.concurrent.ConcurrentMap; 6 | import java.util.concurrent.atomic.AtomicInteger; 7 | 8 | import org.ice4j.TransportAddress; 9 | 10 | /** 11 | * We FoundationsRegistrys to keep track of and generate new foundations within the lifetime of a single Agent. 12 | * 13 | * @author Emil Ivov 14 | */ 15 | public class FoundationsRegistry { 16 | 17 | /** 18 | * The foundation number that was last assigned to a Candidate 19 | */ 20 | private AtomicInteger lastAssignedFoundation = new AtomicInteger(0); 21 | 22 | /** 23 | * The foundation number that was last assigned to a PEER-REFLEXIVE RemoteCandidate 24 | */ 25 | private AtomicInteger lastAssignedRemoteFoundation = new AtomicInteger(10000); 26 | 27 | /** 28 | * Contains mappings between a type+baseIP+server+transport Strings and the foundation that has been assigned to them. 29 | */ 30 | private ConcurrentMap foundations = new ConcurrentHashMap<>(); 31 | 32 | /** 33 | * Assigns to candidate the foundation that corresponds to its base, type and transport properties or a new one if no foundation has 34 | * been generated yet for the specific combination. 35 | * 36 | * @param candidate the Candidate that we'd like to assign a foundation to 37 | */ 38 | public void assignFoundation(Candidate candidate) { 39 | //create the foundation key String 40 | CandidateType candidateType = candidate.getType(); 41 | String type = candidateType.toString(); 42 | String base = candidate.getBase().getTransportAddress().getHostAddress(); 43 | String server; 44 | switch (candidateType) { 45 | case SERVER_REFLEXIVE_CANDIDATE: 46 | TransportAddress serverAddress = candidate.getStunServerAddress(); 47 | server = (serverAddress == null) ? "" : serverAddress.getHostAddress(); 48 | break; 49 | case RELAYED_CANDIDATE: 50 | server = candidate.getRelayServerAddress().getHostAddress(); 51 | break; 52 | default: 53 | server = null; 54 | break; 55 | } 56 | String transport = candidate.getTransport().toString(); 57 | StringBuilder foundationStringBuff = new StringBuilder(type); 58 | foundationStringBuff.append(base); 59 | if (server != null) { 60 | foundationStringBuff.append(server); 61 | } 62 | foundationStringBuff.append(transport); 63 | String foundationString = foundationStringBuff.toString(); 64 | String foundationValue = foundations.get(foundationString); 65 | //obtain a new foundation number if we don't have one for this kind of candidates. 66 | if (foundationValue == null) { 67 | foundationValue = Integer.toString(lastAssignedFoundation.incrementAndGet()); 68 | foundations.put(foundationString, foundationValue); 69 | } 70 | candidate.setFoundation(foundationValue); 71 | } 72 | 73 | /** 74 | * Returns an (as far as you care) random foundation that could be assigned to a learned PEER-REFLEXIVE candidate. 75 | * 76 | * @return a foundation String that could be assigned to a learned PEER-REFLEXIVE candidate. 77 | */ 78 | public String obtainFoundationForPeerReflexiveCandidate() { 79 | return Integer.toString(lastAssignedRemoteFoundation.getAndIncrement()); 80 | } 81 | 82 | /** 83 | * Returns the number of foundation Strings that are currently tracked by the registry. 84 | * 85 | * @return the number of foundation Strings that are currently tracked by this registry. 86 | */ 87 | public int size() { 88 | return foundations.size(); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/main/java/org/ice4j/ice/HostCandidate.java: -------------------------------------------------------------------------------- 1 | /* See LICENSE.md for license information */ 2 | package org.ice4j.ice; 3 | 4 | import java.net.DatagramSocket; 5 | 6 | import org.ice4j.Transport; 7 | import org.ice4j.TransportAddress; 8 | import org.ice4j.socket.IceSocketWrapper; 9 | 10 | /** 11 | * HostCandidates are obtained by binding to a specific port from an IP address on the host that is running us. This includes IP addresses on 12 | * physical interfaces and logical ones, such as ones obtained through Virtual Private Networks (VPNs), Mobile IPv6, Realm Specific IP (RSIP) etc. 13 | *
14 | * At this point this class only supports UDP candidates. Implementation of support for other transport protocols should mean that this class should 15 | * become abstract and some transport specific components like to socket for example should be brought down the inheritance chain. 16 | * 17 | * @author Emil Ivov 18 | */ 19 | public class HostCandidate extends LocalCandidate { 20 | 21 | /** 22 | * If this is a local candidate the field contains the socket that is actually associated with the candidate. 23 | */ 24 | private final IceSocketWrapper socket; 25 | 26 | /** 27 | * Creates a HostCandidate for the specified transport address. 28 | * 29 | * @param socket the {@link DatagramSocket} that communication associated with this Candidate will be going through. 30 | * @param parentComponent the Component that this candidate belongs to. 31 | */ 32 | public HostCandidate(IceSocketWrapper socket, Component parentComponent) { 33 | this(socket, parentComponent, Transport.UDP); 34 | } 35 | 36 | /** 37 | * Creates a HostCandidate for the specified transport address. 38 | * 39 | * @param transportAddress the transport address for the new HostCandidate. 40 | * @param parentComponent the Component that this candidate belongs to. 41 | */ 42 | public HostCandidate(TransportAddress transportAddress, Component parentComponent) { 43 | super(transportAddress, parentComponent, CandidateType.HOST_CANDIDATE, CandidateExtendedType.HOST_CANDIDATE, null); 44 | this.socket = null; 45 | setBase(this); 46 | } 47 | 48 | /** 49 | * Creates a HostCandidate for the specified transport address. 50 | * 51 | * @param socket the {@link DatagramSocket} that communication associated with this Candidate will be going through. 52 | * @param parentComponent the Component that this candidate belongs to. 53 | * @param transport transport protocol used 54 | */ 55 | public HostCandidate(IceSocketWrapper socket, Component parentComponent, Transport transport) { 56 | super(new TransportAddress(socket.getLocalAddress(), socket.getLocalPort(), transport), parentComponent, CandidateType.HOST_CANDIDATE, CandidateExtendedType.HOST_CANDIDATE, null); 57 | this.socket = socket; 58 | setBase(this); 59 | } 60 | 61 | /** 62 | * {@inheritDoc} 63 | * SHOULD NOT be used outside ice4j. Only exposed for use in the org.ice4j.socket package. 64 | */ 65 | @Override 66 | public IceSocketWrapper getCandidateIceSocketWrapper() { 67 | logger.debug("getCandidateIceSocketWrapper: {}", socket); 68 | return socket; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/org/ice4j/ice/IceProcessingState.java: -------------------------------------------------------------------------------- 1 | /* 2 | * ice4j, the OpenSource Java Solution for NAT and Firewall Traversal. Copyright @ 2015 Atlassian Pty Ltd Licensed under the Apache License, Version 2.0 (the "License"); you may 3 | * not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or 4 | * agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 5 | * License for the specific language governing permissions and limitations under the License. 6 | */ 7 | package org.ice4j.ice; 8 | 9 | /** 10 | * RFC 5245 mentions that ICE processing across all media streams also has a 11 | * state associated with it. This state is equal to Running while ICE 12 | * processing is under way. The state is Completed when ICE processing is 13 | * complete and Failed if it failed without success. For convenience reasons 14 | * we are also adding two extra states. The first one is the Waiting 15 | * state that reflects the state of an {@link Agent} before it starts 16 | * processing. This is also an {@link Agent }'s default state. The second one 17 | * is the "Terminated" state. RFC 5245 says that once ICE processing 18 | * has reached the Completed state for all peers for media streams using 19 | * those candidates, the agent SHOULD wait an additional three seconds, 20 | * and then it MAY cease responding to checks or generating triggered 21 | * checks on that candidate. It MAY free the candidate at that time. 22 | * which reflects the state where an Agent does not need to handle incoming 23 | * checks any more and is ready for garbage collection. This is the state we 24 | * refer to with "Terminated". 25 | * 26 | * @author Emil Ivov 27 | * @author Lyubomir Marinov 28 | */ 29 | public enum IceProcessingState { 30 | /** 31 | * The state is equal to Waiting if ICE processing has not started for the corresponding {@link Agent}. 32 | */ 33 | WAITING("Waiting"), 34 | 35 | /** 36 | * The state is equal to Running while ICE processing is under way. 37 | */ 38 | RUNNING("Running"), 39 | 40 | /** 41 | * The state is Completed when ICE processing is complete. 42 | */ 43 | COMPLETED("Completed"), 44 | 45 | /** 46 | * The state is Completed when ICE processing is Failed if processing failed without success. 47 | */ 48 | FAILED("Failed"), 49 | 50 | /** 51 | * Once ICE processing has reached the Completed state for all peers for media streams using those candidates, the agent SHOULD wait an 52 | * additional three seconds, and then it MAY cease responding to checks or generating triggered checks on that candidate. It MAY free the 53 | * candidate at that time. This is also when an agent would enter the terminated state. 54 | */ 55 | TERMINATED("Terminated"); 56 | 57 | /** 58 | * The name of this IceProcessingState instance. 59 | */ 60 | private final String stateName; 61 | 62 | /** 63 | * Creates an IceProcessingState instance with the specified name. 64 | * 65 | * @param stateName the name of the IceProcessingState instance we'd like to create. 66 | */ 67 | private IceProcessingState(String stateName) { 68 | this.stateName = stateName; 69 | } 70 | 71 | /** 72 | * Returns the name of this IceProcessingState (e.g. "Running", "Completed", or "Failed"). 73 | * 74 | * @return name of this IceProcessingState 75 | */ 76 | @Override 77 | public String toString() { 78 | return stateName; 79 | } 80 | 81 | /** 82 | * Determines whether an {@link Agent} in this state has finished its ICE processing. 83 | * 84 | * @return true if an Agent in this state has finished its processing; otherwise false 85 | */ 86 | public boolean isOver() { 87 | return COMPLETED.equals(this) || FAILED.equals(this) || TERMINATED.equals(this); 88 | } 89 | 90 | /** 91 | * Returns true if the state is one in which a connection has been established, that is either COMPLETED or 92 | * TERMINATED. 93 | * 94 | * @return true when a connection has been established and false otherwise 95 | */ 96 | public boolean isEstablished() { 97 | return this == COMPLETED || this == TERMINATED; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/main/java/org/ice4j/ice/KeepAliveStrategy.java: -------------------------------------------------------------------------------- 1 | /* 2 | * ice4j, the OpenSource Java Solution for NAT and Firewall Traversal. 3 | * 4 | * Copyright @ 2015 Atlassian Pty Ltd 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.ice4j.ice; 19 | 20 | /** 21 | * An enumeration of strategies for selecting which candidate pairs to 22 | * keep alive. 23 | */ 24 | public enum KeepAliveStrategy 25 | { 26 | /** 27 | * Only keep alive the selected pair. 28 | */ 29 | SELECTED_ONLY("selected_only"), 30 | 31 | /** 32 | * Keep alive the selected pair and any TCP pairs. 33 | */ 34 | SELECTED_AND_TCP("selected_and_tcp"), 35 | 36 | /** 37 | * Keep alive all succeeded pairs. 38 | */ 39 | ALL_SUCCEEDED("all_succeeded"); 40 | 41 | private String name; 42 | 43 | KeepAliveStrategy(String name) 44 | { 45 | this.name = name; 46 | } 47 | 48 | /** 49 | * @return the {@link KeepAliveStrategy} with name equal to the given 50 | * string, or {@code null} if there is no such strategy. 51 | * @param string the name of the strategy. 52 | */ 53 | public static KeepAliveStrategy fromString(String string) 54 | { 55 | for (KeepAliveStrategy strategy : KeepAliveStrategy.values()) 56 | { 57 | if (strategy.name.equals(string)) 58 | return strategy; 59 | } 60 | return null; 61 | } 62 | 63 | /** 64 | * {@inheritDoc} 65 | */ 66 | @Override 67 | public String toString() 68 | { 69 | return name; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/org/ice4j/ice/NominationStrategy.java: -------------------------------------------------------------------------------- 1 | /* 2 | * ice4j, the OpenSource Java Solution for NAT and Firewall Traversal. Copyright @ 2015 Atlassian Pty Ltd Licensed under the Apache License, Version 2.0 (the "License"); you may 3 | * not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or 4 | * agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 5 | * License for the specific language governing permissions and limitations under the License. 6 | */ 7 | package org.ice4j.ice; 8 | 9 | /** 10 | * Contains the nomination strategies currently supported by this 11 | * implementation's {@link DefaultNominator} class. Applications can either 12 | * pick one of these strategies or select NONE in case they want to 13 | * handle nominations themselves. 14 | *

15 | * Note that NominationStrategies are an ice4j concept and they are not 16 | * mentioned in RFC 5245. 17 | * 18 | * @author Emil Ivov 19 | */ 20 | public enum NominationStrategy { 21 | /** 22 | * Indicates that ice4j's nominator should nominate valid pairs and that 23 | * the application will be handling this. 24 | */ 25 | NONE("None"), 26 | 27 | /** 28 | * The strategy consists in nominating the first candidate pair that's 29 | * confirmed as valid. 30 | */ 31 | NOMINATE_FIRST_VALID("NominateFirstValid"), 32 | 33 | /** 34 | * The strategy consists in nominating the highest priority valid pair once 35 | * all checks in a list have completed. 36 | */ 37 | NOMINATE_HIGHEST_PRIO("NominateHighestPriority"), 38 | 39 | /** 40 | * The strategy consists in nominating the first host or server reflexive 41 | * that's confirmed as valid pair. When a relayed candidate pair is 42 | * validated first, a timer is armed and only if no host or server 43 | * reflexive pair gets validated prior to timeout, the relayed ones 44 | * gets nominated. 45 | */ 46 | NOMINATE_FIRST_HOST_OR_REFLEXIVE_VALID("NominateFirstHostOrReflexiveValid"), 47 | 48 | /** 49 | * The strategy consists in nominating the pair that showed the best 50 | * shortest round trip time once all checks in a list completed. 51 | */ 52 | NOMINATE_BEST_RTT("NominateBestRTT"); 53 | 54 | /** 55 | * The name of this strategy. 56 | */ 57 | private final String strategyName; 58 | 59 | /** 60 | * Creates a NominationStrategy instance with the specified name. 61 | * 62 | * @param name the name of the NominationStrategy that we'd like 63 | * to create. 64 | */ 65 | private NominationStrategy(String name) { 66 | this.strategyName = name; 67 | } 68 | 69 | /** 70 | * Returns the name of this NominationStrategy. 71 | * 72 | * @return the name of this NominationStrategy. 73 | */ 74 | @Override 75 | public String toString() { 76 | return strategyName; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/main/java/org/ice4j/ice/PeerReflexiveCandidate.java: -------------------------------------------------------------------------------- 1 | /* 2 | * ice4j, the OpenSource Java Solution for NAT and Firewall Traversal. Copyright @ 2015 Atlassian Pty Ltd Licensed under the Apache License, Version 2.0 (the "License"); you may 3 | * not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or 4 | * agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 5 | * License for the specific language governing permissions and limitations under the License. 6 | */ 7 | package org.ice4j.ice; 8 | 9 | import org.ice4j.*; 10 | import org.ice4j.socket.*; 11 | import org.slf4j.Logger; 12 | import org.slf4j.LoggerFactory; 13 | 14 | /** 15 | * Peer Reflexive Candidates are candidates whose IP address and port are a binding explicitly allocated by a NAT for an agent when it sent a STUN 16 | * Binding request through the NAT to its peer. 17 | *

18 | * Peer Reflexive Candidates are generally allocated by NATs with endpoint dependent mapping also known as Symmetric NATs. PeerReflexiveCandidates 19 | * are generally preferred to relayed ones. RFC 5245 explains this with better security ... although simply avoiding a relay would probably be 20 | * enough of a reason for many. 21 | * 22 | * @author Emil Ivov 23 | */ 24 | public class PeerReflexiveCandidate extends LocalCandidate { 25 | 26 | private static final Logger logger = LoggerFactory.getLogger(PeerReflexiveCandidate.class); 27 | 28 | /** 29 | * Creates a PeerReflexiveCandidate instance for the specified transport address and properties. 30 | * 31 | * @param transportAddress the transport address that this candidate is encapsulating 32 | * @param parentComponent the Component that this candidate belongs to 33 | * @param base the base of a peer reflexive candidate base is the local candidate of the candidate pair from which the STUN check was sent 34 | * @param priority the priority of the candidate 35 | */ 36 | public PeerReflexiveCandidate(TransportAddress transportAddress, Component parentComponent, LocalCandidate base, long priority) { 37 | super(transportAddress, parentComponent, CandidateType.PEER_REFLEXIVE_CANDIDATE, CandidateExtendedType.STUN_PEER_REFLEXIVE_CANDIDATE, base); 38 | super.setBase(base); 39 | super.priority = priority; 40 | if (transportAddress.getTransport() != Transport.UDP) { 41 | super.setTcpType(base.getTcpType()); 42 | } 43 | logger.debug("ctor - addr: {} comp: {} related candidate: {}", transportAddress, parentComponent, base); 44 | } 45 | 46 | /** 47 | * {@inheritDoc} 48 | */ 49 | @Override 50 | public IceSocketWrapper getCandidateIceSocketWrapper() { 51 | return getBase().getCandidateIceSocketWrapper(); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/org/ice4j/ice/RelayedCandidate.java: -------------------------------------------------------------------------------- 1 | /* See LICENSE.md for license information */ 2 | package org.ice4j.ice; 3 | 4 | import java.io.IOException; 5 | import java.lang.reflect.UndeclaredThrowableException; 6 | 7 | import org.ice4j.TransportAddress; 8 | import org.ice4j.ice.harvest.TurnCandidateHarvest; 9 | import org.ice4j.socket.IceSocketWrapper; 10 | import org.ice4j.socket.RelayedCandidateConnection; 11 | import org.slf4j.Logger; 12 | import org.slf4j.LoggerFactory; 13 | 14 | /** 15 | * Represents a Candidate obtained by sending a TURN Allocate request from a HostCandidate to a TURN server. The relayed candidate is 16 | * resident on the TURN server, and the TURN server relays packets back towards the agent. 17 | * 18 | * @author Lubomir Marinov 19 | * @author Paul Gregoire 20 | */ 21 | public class RelayedCandidate extends LocalCandidate { 22 | 23 | private static final Logger logger = LoggerFactory.getLogger(RelayedCandidate.class); 24 | 25 | /** 26 | * The RelayedCandidateConnection of this RelayedCandidate. 27 | */ 28 | private RelayedCandidateConnection relayedCandidateConnection; 29 | 30 | /** 31 | * The application-purposed DatagramSocket associated with this Candidate. 32 | */ 33 | private IceSocketWrapper socket; 34 | 35 | /** 36 | * The TurnCandidateHarvest which has harvested this RelayedCandidate. 37 | */ 38 | private final TurnCandidateHarvest turnCandidateHarvest; 39 | 40 | /** 41 | * Initializes a new RelayedCandidate which is to represent a specific TransportAddress harvested through a specific HostCandidate and a 42 | * TURN server with a specific TransportAddress. 43 | * 44 | * @param transportAddress the TransportAddress to be represented by the new instance 45 | * @param turnCandidateHarvest the TurnCandidateHarvest which has harvested the new instance 46 | * @param mappedAddress the mapped TransportAddress reported by the TURN server with the delivery of the replayed transportAddress 47 | * to be represented by the new instance 48 | */ 49 | public RelayedCandidate(TransportAddress transportAddress, TurnCandidateHarvest turnCandidateHarvest, TransportAddress mappedAddress) { 50 | super(transportAddress, turnCandidateHarvest.hostCandidate.getParentComponent(), CandidateType.RELAYED_CANDIDATE, CandidateExtendedType.TURN_RELAYED_CANDIDATE, turnCandidateHarvest.hostCandidate.getParentComponent().findLocalCandidate(mappedAddress)); 51 | this.turnCandidateHarvest = turnCandidateHarvest; 52 | // RFC 5245: The base of a relayed candidate is that candidate itself 53 | setBase(this); 54 | setRelayServerAddress(turnCandidateHarvest.harvester.stunServer); 55 | setMappedAddress(mappedAddress); 56 | } 57 | 58 | /** 59 | * Gets the application-purposed IceSocketWrapper associated with this Candidate. 60 | * 61 | * @return the IceSocketWrapper associated with this Candidate 62 | */ 63 | @Override 64 | public IceSocketWrapper getCandidateIceSocketWrapper() { 65 | if (socket == null) { 66 | logger.debug("getCandidateIceSocketWrapper {}", relayedCandidateConnection); 67 | try { 68 | if (relayedCandidateConnection == null) { 69 | // create the RelayedCandidateConnection of this RelayedCandidate 70 | relayedCandidateConnection = new RelayedCandidateConnection(this, turnCandidateHarvest); 71 | // use turn server as remote destination and set relayed connection 72 | socket = IceSocketWrapper.build(relayedCandidateConnection); 73 | } 74 | } catch (IOException e) { 75 | throw new UndeclaredThrowableException(e); 76 | } 77 | } 78 | return socket; 79 | } 80 | 81 | /** 82 | * Returns the relayed candidate connection. 83 | * 84 | * @return RelayedCandidateConnection 85 | */ 86 | public RelayedCandidateConnection getRelayedCandidateConnection() { 87 | return relayedCandidateConnection; 88 | } 89 | 90 | /** 91 | * Returns the TurnCandidateHarvest for this candidate. 92 | * 93 | * @return TurnCandidateHarvest 94 | */ 95 | public TurnCandidateHarvest getTurnCandidateHarvest() { 96 | return turnCandidateHarvest; 97 | } 98 | 99 | } 100 | -------------------------------------------------------------------------------- /src/main/java/org/ice4j/ice/ServerReflexiveCandidate.java: -------------------------------------------------------------------------------- 1 | /* 2 | * ice4j, the OpenSource Java Solution for NAT and Firewall Traversal. Copyright @ 2015 Atlassian Pty Ltd Licensed under the Apache License, Version 2.0 (the "License"); you may 3 | * not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or 4 | * agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 5 | * License for the specific language governing permissions and limitations under the License. 6 | */ 7 | package org.ice4j.ice; 8 | 9 | import org.ice4j.TransportAddress; 10 | import org.ice4j.ice.harvest.StunCandidateHarvest; 11 | import org.ice4j.socket.IceSocketWrapper; 12 | 13 | /** 14 | * ServerReflexiveCandidates are candidates whose IP address and port are a binding allocated by a NAT for an agent when it sent a packet through 15 | * the NAT to a server. ServerReflexiveCandidates can be learned by STUN servers using the Binding Request, or TURN servers, which provides both 16 | * a Relayed and Server Reflexive candidate. 17 | *
18 | * This class does not contain a socket itself and in order to send bytes over the network, one has to retrieve the socket of its base. 19 | * 20 | * @author Emil Ivov 21 | */ 22 | public class ServerReflexiveCandidate extends LocalCandidate { 23 | 24 | /** 25 | * The STUN candidate harvest. 26 | */ 27 | private final StunCandidateHarvest stunHarvest; 28 | 29 | /** 30 | * Creates a ServerReflexiveCandidate for the specified transport address, and base. 31 | * 32 | * @param address the {@link TransportAddress} that this Candidate is representing 33 | * @param base the {@link HostCandidate} that this server reflexive candidate was obtained through 34 | * @param stunSrvrAddr the {@link TransportAddress} of the stun server that reflected this candidate 35 | * @param extendedType The type of method used to discover this candidate ("host", "upnp", "stun peer reflexive", "stun server reflexive", "turn 36 | * relayed", "google turn relayed", "google tcp turn relayed" or "jingle node") 37 | */ 38 | public ServerReflexiveCandidate(TransportAddress address, HostCandidate base, TransportAddress stunSrvrAddr, CandidateExtendedType extendedType) { 39 | this(address, base, stunSrvrAddr, null, extendedType); 40 | } 41 | 42 | /** 43 | * Creates a ServerReflexiveCandidate for the specified transport address, and base. 44 | * 45 | * @param address the {@link TransportAddress} that this Candidate is representing 46 | * @param base the {@link HostCandidate} that this server reflexive candidate was obtained through 47 | * @param stunSrvrAddr the {@link TransportAddress} of the stun server that reflected this candidate 48 | * @param stunHarvest the {@link StunCandidateHarvest} 49 | * @param extendedType The type of method used to discover this candidate ("host", "upnp", "stun peer reflexive", "stun server reflexive", "turn 50 | * relayed", "google turn relayed", "google tcp turn relayed" or "jingle node") 51 | */ 52 | public ServerReflexiveCandidate(TransportAddress address, HostCandidate base, TransportAddress stunSrvrAddr, StunCandidateHarvest stunHarvest, CandidateExtendedType extendedType) { 53 | super(address, base.getParentComponent(), CandidateType.SERVER_REFLEXIVE_CANDIDATE, extendedType, base); 54 | setBase(base); 55 | setStunServerAddress(stunSrvrAddr); 56 | this.stunHarvest = stunHarvest; 57 | computePriority(); 58 | } 59 | 60 | /** {@inheritDoc} */ 61 | @Override 62 | public IceSocketWrapper getCandidateIceSocketWrapper() { 63 | return getBase().getCandidateIceSocketWrapper(); 64 | } 65 | 66 | /** 67 | * Frees resources allocated by this candidate such as itsDatagramSocket, for example. The socket of this 68 | * LocalCandidate is closed only if it is not the socket of the base of this LocalCandidate. 69 | */ 70 | @Override 71 | public void free() { 72 | super.free(); 73 | if (stunHarvest != null) { 74 | stunHarvest.close(); 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/main/java/org/ice4j/ice/TcpHostCandidate.java: -------------------------------------------------------------------------------- 1 | /* See LICENSE.md for license information */ 2 | package org.ice4j.ice; 3 | 4 | import java.net.SocketAddress; 5 | import java.util.LinkedList; 6 | import java.util.List; 7 | 8 | import org.ice4j.TransportAddress; 9 | import org.ice4j.ice.nio.IceTransport; 10 | import org.ice4j.socket.IceSocketWrapper; 11 | import org.ice4j.stack.StunStack; 12 | 13 | /** 14 | * Extends {@link org.ice4j.ice.HostCandidate} allowing the instance to have 15 | * a list of Sockets instead of just one socket. This is needed, 16 | * because with TCP, connections from different remote addresses result in 17 | * different Socket instances. 18 | * 19 | * @author Boris Grozev 20 | */ 21 | public class TcpHostCandidate extends HostCandidate { 22 | /** 23 | * List of accepted sockets for this TcpHostCandidate. 24 | */ 25 | private final List sockets = new LinkedList<>(); 26 | 27 | /** 28 | * Initializes a new TcpHostCandidate. 29 | * 30 | * @param transportAddress the transport address of this 31 | * TcpHostCandidate. 32 | * @param parentComponent the Component that this candidate 33 | * belongs to. 34 | */ 35 | public TcpHostCandidate(TransportAddress transportAddress, Component parentComponent) { 36 | super(transportAddress, parentComponent); 37 | } 38 | 39 | /** 40 | * {@inheritDoc} 41 | */ 42 | @Override 43 | protected IceSocketWrapper getCandidateIceSocketWrapper(SocketAddress remoteAddress) { 44 | for (IceSocketWrapper socket : sockets) { 45 | if (socket.getRemoteTransportAddress().equals(remoteAddress)) { 46 | return socket; 47 | } 48 | } 49 | return null; 50 | } 51 | 52 | public void addSocket(IceSocketWrapper socket) { 53 | sockets.add(socket); 54 | } 55 | 56 | @Override 57 | protected void free() { 58 | StunStack stunStack = getStunStack(); 59 | TransportAddress localAddr = getTransportAddress(); 60 | for (IceSocketWrapper socket : sockets) { 61 | // get the transport / acceptor id 62 | String id = (String) socket.getSession().getAttribute(IceTransport.Ice.UUID); 63 | // remove our sockets from the stack 64 | stunStack.removeSocket(id, localAddr, socket.getRemoteTransportAddress()); 65 | socket.close(); 66 | } 67 | super.free(); 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/org/ice4j/ice/harvest/AbstractCandidateHarvester.java: -------------------------------------------------------------------------------- 1 | /* See LICENSE.md for license information */ 2 | package org.ice4j.ice.harvest; 3 | 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | /** 8 | * An abstract partial implementation of {@link CandidateHarvester}. 9 | * 10 | * @author Emil Ivov 11 | * @author Lyubomir Marinov 12 | * @author Boris Grozev 13 | */ 14 | public abstract class AbstractCandidateHarvester implements CandidateHarvester { 15 | 16 | protected Logger logger = LoggerFactory.getLogger(AbstractCandidateHarvester.class); 17 | 18 | /** 19 | * Manages statistics about harvesting time. 20 | */ 21 | private HarvestStatistics harvestStatistics = new HarvestStatistics(); 22 | 23 | /** {@inheritDoc} */ 24 | @Override 25 | public HarvestStatistics getHarvestStatistics() { 26 | return harvestStatistics; 27 | } 28 | 29 | /** {@inheritDoc} */ 30 | @Override 31 | public boolean isHostHarvester() { 32 | return false; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/org/ice4j/ice/harvest/AddressRef.java: -------------------------------------------------------------------------------- 1 | package org.ice4j.ice.harvest; 2 | 3 | import java.net.Inet6Address; 4 | import java.net.InetAddress; 5 | 6 | /** 7 | * Model for InetAddress and whether or not its from a virtual interface. 8 | */ 9 | public class AddressRef { 10 | 11 | private InetAddress address; 12 | 13 | private boolean virtual; 14 | 15 | public AddressRef(InetAddress address, boolean virtual) { 16 | this.address = address; 17 | this.virtual = virtual; 18 | } 19 | 20 | public InetAddress getAddress() { 21 | return address; 22 | } 23 | 24 | public boolean isVirtual() { 25 | return virtual; 26 | } 27 | 28 | @Override 29 | public int hashCode() { 30 | final int prime = 31; 31 | int result = 1; 32 | result = prime * result + ((address instanceof Inet6Address) ? 64 : 0); 33 | result = prime * result + ((address == null) ? 0 : address.hashCode()); 34 | result = prime * result + (virtual ? 1231 : 1237); 35 | return result; 36 | } 37 | 38 | @Override 39 | public boolean equals(Object obj) { 40 | if (this == obj) 41 | return true; 42 | if (obj == null) 43 | return false; 44 | if (getClass() != obj.getClass()) 45 | return false; 46 | AddressRef other = (AddressRef) obj; 47 | if (address == null) { 48 | if (other.address != null) 49 | return false; 50 | } else if (!address.equals(other.address)) 51 | return false; 52 | if (virtual != other.virtual) 53 | return false; 54 | return true; 55 | } 56 | 57 | @Override 58 | public String toString() { 59 | return "AddressRef [address=" + address + ", virtual=" + virtual + "]"; 60 | } 61 | 62 | } -------------------------------------------------------------------------------- /src/main/java/org/ice4j/ice/harvest/CandidateHarvester.java: -------------------------------------------------------------------------------- 1 | /* See LICENSE.md for license information */ 2 | package org.ice4j.ice.harvest; 3 | 4 | import java.util.*; 5 | 6 | import org.ice4j.ice.*; 7 | 8 | /** 9 | * A CandidateHarvester gathers a certain kind of Candidates (e.g. host, reflexive, or relayed) for a specified {@link org.ice4j.ice.Component}. 10 | * 11 | * @author Emil Ivov 12 | * @author Lyubomir Marinov 13 | * @author Boris Grozev 14 | */ 15 | public interface CandidateHarvester { 16 | /** 17 | * Gathers all candidate addresses of the type that this CandidateHarvester supports. The gathered candidate addresses 18 | * are to be added by this CandidateHarvester to the specified Component using {@link Component#addLocalCandidate(LocalCandidate)} 19 | * as soon as they are discovered. 20 | * 21 | * @param component the {@link Component} that we'd like to gather candidate addresses for 22 | * @return the LocalCandidates gathered by this CandidateHarvester. Though they are to be added by this 23 | * CandidateHarvester to the specified component as soon as they are discovered, they should also be returned in order to make 24 | * sure that the gathering will be considered successful. 25 | */ 26 | Collection harvest(Component component); 27 | 28 | /** 29 | * Returns the statistics describing how well the various harvests of this harvester went. 30 | * 31 | * @return The {@link HarvestStatistics} describing this harvester's harvests 32 | */ 33 | HarvestStatistics getHarvestStatistics(); 34 | 35 | /** 36 | * Returns true if this CandidateHarvester is to be considered a harvester for host candidates. Such a harvester should 37 | * 1. Create local candidates of type HOST_CANDIDATE. 38 | * 2. Not depend on other local candidates, already harvested for the 39 | * component for which it is called. 40 | * 3. Not perform blocking operations while harvesting. 41 | * 42 | * @return true if this CandidateHarvester is a harvester for host candidates 43 | */ 44 | boolean isHostHarvester(); 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/org/ice4j/ice/harvest/CandidateHarvesterSetTask.java: -------------------------------------------------------------------------------- 1 | /* 2 | * ice4j, the OpenSource Java Solution for NAT and Firewall Traversal. Copyright @ 2015 Atlassian Pty Ltd Licensed under the Apache License, Version 2.0 (the "License"); you may 3 | * not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or 4 | * agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 5 | * License for the specific language governing permissions and limitations under the License. 6 | */ 7 | package org.ice4j.ice.harvest; 8 | 9 | import java.util.Collection; 10 | 11 | import org.ice4j.ice.Component; 12 | import org.slf4j.Logger; 13 | import org.slf4j.LoggerFactory; 14 | 15 | /** 16 | * Represents a task to be executed by the specified executorService and 17 | * to call {@link CandidateHarvester#harvest(Component)} on the specified 18 | * harvesters. 19 | * 20 | * @author Lyubomir Marinov 21 | * @author Emil Ivov 22 | */ 23 | class CandidateHarvesterSetTask implements Runnable { 24 | /** 25 | * The Logger used by the CandidateHarvesterSetTask 26 | * class and its instances for logging output. 27 | */ 28 | private static final Logger logger = LoggerFactory.getLogger(CandidateHarvesterSetTask.class); 29 | 30 | /** 31 | * The CandidateHarvester on which 32 | * {@link CandidateHarvester#harvest(org.ice4j.ice.Component)} is to be or 33 | * is being called. 34 | */ 35 | private CandidateHarvesterSetElement harvester; 36 | 37 | /** 38 | * The {@link Component}s whose addresses we will be harvesting in this 39 | * task. 40 | */ 41 | private Collection components; 42 | 43 | /** 44 | * The callback that we will be notifying every time a harvester completes. 45 | */ 46 | private final TrickleCallback trickleCallback; 47 | 48 | /** 49 | * Initializes a new CandidateHarvesterSetTask which is to 50 | * call {@link CandidateHarvester#harvest(org.ice4j.ice.Component)} on a 51 | * specific harvester and then as many harvesters as possible. 52 | * 53 | * @param harvester the CandidateHarvester on which the 54 | * new instance is to call 55 | * @param components the Component whose candidates we are currently 56 | * gathering. 57 | * CandidateHarvester#harvest(Component) first 58 | */ 59 | public CandidateHarvesterSetTask(CandidateHarvesterSetElement harvester, Collection components, TrickleCallback trickleCallback) { 60 | this.harvester = harvester; 61 | this.components = components; 62 | this.trickleCallback = trickleCallback; 63 | } 64 | 65 | /** 66 | * Gets the CandidateHarvester on which 67 | * {@link CandidateHarvester#harvest(org.ice4j.ice.Component)} is being 68 | * called. 69 | * 70 | * @return the CandidateHarvester on which 71 | * CandidateHarvester#harvest(Component) is being called 72 | */ 73 | public CandidateHarvesterSetElement getHarvester() { 74 | return harvester; 75 | } 76 | 77 | /** 78 | * Runs the actual harvesting for this component 79 | */ 80 | public void run() { 81 | if (harvester == null || !harvester.isEnabled()) { 82 | return; 83 | } 84 | for (Component component : components) { 85 | try { 86 | harvester.harvest(component, trickleCallback); 87 | } catch (Throwable t) { 88 | logger.warn("Disabling harvester due to exception: {}", t); 89 | harvester.setEnabled(false); 90 | if (t instanceof ThreadDeath) { 91 | throw (ThreadDeath) t; 92 | } 93 | } 94 | } 95 | 96 | /* 97 | * CandidateHarvester#harvest(Component) has been called on the harvester and its success or failure has been noted. Now forget the harvester because any failure to 98 | * continue execution is surely not its fault. 99 | */ 100 | harvester = null; 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/main/java/org/ice4j/ice/harvest/StunMappingCandidateHarvester.java: -------------------------------------------------------------------------------- 1 | /* See LICENSE.md for license information */ 2 | package org.ice4j.ice.harvest; 3 | 4 | import org.ice4j.TransportAddress; 5 | import org.ice4j.ice.nio.IceTransport; 6 | import org.ice4j.socket.IceSocketWrapper; 7 | import org.ice4j.stunclient.SimpleAddressDetector; 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | 11 | /** 12 | * A {@link MappingCandidateHarvester} which uses a STUN servers to discover its public IP address. 13 | * 14 | * @author Damian Minkov 15 | * @author Boris Grozev 16 | */ 17 | public class StunMappingCandidateHarvester extends MappingCandidateHarvester { 18 | 19 | private static final Logger logger = LoggerFactory.getLogger(StunMappingCandidateHarvester.class); 20 | 21 | /** 22 | * The list of servers we will use to discover our public address. 23 | */ 24 | private TransportAddress stunServerAddress; 25 | 26 | /** 27 | * Initializes a new {@link StunMappingCandidateHarvester} instance with a given local address and a STUN server address. Note that the actual 28 | * discovery of the public address needs to be initiated to a separate call to {@link #discover()}. 29 | * @param localAddress The local address. 30 | * @param stunServerAddress The address of the STUN server. 31 | */ 32 | public StunMappingCandidateHarvester(TransportAddress localAddress, TransportAddress stunServerAddress) { 33 | face = localAddress; 34 | this.stunServerAddress = stunServerAddress; 35 | } 36 | 37 | /** 38 | * Attempts to discover the the public address (mask) via the STUN server. 39 | * Note that this will block until we either receive a response from the STUN server, or a timeout occurs. 40 | */ 41 | public void discover() { 42 | try { 43 | SimpleAddressDetector sad = new SimpleAddressDetector(stunServerAddress); 44 | sad.start(); 45 | // check for existing binding before creating a new one 46 | IceSocketWrapper localSocket = IceTransport.getIceHandler().lookupBinding(face); 47 | // create a new socket since there isn't one registered for the local address 48 | if (localSocket == null) { 49 | localSocket = IceSocketWrapper.build(face, null); 50 | } 51 | mask = sad.getMappingFor(localSocket); 52 | if (mask != null) { 53 | logger.info("Discovered public address {} from STUN server {} using local address {}", mask, stunServerAddress, face); 54 | } 55 | } catch (Exception exc) { 56 | //whatever happens, we just log 57 | logger.info("We failed to obtain addresses for the following reason", exc); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/org/ice4j/ice/harvest/TrickleCallback.java: -------------------------------------------------------------------------------- 1 | /* 2 | * ice4j, the OpenSource Java Solution for NAT and Firewall Traversal. 3 | * 4 | * Copyright @ 2015 Atlassian Pty Ltd 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.ice4j.ice.harvest; 19 | 20 | import org.ice4j.ice.*; 21 | 22 | import java.util.*; 23 | 24 | /** 25 | * We use this callback to feed candidates to ice4j user applications that 26 | * support trickle ICE. The interface provides two methods that allow passing 27 | * candidates to applications either one-by-one or in batches. The former would 28 | * typically be used for harvesters such as STUN, where candidates are learned 29 | * one per message. Discovering batches of candidates is possible when querying 30 | * a TURN server, which in many cases would return both server reflexive (STUN) 31 | * and relayed (TURN) candidates. 32 | * 33 | * @author Emil Ivov 34 | */ 35 | public interface TrickleCallback 36 | { 37 | 38 | /** 39 | * Notifies the callback that a new batch of LocalCandidates has 40 | * been discovered and should be advertised to the remove party. 41 | * 42 | * @param iceCandidates the newly discovered list of candidates or, 43 | * similarly to WebRTC, null in case all candidate harvesting is 44 | * now completed. 45 | */ 46 | public void onIceCandidates(Collection iceCandidates); 47 | 48 | /** 49 | * Notifies the callback that harvesting has completed for a specific 50 | * stream. This may allow for optimizations in cases where all checks for 51 | * a specific stream have failed and no candidate has been found, so a 52 | * failure is due and we wouldn't won't to waist any more time. 53 | * 54 | * @param stream the {@link IceMediaStream}, for which we have just 55 | * completed harvesting. 56 | */ 57 | // we don't currently support this but we might do it one day. 58 | //public void streamCompleted(IceMediaStream stream); 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/org/ice4j/ice/nio/ExpirableAddressEntry.java: -------------------------------------------------------------------------------- 1 | package org.ice4j.ice.nio; 2 | 3 | import java.util.concurrent.Delayed; 4 | import java.util.concurrent.TimeUnit; 5 | 6 | /** 7 | * Immutable entry for expirable address bindings. 8 | * 9 | * @author Paul Gregoire 10 | * 11 | */ 12 | public class ExpirableAddressEntry implements Delayed { 13 | 14 | // use the acceptor timeout as our expiration time modifier (multiply by 1k because its in seconds) 15 | private static final long TIMEOUT = IceTransport.getAcceptorTimeout() * 1000L; 16 | 17 | private final String addressKey; 18 | 19 | private final long expirationTime; 20 | 21 | public ExpirableAddressEntry(String addressKey) { 22 | // represents an address binding 23 | this.addressKey = addressKey; 24 | // entries are allowed to exist for up-to 3 seconds 25 | this.expirationTime = System.currentTimeMillis() + TIMEOUT; 26 | } 27 | 28 | public boolean isExpired() { 29 | return expirationTime >= System.currentTimeMillis(); 30 | } 31 | 32 | public String getAddressKey() { 33 | return addressKey; 34 | } 35 | 36 | @Override 37 | public long getDelay(TimeUnit unit) { 38 | long diff = expirationTime - System.currentTimeMillis(); 39 | return unit.convert(diff, TimeUnit.MILLISECONDS); 40 | } 41 | 42 | @Override 43 | public int compareTo(Delayed o) { 44 | long otherExpirationTime = ((ExpirableAddressEntry) o).expirationTime; 45 | if (expirationTime != otherExpirationTime) { 46 | return (int) (expirationTime - otherExpirationTime); 47 | } 48 | return 0; 49 | } 50 | 51 | @Override 52 | public int hashCode() { 53 | final int prime = 31; 54 | int result = prime * addressKey.hashCode(); 55 | return result; 56 | } 57 | 58 | @Override 59 | public boolean equals(Object obj) { 60 | if (this == obj) { 61 | return true; 62 | } 63 | if (obj == null) { 64 | return false; 65 | } 66 | if (getClass() != obj.getClass()) { 67 | return false; 68 | } 69 | ExpirableAddressEntry other = (ExpirableAddressEntry) obj; 70 | if (addressKey == null) { 71 | if (other.addressKey != null) { 72 | return false; 73 | } 74 | } else if (!addressKey.equals(other.addressKey)) { 75 | return false; 76 | } 77 | return true; 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /src/main/java/org/ice4j/ice/nio/IceEncoder.java: -------------------------------------------------------------------------------- 1 | package org.ice4j.ice.nio; 2 | 3 | import org.apache.mina.core.buffer.IoBuffer; 4 | import org.apache.mina.core.session.IoSession; 5 | import org.apache.mina.filter.codec.ProtocolEncoderAdapter; 6 | import org.apache.mina.filter.codec.ProtocolEncoderOutput; 7 | import org.ice4j.Transport; 8 | import org.ice4j.stack.RawMessage; 9 | import org.slf4j.Logger; 10 | import org.slf4j.LoggerFactory; 11 | 12 | /** 13 | * This class handles the ice encoding. 14 | * 15 | * Refs 16 | * https://tools.ietf.org/html/rfc4571 17 | * https://tools.ietf.org/html/rfc6544#section-3 18 | * 19 | * @author Paul Gregoire 20 | */ 21 | public class IceEncoder extends ProtocolEncoderAdapter { 22 | 23 | private static final Logger logger = LoggerFactory.getLogger(IceEncoder.class); 24 | 25 | /* 26 | +----------+ 27 | | | 28 | | App | 29 | +----------+----------+ +----------+----------+ 30 | | | | | | | 31 | | STUN | (D)TLS | | STUN | App | 32 | +----------+----------+ +----------+----------+ 33 | | | | | 34 | | RFC 4571 | | RFC 4571 | 35 | +---------------------+ +---------------------+ 36 | | | | | 37 | | TCP | | TCP | 38 | +---------------------+ +---------------------+ 39 | | | | | 40 | | IP | | IP | 41 | +---------------------+ +---------------------+ 42 | 43 | Figure 1: ICE TCP Stack with and without (D)TLS 44 | */ 45 | 46 | @Override 47 | public void encode(IoSession session, Object message, ProtocolEncoderOutput out) throws Exception { 48 | logger.trace("encode (session: {}) local: {} remote: {}\n{}", session.getId(), session.getLocalAddress(), session.getRemoteAddress(), String.valueOf(message)); 49 | if (message instanceof RawMessage) { 50 | // determine the transport in-use 51 | Transport transport = (session.getTransportMetadata().isConnectionless() ? Transport.UDP : Transport.TCP); 52 | RawMessage packet = (RawMessage) message; 53 | IoBuffer buf = packet.toIoBuffer(); 54 | logger.trace("Byte buffer: {}", buf); 55 | if (transport == Transport.UDP) { 56 | session.write(buf, packet.getRemoteAddress()); 57 | } else { 58 | session.write(buf); 59 | } 60 | } else { 61 | throw new Exception("Message not RawMessage type"); 62 | } 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/org/ice4j/message/Indication.java: -------------------------------------------------------------------------------- 1 | /* See LICENSE.md for license information */ 2 | package org.ice4j.message; 3 | 4 | /** 5 | * An indication descendant of the message class. 6 | * 7 | * For example, indication messages is used by TURN protocol 8 | * to send and receive encapsulated data. 9 | * 10 | * @author Sebastien Vincent 11 | */ 12 | public class Indication extends Message { 13 | 14 | /** 15 | * Constructor. 16 | */ 17 | Indication() { 18 | } 19 | 20 | /** 21 | * Checks whether indicationType is a valid indication type and if yes sets it as the type of this instance. 22 | * 23 | * @param indicationType the type to set 24 | * @throws IllegalArgumentException if indicationType is not a valid indication type 25 | */ 26 | @Override 27 | public void setMessageType(char indicationType) throws IllegalArgumentException { 28 | // old TURN DATA indication type is an indication despite 0x0115 & 0x0110 indicates STUN error response type 29 | if (!isIndicationType(indicationType) && indicationType != OLD_DATA_INDICATION) { 30 | throw new IllegalArgumentException((int) (indicationType) + " - is not a valid indication type."); 31 | } 32 | super.setMessageType(indicationType); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/org/ice4j/message/Request.java: -------------------------------------------------------------------------------- 1 | /* See LICENSE.md for license information */ 2 | package org.ice4j.message; 3 | 4 | /** 5 | * A request descendant of the message class. The primary purpose of the Request class is to allow better functional definition of the classes in the 6 | * stack package. 7 | * 8 | * @author Emil Ivov 9 | */ 10 | public class Request extends Message { 11 | 12 | /** 13 | * Constructor. 14 | */ 15 | Request() { 16 | } 17 | 18 | /** 19 | * Checks whether requestType is a valid request type and if yes sets it as the type of the current instance. 20 | * @param requestType the type to set 21 | * @throws IllegalArgumentException if requestType is not a valid request type 22 | */ 23 | public void setMessageType(char requestType) throws IllegalArgumentException { 24 | if (!isRequestType(requestType)) { 25 | throw new IllegalArgumentException((int) (requestType) + " - is not a valid request type."); 26 | } 27 | super.setMessageType(requestType); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/org/ice4j/message/Response.java: -------------------------------------------------------------------------------- 1 | /* See LICENSE.md for license information */ 2 | package org.ice4j.message; 3 | 4 | /** 5 | * A response descendant of the message class. The primary purpose of the Response class is to allow better functional definition of the classes in the 6 | * stack package. 7 | * 8 | * @author Emil Ivov 9 | * @author Lubomir Marinov 10 | */ 11 | public class Response extends Message { 12 | 13 | /** 14 | * Constructor. 15 | */ 16 | Response() { 17 | } 18 | 19 | /** 20 | * Determines whether this instance represents a STUN error response. 21 | * 22 | * @return true if this instance represents a STUN error response; 23 | * otherwise, false 24 | */ 25 | public boolean isErrorResponse() { 26 | return isErrorResponseType(getMessageType()); 27 | } 28 | 29 | /** 30 | * Determines whether this instance represents a STUN success response. 31 | * 32 | * @return true if this instance represents a STUN success response; otherwise, false 33 | */ 34 | public boolean isSuccessResponse() { 35 | return isSuccessResponseType(getMessageType()); 36 | } 37 | 38 | /** 39 | * Checks whether responseType is a valid response type and if yes sets it as the type of the current instance. 40 | * @param responseType the type to set 41 | * @throws IllegalArgumentException if responseType is not a valid response type 42 | */ 43 | public void setMessageType(char responseType) throws IllegalArgumentException { 44 | if (!isResponseType(responseType)) { 45 | throw new IllegalArgumentException(Integer.toString(responseType) + " is not a valid response type."); 46 | } 47 | super.setMessageType(responseType); 48 | } 49 | 50 | @Override 51 | public String toString() { 52 | StringBuilder sb = new StringBuilder(); 53 | sb.append(getName()); 54 | sb.append("(0x"); 55 | sb.append(Integer.toHexString(getMessageType())); 56 | sb.append(")[attrib.count="); 57 | sb.append(getAttributeCount()); 58 | sb.append("]"); 59 | sb.append(" successful="); 60 | sb.append(isSuccessResponse()); 61 | return sb.toString(); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/org/ice4j/security/CredentialsAuthority.java: -------------------------------------------------------------------------------- 1 | /* 2 | * ice4j, the OpenSource Java Solution for NAT and Firewall Traversal. 3 | * 4 | * Copyright @ 2015 Atlassian Pty Ltd 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.ice4j.security; 19 | 20 | /** 21 | * The {@link CredentialsAuthority} interface is implemented by applications 22 | * in order to allow the stack to verify the integrity of incoming messages 23 | * containing the MessageIntegrityAttribute. 24 | * 25 | * @author Emil Ivov 26 | */ 27 | public interface CredentialsAuthority 28 | { 29 | /** 30 | * Returns the key (password) that corresponds to the specified local 31 | * username or user frag, an empty array if there was no password for that 32 | * username or null if the username is not a local user name 33 | * recognized by this CredentialsAuthority. 34 | * 35 | * @param username the local user name or user frag whose credentials we'd 36 | * like to obtain. 37 | * 38 | * @return the key (password) that corresponds to the specified local 39 | * username or user frag, an empty array if there was no password for that 40 | * username or null if the username is not a local user name 41 | * recognized by this CredentialsAuthority. 42 | */ 43 | public byte[] getLocalKey(String username); 44 | 45 | /** 46 | * Returns the key (password) that corresponds to the specified remote 47 | * username or user frag, an empty array if there was no password for that 48 | * username or null if the username is not a remote user name 49 | * recognized by this CredentialsAuthority. 50 | * 51 | * @param username the remote user name or user frag whose credentials we'd 52 | * like to obtain. 53 | * @param media the media name that we want to get remote key. 54 | * 55 | * @return the key (password) that corresponds to the specified remote 56 | * username or user frag, an empty array if there was no password for that 57 | * username or null if the username is not a remote user name 58 | * recognized by this CredentialsAuthority. 59 | */ 60 | public byte[] getRemoteKey(String username, String media); 61 | 62 | /** 63 | * Verifies whether username is currently known to this authority 64 | * and returns true if so. Returns false otherwise. 65 | * 66 | * @param username the user name whose validity we'd like to check. 67 | * 68 | * @return true if username is known to this 69 | * CredentialsAuthority and false otherwise. 70 | */ 71 | public boolean checkLocalUserName(String username); 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/org/ice4j/socket/SizeTrackedLinkedTransferQueue.java: -------------------------------------------------------------------------------- 1 | package org.ice4j.socket; 2 | 3 | import java.util.Collection; 4 | import java.util.concurrent.LinkedTransferQueue; 5 | import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; 6 | 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | 10 | /** 11 | * Extension of the LinkedTransferQueue so that removals may be tracked when performed by outside callers. 12 | * 13 | * @param 14 | */ 15 | public class SizeTrackedLinkedTransferQueue extends LinkedTransferQueue { 16 | 17 | private static final long serialVersionUID = -2455379209835774055L; 18 | 19 | private final static Logger logger = LoggerFactory.getLogger(SizeTrackedLinkedTransferQueue.class); 20 | 21 | private final static boolean isDebug = logger.isDebugEnabled(); 22 | 23 | @SuppressWarnings("rawtypes") 24 | private final static AtomicIntegerFieldUpdater AtomicQueueSizeUpdater = AtomicIntegerFieldUpdater.newUpdater(SizeTrackedLinkedTransferQueue.class, "queueSize"); 25 | 26 | private volatile int queueSize; 27 | 28 | @Override 29 | public boolean add(E message) { 30 | // while the queue type is unbounded, this will always return true 31 | boolean added = super.add(message); 32 | if (added) { 33 | int size = AtomicQueueSizeUpdater.addAndGet(this, 1); 34 | if (isDebug) { 35 | logger.debug("Message queued, current size: {}", size); 36 | } 37 | } 38 | return added; 39 | } 40 | 41 | @Override 42 | public boolean offer(E message) { 43 | // while the queue type is unbounded, this will always return true 44 | boolean added = super.offer(message); 45 | if (added) { 46 | int size = AtomicQueueSizeUpdater.addAndGet(this, 1); 47 | if (isDebug) { 48 | logger.debug("Message queued, current size: {}", size); 49 | } 50 | } 51 | return added; 52 | } 53 | 54 | @Override 55 | public E poll() { 56 | E message = super.poll(); 57 | if (message != null) { 58 | int size = AtomicQueueSizeUpdater.decrementAndGet(this); 59 | if (isDebug) { 60 | logger.debug("Message removed, current size: {}", size); 61 | } 62 | } 63 | return message; 64 | } 65 | 66 | @Override 67 | public E take() throws InterruptedException { 68 | E message = super.take(); 69 | if (message != null) { 70 | int size = AtomicQueueSizeUpdater.decrementAndGet(this); 71 | if (isDebug) { 72 | logger.debug("Message removed, current size: {}", size); 73 | } 74 | } 75 | return message; 76 | } 77 | 78 | @Override 79 | public int drainTo(Collection messages) { 80 | int removed = super.drainTo(messages); 81 | int size = AtomicQueueSizeUpdater.updateAndGet(this, s -> s - removed); 82 | if (isDebug) { 83 | logger.debug("Message drained by: {}, current size: {}", removed, size); 84 | } 85 | return removed; 86 | } 87 | 88 | @Override 89 | public void clear() { 90 | super.clear(); 91 | AtomicQueueSizeUpdater.set(this, 0); 92 | } 93 | 94 | @Override 95 | public boolean isEmpty() { 96 | return queueSize == 0; 97 | } 98 | 99 | @Override 100 | public int size() { 101 | return queueSize; 102 | } 103 | 104 | } -------------------------------------------------------------------------------- /src/main/java/org/ice4j/socket/SocketClosedException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * ice4j, the OpenSource Java Solution for NAT and Firewall Traversal. Copyright @ 2015-2016 Atlassian Pty Ltd Licensed under the Apache License, Version 2.0 (the "License"); you 3 | * may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law 4 | * or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See 5 | * the License for the specific language governing permissions and limitations under the License. 6 | */ 7 | package org.ice4j.socket; 8 | 9 | import java.net.*; 10 | 11 | /** 12 | * An exception that indicates that a socket is closed. 13 | */ 14 | public class SocketClosedException extends SocketException { 15 | private static final long serialVersionUID = -2571217415633483512L; 16 | 17 | /** 18 | * Initializes a new {@link SocketClosedException}. 19 | */ 20 | public SocketClosedException() { 21 | // Keep the same message as the one used by jdk, since existing code 22 | // might be matching against the string. 23 | super("Socket closed"); 24 | } 25 | 26 | /** 27 | * Initializes a new {@link SocketClosedException}. 28 | * 29 | * @param message 30 | */ 31 | public SocketClosedException(String message) { 32 | super(message); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/org/ice4j/socket/filter/DataFilter.java: -------------------------------------------------------------------------------- 1 | package org.ice4j.socket.filter; 2 | 3 | /** 4 | * Represents a filter which accepts or rejects data in a byte array. 5 | * 6 | * @author Paul Gregoire 7 | */ 8 | public interface DataFilter { 9 | 10 | /** 11 | * Determines whether data is accepted by this filter. 12 | * 13 | * @param buf the bytes which are checked for acceptance by this filter 14 | * @return true if this filter accepts the specified data and false otherwise 15 | */ 16 | public boolean accept(byte[] buf); 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/org/ice4j/stack/Connector.java: -------------------------------------------------------------------------------- 1 | /* See LICENSE.md for license information */ 2 | package org.ice4j.stack; 3 | 4 | import java.io.IOException; 5 | import java.util.concurrent.atomic.AtomicBoolean; 6 | 7 | import org.apache.mina.core.buffer.IoBuffer; 8 | import org.ice4j.TransportAddress; 9 | import org.ice4j.socket.IceSocketWrapper; 10 | 11 | /** 12 | * The Network Access Point is the most outward part of the stack. It is constructed around socket and sends datagrams 13 | * to the STUN server specified by the original NetAccessPointDescriptor. 14 | * 15 | * @author Emil Ivov 16 | */ 17 | class Connector implements Comparable { 18 | 19 | /** 20 | * The socket object that used by this access point to access the network. 21 | */ 22 | private final IceSocketWrapper sock; 23 | 24 | /** 25 | * The address that we are listening to. 26 | */ 27 | private final TransportAddress listenAddress; 28 | 29 | /** 30 | * The remote address of the socket of this Connector if it is a TCP socket, or null if it is UDP. 31 | */ 32 | private TransportAddress remoteAddress; 33 | 34 | /** 35 | * Whether or not the connector is alive (not yet stopped) 36 | */ 37 | private final AtomicBoolean alive = new AtomicBoolean(true); 38 | 39 | /** 40 | * Creates a network access point. 41 | * 42 | * @param socket the socket that this access point is supposed to use for communication 43 | * @param remoteAddress the remote address of the socket of this {@link Connector} if it is a TCP socket, or null if it is UDP 44 | */ 45 | protected Connector(IceSocketWrapper socket, TransportAddress remoteAddress) { 46 | this.sock = socket; 47 | this.remoteAddress = remoteAddress; 48 | listenAddress = socket.getTransportAddress(); 49 | } 50 | 51 | /** 52 | * Returns the DatagramSocket that contains the port and address associated with this access point. 53 | * 54 | * @return the DatagramSocket associated with this AP. 55 | */ 56 | protected IceSocketWrapper getSocket() { 57 | return sock; 58 | } 59 | 60 | /** 61 | * Returns alive status. 62 | * 63 | * @return true if alive and false if stopped 64 | */ 65 | public boolean isAlive() { 66 | return alive.get(); 67 | } 68 | 69 | /** 70 | * Makes the access point stop listening on its socket. 71 | */ 72 | protected void stop() { 73 | if (alive.compareAndSet(true, false)) { 74 | // stun stack also calls socket close as part of the process 75 | sock.close(); 76 | } 77 | } 78 | 79 | /** 80 | * Sends message through this access point's socket. 81 | * 82 | * @param message the bytes to send 83 | * @param address message destination 84 | * @throws IOException if an exception occurs while sending the message 85 | */ 86 | void sendMessage(byte[] message, TransportAddress address) throws IOException { 87 | // update stun/turn message/byte counters 88 | sock.updateSTUNWriteCounters((message != null ? message.length : 0)); 89 | // send the message 90 | sock.send(IoBuffer.wrap(message), address); 91 | } 92 | 93 | /** 94 | * Returns the TransportAddress that this access point is bound on. 95 | * 96 | * @return the TransportAddress associated with this AP. 97 | */ 98 | TransportAddress getListenAddress() { 99 | return listenAddress; 100 | } 101 | 102 | /** 103 | * Allow setting remote address for TCP sockets. 104 | * 105 | * @param remoteAddress 106 | */ 107 | void setRemoteAddress(TransportAddress remoteAddress) { 108 | this.remoteAddress = remoteAddress; 109 | } 110 | 111 | /** 112 | * Returns the remote TransportAddress or null if none is specified. 113 | * 114 | * @return the remote TransportAddress or null if none is specified. 115 | */ 116 | TransportAddress getRemoteAddress() { 117 | return remoteAddress; 118 | } 119 | 120 | @Override 121 | public int compareTo(Connector that) { 122 | return sock.compareTo(that.sock); 123 | } 124 | 125 | /** 126 | * Returns a String representation of the object. 127 | * 128 | * @return String 129 | */ 130 | @Override 131 | public String toString() { 132 | return "ice4j.Connector@" + listenAddress; 133 | } 134 | 135 | } 136 | -------------------------------------------------------------------------------- /src/main/java/org/ice4j/stack/MessageEventHandler.java: -------------------------------------------------------------------------------- 1 | /* See LICENSE.md for license information */ 2 | package org.ice4j.stack; 3 | 4 | import org.ice4j.*; 5 | 6 | /** 7 | * The class is used for collecting incoming STUN messages. This is our way of keeping scalable network and stun layers. 8 | * 9 | * @author Emil Ivov 10 | */ 11 | public interface MessageEventHandler { 12 | 13 | /** 14 | * Called when an incoming message has been received, parsed and is ready for delivery. 15 | * 16 | * @param evt the Event object that encapsulates the newly received message 17 | */ 18 | public void handleMessageEvent(StunMessageEvent evt); 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/org/ice4j/stack/PacketLogger.java: -------------------------------------------------------------------------------- 1 | /* 2 | * ice4j, the OpenSource Java Solution for NAT and Firewall Traversal. 3 | * 4 | * Copyright @ 2015 Atlassian Pty Ltd 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.ice4j.stack; 19 | 20 | /** 21 | * The interface which interested implementers will use in order 22 | * to track and log packets send and received by this stack. 23 | * 24 | * @author Damian Minkov 25 | */ 26 | public interface PacketLogger 27 | { 28 | /** 29 | * Logs a incoming or outgoing packet. 30 | * 31 | * @param sourceAddress the source address of the packet. 32 | * @param sourcePort the source port. 33 | * @param destinationAddress the destination address of the packet. 34 | * @param destinationPort the destination port. 35 | * @param packetContent the content of the packet. 36 | * @param sender whether or not we are sending the packet. 37 | */ 38 | public void logPacket( 39 | byte[] sourceAddress, 40 | int sourcePort, 41 | byte[] destinationAddress, 42 | int destinationPort, 43 | byte[] packetContent, 44 | boolean sender); 45 | 46 | /** 47 | * Checks whether the logger is enabled. 48 | * @return true if the logger is enabled, false 49 | * otherwise. 50 | */ 51 | public boolean isEnabled(); 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/org/ice4j/stack/RequestListener.java: -------------------------------------------------------------------------------- 1 | /* See LICENSE.md for license information */ 2 | package org.ice4j.stack; 3 | 4 | import org.ice4j.*; 5 | import org.ice4j.message.*; 6 | 7 | /** 8 | * Handles incoming requests. 9 | * 10 | * @author Emil Ivov 11 | */ 12 | public interface RequestListener { 13 | /** 14 | * Called when delivering incoming STUN requests. Throwing an {@link IllegalArgumentException} from within this method would cause the 15 | * stack to reply with a 400 Bad Request {@link Response} using the exception's message as a reason phrase for the error response. Any 16 | * other exception would result in a 500 Server Error {@link Response}. 17 | * 18 | * @param evt the event containing the incoming STUN request. 19 | * 20 | * @throws IllegalArgumentException if evt contains a malformed {@link Request} and the stack would need to response with a 21 | * 400 Bad Request {@link Response}. 22 | */ 23 | public void processRequest(StunMessageEvent evt) throws IllegalArgumentException; 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/org/ice4j/stunclient/StunDiscoveryReport.java: -------------------------------------------------------------------------------- 1 | /* 2 | * ice4j, the OpenSource Java Solution for NAT and Firewall Traversal. Copyright @ 2015 Atlassian Pty Ltd Licensed under the Apache License, Version 2.0 (the "License"); you may 3 | * not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or 4 | * agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 5 | * License for the specific language governing permissions and limitations under the License. 6 | */ 7 | package org.ice4j.stunclient; 8 | 9 | import org.ice4j.*; 10 | 11 | /** 12 | * The class is used to deliver results from a STUN Discovery Process. It contains information about the NAT Server (or firewall) this client is behind, 13 | * and a mapped address value (if discovered) 14 | * 15 | * @author Emil Ivov 16 | */ 17 | 18 | public class StunDiscoveryReport { 19 | /** 20 | * Indicates that NAT detection has failed or not yet initiated. 21 | */ 22 | public static final String UNKNOWN = "Unknown Network Configuration"; 23 | 24 | /** 25 | * Means, there's no NAT or firewall. 26 | */ 27 | public static final String OPEN_INTERNET = "Open Internet Configuration"; 28 | 29 | /** 30 | * Indicates that UDP communication is not possible. 31 | */ 32 | public static final String UDP_BLOCKING_FIREWALL = "UDP Blocking Firewall"; 33 | 34 | /** 35 | * Means we are behind a symmetric udp firewall. 36 | */ 37 | public static final String SYMMETRIC_UDP_FIREWALL = "Symmetric UDP Firewall"; 38 | 39 | /** 40 | * NAT type is full cone. 41 | */ 42 | public static final String FULL_CONE_NAT = "Full Cone NAT"; 43 | 44 | /** 45 | * We are behind a symmetric nat. 46 | */ 47 | public static final String SYMMETRIC_NAT = "Symmetric NAT"; 48 | 49 | /** 50 | * NAT type is Restricted Cone. 51 | */ 52 | public static final String RESTRICTED_CONE_NAT = "Restricted Cone NAT"; 53 | 54 | /** 55 | * NAT type is port restricted cone. 56 | */ 57 | public static final String PORT_RESTRICTED_CONE_NAT = "Port Restricted Cone NAT"; 58 | 59 | private String natType = UNKNOWN; 60 | 61 | private TransportAddress publicAddress; 62 | 63 | /** 64 | * Creates a discovery report with natType = UNKNOWN and a null public 65 | * address. 66 | */ 67 | StunDiscoveryReport() { 68 | } 69 | 70 | /** 71 | * Returns the type of the NAT described in the report. 72 | * @return the type of the NAT that this report is about. 73 | */ 74 | public String getNatType() { 75 | return natType; 76 | } 77 | 78 | /** 79 | * Sets the type of the NAT indicated by the report. 80 | * @param natType the type of the NAT. 81 | */ 82 | void setNatType(String natType) { 83 | this.natType = natType; 84 | } 85 | 86 | /** 87 | * Returns the public addressed discovered by a discovery process. 88 | * @return an internet address for public use. 89 | */ 90 | public TransportAddress getPublicAddress() { 91 | return publicAddress; 92 | } 93 | 94 | /** 95 | * Sets a public address. 96 | * @param stunAddress An address that's accessible from everywhere. 97 | */ 98 | void setPublicAddress(TransportAddress stunAddress) { 99 | this.publicAddress = stunAddress; 100 | } 101 | 102 | /** 103 | * Compares this object with obj. Two reports are considered equal if and 104 | * only if both have the same nat type and their public addresses are 105 | * equal or are both null. 106 | * @param obj the object to compare against. 107 | * @return true if the two objects are equal and false otherwise. 108 | */ 109 | public boolean equals(Object obj) { 110 | if (!(obj instanceof StunDiscoveryReport)) 111 | return false; 112 | 113 | if (obj == this) 114 | return true; 115 | 116 | StunDiscoveryReport target = (StunDiscoveryReport) obj; 117 | 118 | return (target.getNatType() == getNatType() && (getPublicAddress() == null && target.getPublicAddress() == null || target.getPublicAddress().equals(getPublicAddress()))); 119 | } 120 | 121 | /** 122 | * Returns a readable representation of the report. 123 | * @return a readable representation of the report. 124 | */ 125 | public String toString() { 126 | return "The detected network configuration is: " + getNatType() + "\n" + "Your mapped public address is: " + getPublicAddress(); 127 | } 128 | 129 | } 130 | -------------------------------------------------------------------------------- /src/main/java/org/ice4j/util/DatagramUtil.java: -------------------------------------------------------------------------------- 1 | package org.ice4j.util; 2 | 3 | import java.net.DatagramPacket; 4 | import java.net.InetAddress; 5 | 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | public class DatagramUtil { 10 | 11 | private static final Logger logger = LoggerFactory.getLogger(DatagramUtil.class); 12 | 13 | /** 14 | * Initializes a new DatagramPacket instance which is a clone of a specific DatagramPacket i.e. the properties of the clone 15 | * DatagramPacket are clones of the specified DatagramPacket. 16 | * 17 | * @param p the DatagramPacket to clone 18 | * @param arraycopy true if the actual bytes of the data of p are to be copied into the clone or false if only the 19 | * capacity of the data of p is to be cloned without copying the actual bytes of the data of p 20 | * @return a new DatagramPacket instance which is a clone of the specified DatagramPacket 21 | */ 22 | public static DatagramPacket clone(DatagramPacket p, boolean arraycopy) { 23 | byte[] data; 24 | int off; 25 | int len; 26 | InetAddress address; 27 | int port; 28 | 29 | synchronized (p) { 30 | data = p.getData(); 31 | off = p.getOffset(); 32 | len = p.getLength(); 33 | 34 | // Clone the data. 35 | { 36 | // The capacity of the specified p is preserved. 37 | byte[] dataClone = new byte[data.length]; 38 | 39 | // However, only copy the range of data starting with off and 40 | // spanning len number of bytes. Of course, preserve off and len 41 | // in addition to the capacity. 42 | if (arraycopy && (len > 0)) { 43 | int arraycopyOff, arraycopyLen; 44 | 45 | // If off and/or len are going to cause an exception though, 46 | // copy the whole data. 47 | if ((off >= 0) && (off < data.length) && (off + len <= data.length)) { 48 | arraycopyOff = off; 49 | arraycopyLen = len; 50 | } else { 51 | arraycopyOff = 0; 52 | arraycopyLen = data.length; 53 | } 54 | System.arraycopy(data, arraycopyOff, dataClone, arraycopyOff, arraycopyLen); 55 | } 56 | data = dataClone; 57 | } 58 | 59 | address = p.getAddress(); 60 | port = p.getPort(); 61 | } 62 | 63 | DatagramPacket c = new DatagramPacket(data, off, len); 64 | 65 | if (address != null) 66 | c.setAddress(address); 67 | if (port >= 0) 68 | c.setPort(port); 69 | 70 | return c; 71 | } 72 | 73 | /** 74 | * Copies the properties of a specific DatagramPacket to another DatagramPacket. The property values are not cloned. 75 | * 76 | * @param src the DatagramPacket which is to have its properties copied to dest 77 | * @param dest the DatagramPacket which is to have its properties set to the value of the respective properties of src 78 | */ 79 | public static void copy(DatagramPacket src, DatagramPacket dest) { 80 | synchronized (dest) { 81 | dest.setAddress(src.getAddress()); 82 | dest.setPort(src.getPort()); 83 | 84 | byte[] srcData = src.getData(); 85 | 86 | if (srcData == null) { 87 | dest.setLength(0); 88 | } else { 89 | byte[] destData = dest.getData(); 90 | 91 | if (destData == null) { 92 | dest.setLength(0); 93 | } else { 94 | int destOffset = dest.getOffset(); 95 | int destLength = destData.length - destOffset; 96 | int srcLength = src.getLength(); 97 | 98 | if (destLength >= srcLength) { 99 | destLength = srcLength; 100 | } else if (logger.isWarnEnabled()) { 101 | logger.warn("Truncating received DatagramPacket data!"); 102 | } 103 | System.arraycopy(srcData, src.getOffset(), destData, destOffset, destLength); 104 | dest.setLength(destLength); 105 | } 106 | } 107 | } 108 | } 109 | 110 | } 111 | -------------------------------------------------------------------------------- /src/main/java/org/ice4j/util/QueueStatistics.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright @ 2015 Atlassian Pty Ltd 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.ice4j.util; 17 | 18 | import java.util.logging.*; 19 | import java.util.logging.Logger; // Disambiguation. 20 | 21 | public class QueueStatistics 22 | { 23 | /** 24 | * The scale to use for {@link RateStatistics}. This makes their output in 25 | * units (e.g. packets) per second. 26 | */ 27 | private static final int SCALE = 1000; 28 | 29 | /** 30 | * The interval (in number of calls to {@link #add(long)} or 31 | * {@link #remove(long)}) at which the gathered statistics will be printed. 32 | */ 33 | private static final int DEFAULT_PRINT_INTERVAL = 500; 34 | 35 | /** 36 | * Calculate the average rate of addition of packets in a 200ms window. 37 | */ 38 | private final RateStatistics addRateStatistics = new RateStatistics(200, SCALE); 39 | 40 | /** 41 | * Calculate the average rate of removal of packets in a 200ms window. 42 | */ 43 | private final RateStatistics removeRateStatistics = new RateStatistics(200, SCALE); 44 | 45 | /** 46 | * The {@link Logger} instance used for logging output. 47 | */ 48 | private final Logger logger; 49 | 50 | private int head = 0; 51 | private int size = 0; 52 | private int[] sizes = new int[DEFAULT_PRINT_INTERVAL]; 53 | private long[] timestamps = new long[DEFAULT_PRINT_INTERVAL]; 54 | private long[] addRates = new long[DEFAULT_PRINT_INTERVAL]; 55 | private long[] removeRates = new long[DEFAULT_PRINT_INTERVAL]; 56 | private int[] totalPacketsAddedHistory = new int[DEFAULT_PRINT_INTERVAL]; 57 | private int totalPacketsAdded = 0; 58 | private String logHeader; 59 | 60 | /** 61 | * Initializes a new {@link QueueStatistics} instance. 62 | * 63 | * @param id Identifier to distinguish the log output of multiple 64 | * {@link QueueStatistics} instances. 65 | */ 66 | public QueueStatistics(String id) 67 | { 68 | logger = Logger.getLogger("QueueStatistics-" + id); 69 | logHeader = "QueueStatistics-" + id + ": "; 70 | 71 | // We let the users of this class decide whether to enable logging (by 72 | // creating a QueueStatistic instance) or not. 73 | logger.setLevel(Level.ALL); 74 | } 75 | 76 | /** 77 | * Registers the addition of a packet to the corresponding queue. 78 | * @param now the time (in milliseconds since the epoch) at which the 79 | * packet was added. 80 | */ 81 | public synchronized void add(long now) 82 | { 83 | addRateStatistics.update(1, now); 84 | size++; 85 | totalPacketsAdded++; 86 | update(now); 87 | } 88 | 89 | /** 90 | * Registers the removal of a packet from the corresponding queue. 91 | * @param now the time (in milliseconds since the epoch) at which the 92 | * packet was removed. 93 | */ 94 | public synchronized void remove(long now) 95 | { 96 | removeRateStatistics.update(1, now); 97 | size--; 98 | update(now); 99 | } 100 | 101 | private synchronized void update(long now) 102 | { 103 | if (head == sizes.length) 104 | { 105 | print(); 106 | head = 0; 107 | } 108 | 109 | sizes[head] = size; 110 | timestamps[head] = now; 111 | addRates[head] = addRateStatistics.getRate(now); 112 | removeRates[head] = removeRateStatistics.getRate(now); 113 | totalPacketsAddedHistory[head] = totalPacketsAdded; 114 | head++; 115 | } 116 | 117 | private void print() 118 | { 119 | StringBuilder s = new StringBuilder(); 120 | for (int i =0; i= buckets.length) 91 | { 92 | oldestIndex = 0; 93 | } 94 | ++oldestTime; 95 | if (accumulatedCount == 0L) 96 | { 97 | // This guarantees we go through all the buckets at most once, 98 | // even if newOldestTime is far greater than oldestTime. 99 | break; 100 | } 101 | } 102 | oldestTime = newOldestTime; 103 | } 104 | 105 | public long getRate() 106 | { 107 | return getRate(System.currentTimeMillis()); 108 | } 109 | 110 | public long getRate(long nowMs) 111 | { 112 | eraseOld(nowMs); 113 | return (long) (accumulatedCount * scale + 0.5F); 114 | } 115 | 116 | public long getAccumulatedCount() 117 | { 118 | return getAccumulatedCount(System.currentTimeMillis()); 119 | } 120 | 121 | public long getAccumulatedCount(long nowMs) 122 | { 123 | eraseOld(nowMs); 124 | return accumulatedCount; 125 | } 126 | 127 | 128 | public void update(int count, long nowMs) 129 | { 130 | if (nowMs < oldestTime) // Too old data is ignored. 131 | return; 132 | 133 | synchronized (this) 134 | { 135 | eraseOld(nowMs); 136 | 137 | int nowOffset = (int) (nowMs - oldestTime); 138 | int index = oldestIndex + nowOffset; 139 | 140 | if (index >= buckets.length) 141 | index -= buckets.length; 142 | buckets[index] += count; 143 | accumulatedCount += count; 144 | } 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /src/main/java/org/ice4j/util/Utils.java: -------------------------------------------------------------------------------- 1 | package org.ice4j.util; 2 | 3 | public class Utils { 4 | 5 | private static final char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray(); 6 | 7 | /** 8 | * Returns a byte array for the given hex encoded string. 9 | * 10 | * @param hexString encoded hex string 11 | * @return byte array 12 | */ 13 | public final static byte[] fromHexString(String hexString) { 14 | // remove all the whitespace first 15 | hexString = hexString.replaceAll("\\s+", ""); 16 | int len = hexString.length(); 17 | byte[] data = new byte[len / 2]; 18 | for (int i = 0; i < len; i += 2) { 19 | data[i / 2] = (byte) ((Character.digit(hexString.charAt(i), 16) << 4) + Character.digit(hexString.charAt(i + 1), 16)); 20 | } 21 | return data; 22 | } 23 | 24 | /** 25 | * Returns a hex string for a given byte array. 26 | * 27 | * @param bytes 28 | * @return hex string 29 | */ 30 | public final static String toHexString(byte[] bytes) { 31 | if (bytes == null || bytes.length == 0) { 32 | throw new IllegalArgumentException("bytes empty or null"); 33 | } 34 | StringBuilder output = new StringBuilder(bytes.length * 2); 35 | for (byte b : bytes) { 36 | int b0 = b & 0xFF; 37 | int b1 = b0 >> 4; 38 | int b2 = b0 & 0x0F; 39 | output.append(HEX_ARRAY[b1]).append(HEX_ARRAY[b2]); 40 | } 41 | return output.toString(); 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/test/java/org/ice4j/StunTestSuite.java: -------------------------------------------------------------------------------- 1 | /* 2 | * ice4j, the OpenSource Java Solution for NAT and Firewall Traversal. Copyright @ 2015 Atlassian Pty Ltd Licensed under the Apache License, Version 2.0 (the "License"); you may 3 | * not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or 4 | * agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 5 | * License for the specific language governing permissions and limitations under the License. 6 | */ 7 | package org.ice4j; 8 | 9 | import junit.framework.Test; 10 | import junit.framework.TestCase; 11 | import junit.framework.TestSuite; 12 | 13 | /** 14 | * Contains all tests in the ice4j project. 15 | * 16 | * @author Emil Ivov 17 | */ 18 | public class StunTestSuite extends TestCase { 19 | 20 | /** 21 | * Creates a new instance of the suite 22 | * 23 | * @param s test name 24 | */ 25 | public StunTestSuite(String s) { 26 | super(s); 27 | } 28 | 29 | /** 30 | * Returns the suite of tests to run. 31 | * @return the suite of tests to run. 32 | */ 33 | public static Test suite() { 34 | TestSuite suite = new TestSuite(); 35 | // attributes 36 | suite.addTestSuite(org.ice4j.attribute.AddressAttributeTest.class); 37 | suite.addTestSuite(org.ice4j.attribute.XorOnlyTest.class); 38 | suite.addTestSuite(org.ice4j.attribute.AttributeDecoderTest.class); 39 | suite.addTestSuite(org.ice4j.attribute.ChangeRequestAttributeTest.class); 40 | suite.addTestSuite(org.ice4j.attribute.ErrorCodeAttributeTest.class); 41 | suite.addTestSuite(org.ice4j.attribute.UnknownAttributesAttributeTest.class); 42 | suite.addTestSuite(org.ice4j.attribute.SoftwareAttributeTest.class); 43 | suite.addTestSuite(org.ice4j.attribute.OptionalAttributeAttributeTest.class); 44 | suite.addTestSuite(org.ice4j.attribute.ConnectionIdAttributeTest.class); 45 | suite.addTestSuite(org.ice4j.attribute.RequestedAddressFamilyAttributeTest.class); 46 | suite.addTestSuite(org.ice4j.attribute.UsernameAttributeTest.class); 47 | suite.addTestSuite(org.ice4j.attribute.NonceAttributeTest.class); 48 | suite.addTestSuite(org.ice4j.attribute.RealmAttributeTest.class); 49 | // messages 50 | suite.addTestSuite(org.ice4j.message.MessageFactoryTest.class); 51 | suite.addTestSuite(org.ice4j.message.MessageTest.class); 52 | // stack 53 | suite.addTestSuite(org.ice4j.stack.ShallowStackTest.class); 54 | // event dispatching 55 | suite.addTestSuite(org.ice4j.MessageEventDispatchingTest.class); 56 | // transactions 57 | suite.addTestSuite(org.ice4j.TransactionSupportTests.class); 58 | // client 59 | //suite.addTestSuite(org.ice4j.stunclient.StunAddressDiscovererTest.class); 60 | //suite.addTestSuite(org.ice4j.stunclient.StunAddressDiscovererTest_v6.class); 61 | //suite.addTestSuite(org.ice4j.stunclient.StunAddressDiscovererTest_v4v6.class); 62 | return suite; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/test/java/org/ice4j/attribute/NonceAttributeTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * ice4j, the OpenSource Java Solution for NAT and Firewall Traversal. 3 | * 4 | * Copyright @ 2015 Atlassian Pty Ltd 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.ice4j.attribute; 19 | 20 | import junit.framework.*; 21 | 22 | import java.util.*; 23 | 24 | import org.ice4j.*; 25 | 26 | /** 27 | * Tests the nonce attribute class. 28 | * 29 | * @author Emil Ivov 30 | * @author Sebastien Vincent 31 | */ 32 | public class NonceAttributeTest extends TestCase 33 | { 34 | private NonceAttribute nonceAttribute = new NonceAttribute(); 35 | MsgFixture msgFixture = null; 36 | String nonceValue = "0123456789abcdef"; 37 | byte[] attributeBinValue = new byte[]{ 38 | (byte)(nonceAttribute.getAttributeType().type>>8), 39 | (byte)(nonceAttribute.getAttributeType().type & 0x00FF), 40 | 0, (byte)nonceValue.length(), 41 | '0', '1', '2', '3', '4', '5', '6','7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; 42 | 43 | protected void setUp() throws Exception 44 | { 45 | super.setUp(); 46 | msgFixture = new MsgFixture(); 47 | 48 | nonceAttribute = new NonceAttribute(); 49 | nonceAttribute.setNonce(nonceValue.getBytes()); 50 | } 51 | 52 | protected void tearDown() throws Exception 53 | { 54 | nonceAttribute = null; 55 | msgFixture = null; 56 | super.tearDown(); 57 | } 58 | 59 | /** 60 | * Tests decoding of the nonce attribute. 61 | * @throws StunException upon a failure 62 | */ 63 | public void testDecodeAttributeBody() throws StunException 64 | { 65 | char offset = 0; 66 | NonceAttribute decoded = new NonceAttribute(); 67 | char length = (char)nonceValue.length(); 68 | decoded.decodeAttributeBody(nonceValue.getBytes(), offset, length); 69 | 70 | //nonce value 71 | assertEquals( "decode failed", nonceAttribute, decoded); 72 | } 73 | 74 | /** 75 | * Tests the encode method 76 | */ 77 | public void testEncode() 78 | { 79 | assertTrue("encode failed", 80 | Arrays.equals(nonceAttribute.encode(), 81 | attributeBinValue)); 82 | } 83 | 84 | /** 85 | * Test Equals 86 | */ 87 | public void testEquals() 88 | { 89 | NonceAttribute nonceAttribute2 = new NonceAttribute(); 90 | nonceAttribute2.setNonce(nonceValue.getBytes()); 91 | 92 | //test positive equals 93 | assertEquals("testequals failed", nonceAttribute, nonceAttribute2); 94 | 95 | //test negative equals 96 | nonceAttribute2 = new NonceAttribute(); 97 | nonceAttribute2.setNonce("some other nonce".getBytes()); 98 | 99 | //test positive equals 100 | assertFalse("testequals failed", 101 | nonceAttribute.equals(nonceAttribute2)); 102 | 103 | //test null equals 104 | assertFalse("testequals failed", 105 | nonceAttribute.equals(null)); 106 | } 107 | 108 | /** 109 | * Tests extracting data length 110 | */ 111 | public void testGetDataLength() 112 | { 113 | int expectedReturn = (char)nonceValue.length(); 114 | int actualReturn = nonceAttribute.getDataLength(); 115 | assertEquals("getDataLength - failed", expectedReturn, actualReturn); 116 | } 117 | 118 | /** 119 | * Tests getting the name 120 | */ 121 | public void testGetName() 122 | { 123 | String expectedReturn = "NONCE"; 124 | String actualReturn = nonceAttribute.getName(); 125 | assertEquals("getting name failed", expectedReturn, actualReturn); 126 | } 127 | 128 | public void testSetGetNonce() 129 | { 130 | byte[] expectedReturn = nonceValue.getBytes(); 131 | 132 | NonceAttribute att = new NonceAttribute(); 133 | att.setNonce(expectedReturn); 134 | 135 | byte[] actualReturn = att.getNonce(); 136 | assertTrue("nonce setter or getter failed", 137 | Arrays.equals( expectedReturn, 138 | actualReturn)); 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /src/test/java/org/ice4j/attribute/RealmAttributeTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * ice4j, the OpenSource Java Solution for NAT and Firewall Traversal. 3 | * 4 | * Copyright @ 2015 Atlassian Pty Ltd 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.ice4j.attribute; 19 | 20 | import junit.framework.*; 21 | 22 | import java.util.*; 23 | 24 | import org.ice4j.*; 25 | 26 | /** 27 | * Tests the realm attribute class. 28 | * 29 | * @author Emil Ivov 30 | * @author Sebastien Vincent 31 | */ 32 | public class RealmAttributeTest extends TestCase 33 | { 34 | private RealmAttribute realmAttribute = null; 35 | MsgFixture msgFixture = null; 36 | String realmValue = "domain.org"; 37 | byte[] attributeBinValue = new byte[]{ 38 | (byte)(RealmAttribute.Type.REALM.type>>8), 39 | (byte)(RealmAttribute.Type.REALM.type & 0x00FF), 40 | 0, (byte)realmValue.length(), 41 | 'd', 'o', 'm', 'a', 'i', 'n', '.', 'o', 'r', 'g', 0x00, 0x00}; 42 | 43 | protected void setUp() throws Exception 44 | { 45 | super.setUp(); 46 | msgFixture = new MsgFixture(); 47 | 48 | realmAttribute = new RealmAttribute(); 49 | realmAttribute.setRealm(realmValue.getBytes()); 50 | } 51 | 52 | protected void tearDown() throws Exception 53 | { 54 | realmAttribute = null; 55 | msgFixture = null; 56 | super.tearDown(); 57 | } 58 | 59 | /** 60 | * Tests decoding of the realm attribute. 61 | * @throws StunException upon a failure 62 | */ 63 | public void testDecodeAttributeBody() throws StunException 64 | { 65 | char offset = 0; 66 | RealmAttribute decoded = new RealmAttribute(); 67 | char length = (char)realmValue.length(); 68 | decoded.decodeAttributeBody(realmValue.getBytes(), offset, length); 69 | 70 | //realm value 71 | assertEquals( "decode failed", realmAttribute, decoded); 72 | } 73 | 74 | /** 75 | * Tests the encode method 76 | */ 77 | public void testEncode() 78 | { 79 | assertTrue("encode failed", 80 | Arrays.equals(realmAttribute.encode(), 81 | attributeBinValue)); 82 | } 83 | 84 | /** 85 | * Test Equals 86 | */ 87 | public void testEquals() 88 | { 89 | RealmAttribute realmAttribute2 = new RealmAttribute(); 90 | realmAttribute2.setRealm(realmValue.getBytes()); 91 | 92 | //test positive equals 93 | assertEquals("testequals failed", realmAttribute, realmAttribute2); 94 | 95 | //test negative equals 96 | realmAttribute2 = new RealmAttribute(); 97 | realmAttribute2.setRealm("some other realm".getBytes()); 98 | 99 | //test positive equals 100 | assertFalse("testequals failed", 101 | realmAttribute.equals(realmAttribute2)); 102 | 103 | //test null equals 104 | assertFalse("testequals failed", 105 | realmAttribute.equals(null)); 106 | } 107 | 108 | /** 109 | * Tests extracting data length 110 | */ 111 | public void testGetDataLength() 112 | { 113 | int expectedReturn = realmValue.length(); 114 | int actualReturn = realmAttribute.getDataLength(); 115 | assertEquals("getDataLength - failed", expectedReturn, actualReturn); 116 | } 117 | 118 | /** 119 | * Tests getting the name 120 | */ 121 | public void testGetName() 122 | { 123 | String expectedReturn = "REALM"; 124 | String actualReturn = realmAttribute.getName(); 125 | assertEquals("getting name failed", expectedReturn, actualReturn); 126 | } 127 | 128 | public void testSetGetRealm() 129 | { 130 | byte[] expectedReturn = realmValue.getBytes(); 131 | 132 | RealmAttribute att = new RealmAttribute(); 133 | att.setRealm(expectedReturn); 134 | 135 | byte[] actualReturn = att.getRealm(); 136 | assertTrue("realm setter or getter failed", 137 | Arrays.equals( expectedReturn, 138 | actualReturn)); 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /src/test/java/org/ice4j/attribute/XorOnlyTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * ice4j, the OpenSource Java Solution for NAT and Firewall Traversal. 3 | * 4 | * Copyright @ 2015 Atlassian Pty Ltd 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.ice4j.attribute; 19 | 20 | import junit.framework.*; 21 | 22 | import java.util.*; 23 | 24 | import org.ice4j.*; 25 | 26 | /** 27 | * @author Emil Ivov 28 | */ 29 | public class XorOnlyTest extends TestCase 30 | { 31 | private XorOnlyAttribute xorOnly = null; 32 | private MsgFixture msgFixture = null; 33 | 34 | protected void setUp() throws Exception 35 | { 36 | super.setUp(); 37 | xorOnly = new XorOnlyAttribute(); 38 | msgFixture = new MsgFixture(); 39 | } 40 | 41 | protected void tearDown() throws Exception 42 | { 43 | xorOnly = null; 44 | msgFixture = null; 45 | super.tearDown(); 46 | } 47 | 48 | /** 49 | * Just makes sure that no exceptions are thrown when calling it as the 50 | * decode method doesn't do anything in the XorOnly att. 51 | * @throws StunException if sth happens 52 | */ 53 | public void testDecodeAttributeBody() throws StunException 54 | { 55 | byte[] attributeValue = new byte[]{}; 56 | char offset = 0; 57 | char length = 0; 58 | xorOnly.decodeAttributeBody(attributeValue, offset, length); 59 | } 60 | 61 | /** 62 | * Test encoding XorOnly attributes. 63 | */ 64 | public void testEncode() 65 | { 66 | byte[] expectedReturn = new byte[]{ 67 | (byte) (Attribute.Type.XOR_ONLY.type>>8), 68 | (byte) (Attribute.Type.XOR_ONLY.type&0x00FF), 69 | 0, 0}; 70 | byte[] actualReturn = xorOnly.encode(); 71 | assertTrue("XorOnly failed to encode", 72 | Arrays.equals( expectedReturn, actualReturn)); 73 | } 74 | 75 | /** 76 | * Test positive and negative XorOnly.equals() returns 77 | * @throws Exception if decoding fails 78 | */ 79 | @SuppressWarnings("unlikely-arg-type") 80 | public void testEquals() throws Exception 81 | { 82 | XorOnlyAttribute xor2 = new XorOnlyAttribute(); 83 | assertEquals("equals() failes for XorOnly", xorOnly, xor2); 84 | 85 | MappedAddressAttribute maatt = new MappedAddressAttribute(); 86 | maatt.decodeAttributeBody( msgFixture.mappedAddress, 87 | (char) 0, 88 | (char) msgFixture.mappedAddress.length ); 89 | 90 | 91 | assertFalse("equals failed to see a difference", xorOnly.equals(maatt)); 92 | assertFalse("equals failed for null", xorOnly.equals(null)); 93 | } 94 | 95 | /** 96 | * Makes sure the data langth is 0 97 | */ 98 | public void testGetDataLength() 99 | { 100 | int expectedReturn = 0; 101 | int actualReturn = xorOnly.getDataLength(); 102 | assertEquals("data length was not 0", expectedReturn, actualReturn); 103 | } 104 | 105 | /** 106 | * Verifies the name (do we really need this?). 107 | */ 108 | public void testGetName() 109 | { 110 | String expectedReturn = "XOR_ONLY"; 111 | String actualReturn = xorOnly.getName(); 112 | assertEquals("Is name correct", expectedReturn, actualReturn); 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /src/test/java/org/ice4j/ice/NetworkUtilsTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * ice4j, the OpenSource Java Solution for NAT and Firewall Traversal. 3 | * 4 | * Copyright @ 2015 Atlassian Pty Ltd 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.ice4j.ice; 19 | 20 | import static org.junit.Assert.*; 21 | 22 | import org.junit.*; 23 | 24 | public class NetworkUtilsTest 25 | { 26 | @Test 27 | public void testIpv6StringToBytes() 28 | { 29 | byte[] addr = NetworkUtils.strToIPv6("::12"); 30 | assertNotNull(addr); 31 | assertEquals(18, addr[15]); 32 | 33 | addr = NetworkUtils.strToIPv6("[::12]"); 34 | assertNotNull(addr); 35 | assertEquals(18, addr[15]); 36 | 37 | addr = NetworkUtils.strToIPv6("::12%1"); 38 | assertNotNull(addr); 39 | assertEquals(18, addr[15]); 40 | 41 | addr = NetworkUtils.strToIPv6("[::12%1]"); 42 | assertNotNull(addr); 43 | assertEquals(18, addr[15]); 44 | 45 | assertNull(NetworkUtils.strToIPv6("[::12]%1")); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/test/java/org/ice4j/message/ChannelDataTest.java: -------------------------------------------------------------------------------- 1 | package org.ice4j.message; 2 | 3 | import org.ice4j.StunException; 4 | import org.junit.Rule; 5 | import org.junit.Test; 6 | import org.junit.rules.ExpectedException; 7 | 8 | import static org.junit.Assert.assertArrayEquals; 9 | import static org.junit.Assert.assertEquals; 10 | import static org.junit.Assert.assertFalse; 11 | import static org.junit.Assert.assertTrue; 12 | 13 | public class ChannelDataTest { 14 | 15 | @Rule public final ExpectedException thrown = ExpectedException.none(); 16 | 17 | @Test 18 | public void testDecode() throws StunException { 19 | final ChannelData channelData = 20 | ChannelData.decode(new byte[]{64, 0, 0, 0, 1}, '\u0000'); 21 | assertArrayEquals(new byte[]{}, channelData.getData()); 22 | assertEquals('\u4000', channelData.getChannelNumber()); 23 | 24 | @SuppressWarnings("deprecation") 25 | final ChannelData channelData2 = 26 | ChannelData.decode(new byte[]{64, 0, 0, 0, 1, 1, 1, 1, 1}, 27 | '\u0000', '\u0000'); 28 | assertArrayEquals(new byte[]{}, channelData2.getData()); 29 | assertEquals('\u4000', channelData2.getChannelNumber()); 30 | } 31 | 32 | @Test 33 | public void testDecodeExceptionSizeTooShort() throws StunException { 34 | thrown.expect(StunException.class); 35 | ChannelData.decode(new byte[] {0, 0, 123, -7, 122, 122, 122}, '\u0007'); 36 | // Method is not expected to return due to exception thrown 37 | } 38 | 39 | @Test 40 | public void testDecodeExceptionChannelNumberInvalid() throws StunException { 41 | thrown.expect(StunException.class); 42 | ChannelData.decode(new byte[]{0, 0, 32, 0, 33}, '\u0000'); 43 | // Method is not expected to return due to exception thrown 44 | } 45 | 46 | @Test 47 | public void testDecodeExceptionSizeMismatch() throws StunException { 48 | thrown.expect(StunException.class); 49 | ChannelData.decode(new byte[]{64, 0, 32, 0, 33}, '\u0000'); 50 | // Method is not expected to return due to exception thrown 51 | } 52 | 53 | @SuppressWarnings("deprecation") 54 | @Test 55 | public void testEncode() throws StunException { 56 | final ChannelData channelData = new ChannelData(); 57 | 58 | channelData.setChannelNumber('\u8001'); 59 | assertArrayEquals(new byte[] {-128, 1, 0, 0}, channelData.encode(false)); 60 | assertArrayEquals(new byte[] {-128, 1, 0, 0}, channelData.encode(true)); 61 | assertArrayEquals(new byte[] {-128, 1, 0, 0}, channelData.encode()); 62 | 63 | channelData.setChannelNumber('\u4000'); 64 | channelData.setData(new byte[] {}); 65 | assertArrayEquals(new byte[] {64, 0, 0, 0}, channelData.encode(true)); 66 | 67 | channelData.setChannelNumber('\u0001'); 68 | channelData.setData(new byte[] {}); 69 | thrown.expect(StunException.class); 70 | channelData.encode(true); 71 | // Method is not expected to return due to exception thrown 72 | } 73 | 74 | @Test 75 | public void testGetDataLength() { 76 | final ChannelData channelData = new ChannelData(); 77 | 78 | assertEquals('\u0000', channelData.getDataLength()); 79 | 80 | channelData.setData(new byte[] {1, 2, 3}); 81 | assertEquals('\u0003', channelData.getDataLength()); 82 | } 83 | 84 | @Test 85 | public void testIsChannelDataMessage() { 86 | assertFalse(ChannelData.isChannelDataMessage(new byte[] {0})); 87 | assertTrue(ChannelData.isChannelDataMessage(new byte[] {64})); 88 | } 89 | 90 | } 91 | -------------------------------------------------------------------------------- /src/test/java/org/ice4j/stunclient/ResponseSequenceServer.java: -------------------------------------------------------------------------------- 1 | /* See LICENSE.md for license information */ 2 | package org.ice4j.stunclient; 3 | 4 | import java.io.IOException; 5 | import java.util.Vector; 6 | 7 | import org.ice4j.StunException; 8 | import org.ice4j.StunMessageEvent; 9 | import org.ice4j.TransportAddress; 10 | import org.ice4j.ice.nio.IceUdpTransport; 11 | import org.ice4j.message.Response; 12 | import org.ice4j.socket.IceSocketWrapper; 13 | import org.ice4j.socket.IceUdpSocketWrapper; 14 | import org.ice4j.stack.RequestListener; 15 | import org.ice4j.stack.StunStack; 16 | import org.slf4j.Logger; 17 | import org.slf4j.LoggerFactory; 18 | 19 | /** 20 | * This class implements a programmable STUN server that sends predefined 21 | * sequences of responses. It may be used to test whether a STUN client 22 | * behaves correctly in different use cases. 23 | * 24 | * @author Emil Ivov 25 | */ 26 | public class ResponseSequenceServer implements RequestListener { 27 | 28 | private static final Logger logger = LoggerFactory.getLogger(ResponseSequenceServer.class); 29 | 30 | /** 31 | * The sequence of responses to send. 32 | */ 33 | private Vector messageSequence = new Vector<>(); 34 | 35 | /** 36 | * The StunStack used by this instance for the purposes of STUN communication. 37 | */ 38 | private final StunStack stunStack; 39 | 40 | private TransportAddress serverAddress; 41 | 42 | private IceSocketWrapper localSocket; 43 | 44 | /** 45 | * Initializes a new ResponseSequenceServer instance with a specific StunStack to be used for the purposes of STUN communication. 46 | * 47 | * @param stunStack the StunStack to be used by the new instance for the purposes of STUN communication 48 | * @param bindAddress 49 | */ 50 | public ResponseSequenceServer(StunStack stunStack, TransportAddress bindAddress) { 51 | this.stunStack = stunStack; 52 | this.serverAddress = bindAddress; 53 | } 54 | 55 | /** 56 | * Initializes the underlying stack. 57 | * 58 | * @throws StunException if something else fails 59 | * @throws IOException if we fail to bind a local socket. 60 | */ 61 | public void start() throws IOException, StunException { 62 | localSocket = IceSocketWrapper.build(serverAddress, null); 63 | stunStack.addRequestListener(serverAddress, this); 64 | IceUdpTransport.getInstance(localSocket.getId()).registerStackAndSocket(stunStack, localSocket); 65 | } 66 | 67 | /** 68 | * Resets the server (deletes the sequence and stops the stack) 69 | */ 70 | public void shutDown() { 71 | messageSequence.removeAllElements(); 72 | localSocket.close(); 73 | } 74 | 75 | /** 76 | * Adds the specified response to this sequence or marks a pause (i.e. do not respond) if response is null. 77 | * 78 | * @param response the response to add or null to mark a pause 79 | */ 80 | public void addMessage(Response response) { 81 | if (response == null) { 82 | // leave a mark to skip a message 83 | messageSequence.add(false); 84 | } else { 85 | messageSequence.add(response); 86 | } 87 | } 88 | 89 | /** 90 | * Completely ignores the event that is passed and just sends the next message from the sequence - or does nothing if there's something 91 | * different from a Response on the current position. 92 | * 93 | * @param evt the event being dispatched 94 | */ 95 | public void processRequest(StunMessageEvent evt) { 96 | if (messageSequence.isEmpty()) { 97 | return; 98 | } 99 | Object obj = messageSequence.remove(0); 100 | if (!(obj instanceof Response)) { 101 | return; 102 | } 103 | Response res = (Response) obj; 104 | try { 105 | stunStack.sendResponse(evt.getMessage().getTransactionID(), res, serverAddress, evt.getRemoteAddress()); 106 | } catch (Exception ex) { 107 | logger.warn("Failed to send a response", ex); 108 | } 109 | } 110 | 111 | /** 112 | * Returns a string representation of this Server. 113 | * 114 | * @return the ip address and port where this server is bound 115 | */ 116 | public String toString() { 117 | return serverAddress == null ? "null" : serverAddress.toString(); 118 | } 119 | 120 | } 121 | -------------------------------------------------------------------------------- /src/test/java/test/AwsTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * ice4j, the OpenSource Java Solution for NAT and Firewall Traversal. Copyright @ 2015 Atlassian Pty Ltd Licensed under the Apache License, Version 2.0 (the "License"); you may 3 | * not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or 4 | * agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 5 | * License for the specific language governing permissions and limitations under the License. 6 | */ 7 | package test; 8 | 9 | import java.util.*; 10 | import java.util.logging.*; 11 | 12 | import org.ice4j.ice.*; 13 | import org.ice4j.ice.harvest.*; 14 | 15 | /** 16 | * An example of using the AWS Harvester. 17 | *

18 | * @author Emil Ivov 19 | */ 20 | public class AwsTest extends Ice { 21 | 22 | private static final Logger logger = Logger.getLogger(AwsTest.class.getName()); 23 | 24 | /** 25 | * Runs a test application that creates an agent, attaches an AWS harvester 26 | * as well as a few allocates streams, generates an SDP and dumps 27 | * it on stdout 28 | * 29 | * @param args none currently handled 30 | * @throws Throwable every now and then. 31 | */ 32 | public static void main(String[] args) throws Throwable { 33 | if (!AwsCandidateHarvester.smellsLikeAnEC2()) { 34 | logger.info("This does not appear to be an EC2 machine"); 35 | return; 36 | } else { 37 | logger.info("Oh nice! Looks like we are on an EC2 machine"); 38 | 39 | } 40 | AwsCandidateHarvester mch = new AwsCandidateHarvester(); 41 | 42 | List harvesters = new ArrayList<>(); 43 | harvesters.add(mch); 44 | 45 | Agent localAgent = createAgent(2020, false, harvesters); 46 | localAgent.setNominationStrategy(NominationStrategy.NOMINATE_HIGHEST_PRIO); 47 | // create a resource file for a test sdp 48 | //String localSDP = SdpUtils.createSDPDescription(localAgent); 49 | 50 | //wait a bit so that the logger can stop dumping stuff: 51 | Thread.sleep(500); 52 | 53 | logger.info("=================== feed the following" + " to the remote agent ==================="); 54 | //logger.info("\n" + localSDP); 55 | logger.info("======================================" + "========================================\n"); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/test/java/test/PortUtil.java: -------------------------------------------------------------------------------- 1 | package test; 2 | 3 | import java.util.concurrent.atomic.AtomicInteger; 4 | 5 | public class PortUtil { 6 | 7 | private final static int PORT_RANGE_START = 49152; 8 | 9 | private final static int PORT_RANGE_MAX = 65536; 10 | 11 | private final static AtomicInteger PORT_PROVIDER = new AtomicInteger(49152); 12 | 13 | public final static int getPort() { 14 | int port = PORT_PROVIDER.getAndIncrement(); 15 | if (port >= PORT_RANGE_MAX) { 16 | PORT_PROVIDER.set(PORT_RANGE_START); 17 | port = PORT_PROVIDER.getAndIncrement(); 18 | } 19 | return port; 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/test/java/test/signalling/Signalling.java: -------------------------------------------------------------------------------- 1 | /* 2 | * ice4j, the OpenSource Java Solution for NAT and Firewall Traversal. 3 | * 4 | * Copyright @ 2015 Atlassian Pty Ltd 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package test.signalling; 19 | 20 | import java.net.*; 21 | 22 | /** 23 | * A simple signaling utility that we use for ICE tests. 24 | * 25 | * @author Emil Ivov 26 | */ 27 | public class Signalling 28 | { 29 | /** 30 | * The socket where we send and receive signaling 31 | */ 32 | // private final Socket signallingSocket; 33 | 34 | // private final SignallingCallback signallingCallback; 35 | 36 | /** 37 | * Creates a signaling instance over the specified socket. 38 | * 39 | * @param socket the socket that this instance should use for signalling 40 | */ 41 | public Signalling(Socket socket, SignallingCallback signallingCallback) 42 | { 43 | // this.signallingSocket = socket; 44 | // this.signallingCallback = signallingCallback; 45 | } 46 | 47 | /** 48 | * Creates a server signalling object. The method will block until a 49 | * connection is actually received on 50 | * 51 | * @param socketAddress our bind address 52 | * @param signallingCallback the callback that we will deliver signalling 53 | * to. 54 | * 55 | * @return the newly created Signalling object 56 | * 57 | * @throws Throwable if anything goes wrong (which could happen with the 58 | * socket stuff). 59 | */ 60 | public static Signalling createServerSignalling( 61 | InetSocketAddress socketAddress, 62 | SignallingCallback signallingCallback) 63 | throws Throwable 64 | { 65 | // ServerSocket serverSocket = new ServerSocket(socketAddress); 66 | // Signalling signalling = new Signalling(socketAddress, signallingCallback); 67 | return null; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/test/java/test/signalling/SignallingCallback.java: -------------------------------------------------------------------------------- 1 | /* 2 | * ice4j, the OpenSource Java Solution for NAT and Firewall Traversal. 3 | * 4 | * Copyright @ 2015 Atlassian Pty Ltd 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package test.signalling; 19 | 20 | /** 21 | * A simple signalling callback interface where we deliever newly received 22 | * signalling from the {@link Signalling} 23 | * 24 | * @author Emil Ivov 25 | */ 26 | public interface SignallingCallback 27 | { 28 | /** 29 | * Processes the specified signalling string 30 | * 31 | * @param signalling the signalling string to process 32 | */ 33 | public void onSignalling(String signalling); 34 | } 35 | -------------------------------------------------------------------------------- /src/test/resources/logback-test.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | TRACE 6 | 7 | 8 | [%p] [%thread] %logger - %msg%n 9 | 10 | 11 | 12 | target/test.log 13 | false 14 | 15 | %d{ISO8601} [%thread] %-5level %logger{35} - %msg%n 16 | 17 | 18 | 19 | 20 | 21 | 22 | 25 | -------------------------------------------------------------------------------- /src/test/resources/logging.properties: -------------------------------------------------------------------------------- 1 | ############################################################ 2 | # Default Logging Configuration File 3 | # 4 | # You can use a different file by specifying a filename 5 | # with the java.util.logging.config.file system property. 6 | # For example java -Djava.util.logging.config.file=myfile 7 | ############################################################ 8 | 9 | ############################################################ 10 | # Global properties 11 | ############################################################ 12 | 13 | # "handlers" specifies a comma separated list of log Handler 14 | # classes. These handlers will be installed during VM startup. 15 | # Note that these classes must be on the system classpath. 16 | # By default we only configure a ConsoleHandler, which will only 17 | # show messages at the INFO and above levels. 18 | handlers= java.util.logging.ConsoleHandler 19 | 20 | 21 | # To also add the FileHandler, use the following line instead. 22 | #handlers= java.util.logging.FileHandler, java.util.logging.ConsoleHandler 23 | 24 | # Default global logging level. 25 | # This specifies which kinds of events are logged across 26 | # all loggers. For any given facility this global level 27 | # can be overriden by a facility specific level 28 | # Note that the ConsoleHandler also has a separate level 29 | # setting to limit messages printed to the console. 30 | .level= SEVERE 31 | 32 | ############################################################ 33 | # Handler specific properties. 34 | # Describes specific configuration info for Handlers. 35 | ############################################################ 36 | 37 | # default file output is in user's home directory. 38 | 39 | 40 | 41 | # Note that the level for the console handler may be modified by the application. 42 | # Also note that you won't see any logs with a Level Lower than this one. 43 | java.util.logging.ConsoleHandler.level = FINEST 44 | java.util.logging.ConsoleHandler.formatter = org.ice4j.util.Ice4jLogFormatter 45 | 46 | 47 | ############################################################ 48 | # Facility specific properties. 49 | # Provides extra control for each logger. 50 | ############################################################ 51 | 52 | # Things coming from ice4j 53 | org.ice4j.level = INFO 54 | test.level = INFO 55 | #org.ice4j.ice.checks.levell = FINEST 56 | #org.ice4j.ice.ConnectivityCheckClient.level = FINER 57 | 58 | --------------------------------------------------------------------------------