├── .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 | 
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 super E> 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