├── .github
└── workflows
│ ├── maven-publish.yml
│ └── maven.yml
├── README
├── pom.xml
├── src
├── main
│ └── java
│ │ ├── io
│ │ └── netty
│ │ │ └── handler
│ │ │ └── codec
│ │ │ └── compression
│ │ │ └── Crc32c.java
│ │ └── pe
│ │ └── pi
│ │ └── sctp4j
│ │ └── sctp
│ │ ├── Association.java
│ │ ├── AssociationListener.java
│ │ ├── MessageCompleteHandler.java
│ │ ├── ReconfigState.java
│ │ ├── SCTPByteStreamListener.java
│ │ ├── SCTPMessage.java
│ │ ├── SCTPOutboundStreamOpenedListener.java
│ │ ├── SCTPStream.java
│ │ ├── SCTPStreamListener.java
│ │ ├── SCTPTimer.java
│ │ ├── StreamNumberInUseException.java
│ │ ├── behave
│ │ ├── OldDCEPStreamBehaviour.java
│ │ ├── OrderedStreamBehaviour.java
│ │ ├── SCTPStreamBehaviour.java
│ │ └── UnorderedStreamBehaviour.java
│ │ ├── dataChannel
│ │ └── DECP
│ │ │ └── DCOpen.java
│ │ ├── dummy
│ │ └── DummyStream.java
│ │ ├── leakey
│ │ ├── LeakyAssociation.java
│ │ └── LeakyTransport.java
│ │ ├── messages
│ │ ├── AbortChunk.java
│ │ ├── Chunk.java
│ │ ├── CookieAckChunk.java
│ │ ├── CookieEchoChunk.java
│ │ ├── DataChunk.java
│ │ ├── ErrorChunk.java
│ │ ├── HeartBeatAckChunk.java
│ │ ├── HeartBeatChunk.java
│ │ ├── InitAckChunk.java
│ │ ├── InitChunk.java
│ │ ├── Packet.java
│ │ ├── ReConfigChunk.java
│ │ ├── SackChunk.java
│ │ ├── exceptions
│ │ │ ├── ChecksumException.java
│ │ │ ├── InvalidDataChunkException.java
│ │ │ ├── InvalidSCTPPacketException.java
│ │ │ ├── MessageException.java
│ │ │ ├── SctpPacketFormatException.java
│ │ │ ├── StaleCookieException.java
│ │ │ └── UnreadyAssociationException.java
│ │ └── params
│ │ │ ├── AddIncomingStreamsRequestParameter.java
│ │ │ ├── AddOutgoingStreamsRequestParameter.java
│ │ │ ├── AddStreamsRequestParameter.java
│ │ │ ├── CookiePreservative.java
│ │ │ ├── HostNameAddress.java
│ │ │ ├── IPv4Address.java
│ │ │ ├── IPv6Address.java
│ │ │ ├── IncomingSSNResetRequestParameter.java
│ │ │ ├── KnownError.java
│ │ │ ├── KnownParam.java
│ │ │ ├── OutgoingSSNResetRequestParameter.java
│ │ │ ├── ProtocolViolationError.java
│ │ │ ├── ReconfigurationResponseParameter.java
│ │ │ ├── RequestedHMACAlgorithmParameter.java
│ │ │ ├── SSNTSNResetRequestParameter.java
│ │ │ ├── StaleCookieError.java
│ │ │ ├── StateCookie.java
│ │ │ ├── SupportedAddressTypes.java
│ │ │ ├── Unknown.java
│ │ │ ├── UnrecognizedParameters.java
│ │ │ └── VariableParam.java
│ │ └── small
│ │ ├── BlockingSCTPStream.java
│ │ ├── MessageSizeExceededException.java
│ │ ├── SimpleSCTPTimer.java
│ │ ├── ThreadedAssociation.java
│ │ └── UDPForwardingStream.java
└── test
│ └── java
│ └── pe
│ └── pi
│ └── sctp4j
│ └── sctp
│ ├── SCTPMessageTest.java
│ ├── behave
│ ├── OrderedStreamBehaviourTest.java
│ └── UnorderedStreamBehaviourTest.java
│ └── small
│ ├── ThreadedAssociationTest.java
│ └── ThreadedAssociationTestEarlies.java
└── test
├── com
└── ipseorama
│ └── sctp
│ └── messages
│ └── TestPacket.groovy
└── main
├── groovy
└── com
│ └── ipseorama
│ └── sctp
│ ├── TestAssociation.groovy
│ └── TestMessage.groovy
└── java
└── com
└── ipseorama
└── sctp
└── MockAssociation.java
/.github/workflows/maven-publish.yml:
--------------------------------------------------------------------------------
1 | # This workflow will build a package using Maven and then publish it to GitHub packages when a release is created
2 | # For more information see: https://github.com/actions/setup-java#apache-maven-with-a-settings-path
3 |
4 | name: Maven Package
5 |
6 | on:
7 | release:
8 | types: [created]
9 |
10 | jobs:
11 | build:
12 |
13 | runs-on: ubuntu-latest
14 |
15 | steps:
16 | - uses: actions/checkout@v2
17 | - name: Set up JDK 11
18 | uses: actions/setup-java@v1
19 | with:
20 | java-version: 11
21 | server-id: github # Value of the distributionManagement/repository/id field of the pom.xml
22 | settings-path: ${{ github.workspace }} # location for the settings.xml file
23 |
24 | - name: Build with Maven
25 | run: mvn -B package --file pom.xml -s $GITHUB_WORKSPACE/settings.xml
26 | env:
27 | GITHUB_TOKEN: ${{ github.token }}
28 |
29 | - name: Publish to GitHub Packages Apache Maven
30 | run: mvn deploy -s $GITHUB_WORKSPACE/settings.xml
31 | env:
32 | GITHUB_TOKEN: ${{ github.token }}
33 |
--------------------------------------------------------------------------------
/.github/workflows/maven.yml:
--------------------------------------------------------------------------------
1 | # This workflow will build a Java project with Maven
2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven
3 |
4 | name: Java CI with Maven
5 |
6 | on:
7 | push:
8 | branches: [ main ]
9 | pull_request:
10 | branches: [ main ]
11 |
12 | jobs:
13 | build:
14 |
15 | runs-on: ubuntu-latest
16 |
17 | steps:
18 | - uses: actions/checkout@v2
19 | - name: Set up JDK 11
20 | uses: actions/setup-java@v1
21 | with:
22 | java-version: 11
23 | - name: Build with Maven
24 | run: mvn -B package --file pom.xml
25 | env:
26 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
27 |
--------------------------------------------------------------------------------
/README:
--------------------------------------------------------------------------------
1 | SCTP4J - by |pipe|
2 |
3 | This is a pure java implementation of the SCTP protocol.
4 | The target usecase is small devices that want to run the webRTC datachannel.
5 |
6 | This implementation does not include all the necessary parts for a full
7 | webRTC stack. You'll need DTLS (we use Bouncy Castle) and ICE/STUN/TURN (you can use Jitsi's ice4j or our slice ).
8 |
9 | This implementation assumes that datagrams will arrive from an DTLS/ICE stack
10 | which implements a Datagram Transport. It also assumes a consumer of open SCTP Streams (or datachannels) - it is pure middleware.
11 |
12 | Brief note on how to drive it:
13 |
14 | Once you have a BouncyCastle DTLS transport open to a WebRTC agent you can:
15 |
16 | public Association makeAssociation(DTLSTransport trans, AssociationListener li) {
17 | a = new ThreadedAssociation(trans, li);
18 | }
19 | The associationListener will fire events when an association is made and when inbound dataChannels are created.
20 | SCTPStreamListener sl;
21 | // create a streamListener here
22 | SCTPStream echo = a.mkStream("echo", sl);
23 | Will create an outbound stream labeled 'echo';
24 |
25 | Background:
26 |
27 | The stack tries to keep the details of concurrency in a single package, so that the current pure thread model could be replaced with Akka actors or NIO-like async mechanisms.
28 |
29 | This implementation works well on small devices (eg Raspberry Pi, C.H.I.P etc)
30 |
31 | Thanks to Michael Tüxen (@tuexen) for help and advice
32 | Thanks to Emil Ivov (@Emcho) for Ice4J and encouragement.
33 |
34 | Some context on the long silence, we hurried a release out as opensource at the request of some friends,
35 | in the end they didn't adopt the release, so it got substantially sidelined whilst I worked on the rest of the |pipe| stack.
36 | I've now circled back and am attempting to make this a viable public project. Sorry for the delay.
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 4.0.0
4 |
5 | pe.pi
6 | sctp4j
7 | 1.0.7
8 | jar
9 |
10 | sctp4j
11 |
12 |
13 | ${project.build.directory}/endorsed
14 | UTF-8
15 |
16 |
17 |
18 |
19 | github
20 | Srtplight
21 | https://maven.pkg.github.com/steely-glint/srtplight
22 |
23 | true
24 |
25 |
26 | true
27 |
28 |
29 |
30 |
31 |
32 |
33 | org.bouncycastle
34 | bcutil-jdk18on
35 | 1.78.1
36 |
37 |
38 | org.glassfish
39 | javax.json
40 | 1.0.4
41 |
42 |
43 | org.bouncycastle
44 | bctls-jdk18on
45 | 1.78.1
46 |
47 |
48 | junit
49 | junit
50 | 4.13.1
51 | test
52 |
53 |
54 | org.hamcrest
55 | hamcrest-core
56 | 1.3
57 | test
58 |
59 |
60 | javax
61 | javaee-web-api
62 | 7.0
63 | provided
64 |
65 |
66 | com.phono
67 | srtplight
68 | 1.1.12
69 |
70 |
71 |
72 |
73 | github
74 | GitHub Packages
75 | https://maven.pkg.github.com/pipe/sctp4j
76 |
77 |
78 |
79 |
80 |
81 | org.apache.maven.plugins
82 | maven-compiler-plugin
83 | 3.1
84 |
85 | 11
86 | 11
87 |
88 | ${endorsed.dir}
89 |
90 |
91 |
92 |
93 | org.apache.maven.plugins
94 | maven-war-plugin
95 | 2.3
96 |
97 | false
98 |
99 |
100 |
101 | org.apache.maven.plugins
102 | maven-dependency-plugin
103 | 2.6
104 |
105 |
106 | validate
107 |
108 | copy
109 |
110 |
111 | ${endorsed.dir}
112 | true
113 |
114 |
115 | javax
116 | javaee-endorsed-api
117 | 7.0
118 | jar
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
--------------------------------------------------------------------------------
/src/main/java/io/netty/handler/codec/compression/Crc32c.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 The Netty Project
3 | *
4 | * The Netty Project licenses this file to you under the Apache License,
5 | * version 2.0 (the "License"); you may not use this file except in compliance
6 | * with the License. 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, WITHOUT
12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 | * License for the specific language governing permissions and limitations
14 | * under the License.
15 | */
16 | package io.netty.handler.codec.compression;
17 |
18 | import java.util.zip.Checksum;
19 |
20 | /**
21 | * Implements CRC32-C as defined in:
22 | * "Optimization of Cyclic Redundancy-CHeck Codes with 24 and 32 Parity Bits",
23 | * IEEE Transactions on Communications 41(6): 883-892 (1993).
24 | *
25 | * The implementation of this class has been sourced from the Appendix of RFC 3309,
26 | * but with masking due to Java not being able to support unsigned types.
27 | */
28 | public class Crc32c implements Checksum {
29 | private static final int[] CRC_TABLE = {
30 | 0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4,
31 | 0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB,
32 | 0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B,
33 | 0x4D43CFD0, 0xBF284CD3, 0xAC78BF27, 0x5E133C24,
34 | 0x105EC76F, 0xE235446C, 0xF165B798, 0x030E349B,
35 | 0xD7C45070, 0x25AFD373, 0x36FF2087, 0xC494A384,
36 | 0x9A879FA0, 0x68EC1CA3, 0x7BBCEF57, 0x89D76C54,
37 | 0x5D1D08BF, 0xAF768BBC, 0xBC267848, 0x4E4DFB4B,
38 | 0x20BD8EDE, 0xD2D60DDD, 0xC186FE29, 0x33ED7D2A,
39 | 0xE72719C1, 0x154C9AC2, 0x061C6936, 0xF477EA35,
40 | 0xAA64D611, 0x580F5512, 0x4B5FA6E6, 0xB93425E5,
41 | 0x6DFE410E, 0x9F95C20D, 0x8CC531F9, 0x7EAEB2FA,
42 | 0x30E349B1, 0xC288CAB2, 0xD1D83946, 0x23B3BA45,
43 | 0xF779DEAE, 0x05125DAD, 0x1642AE59, 0xE4292D5A,
44 | 0xBA3A117E, 0x4851927D, 0x5B016189, 0xA96AE28A,
45 | 0x7DA08661, 0x8FCB0562, 0x9C9BF696, 0x6EF07595,
46 | 0x417B1DBC, 0xB3109EBF, 0xA0406D4B, 0x522BEE48,
47 | 0x86E18AA3, 0x748A09A0, 0x67DAFA54, 0x95B17957,
48 | 0xCBA24573, 0x39C9C670, 0x2A993584, 0xD8F2B687,
49 | 0x0C38D26C, 0xFE53516F, 0xED03A29B, 0x1F682198,
50 | 0x5125DAD3, 0xA34E59D0, 0xB01EAA24, 0x42752927,
51 | 0x96BF4DCC, 0x64D4CECF, 0x77843D3B, 0x85EFBE38,
52 | 0xDBFC821C, 0x2997011F, 0x3AC7F2EB, 0xC8AC71E8,
53 | 0x1C661503, 0xEE0D9600, 0xFD5D65F4, 0x0F36E6F7,
54 | 0x61C69362, 0x93AD1061, 0x80FDE395, 0x72966096,
55 | 0xA65C047D, 0x5437877E, 0x4767748A, 0xB50CF789,
56 | 0xEB1FCBAD, 0x197448AE, 0x0A24BB5A, 0xF84F3859,
57 | 0x2C855CB2, 0xDEEEDFB1, 0xCDBE2C45, 0x3FD5AF46,
58 | 0x7198540D, 0x83F3D70E, 0x90A324FA, 0x62C8A7F9,
59 | 0xB602C312, 0x44694011, 0x5739B3E5, 0xA55230E6,
60 | 0xFB410CC2, 0x092A8FC1, 0x1A7A7C35, 0xE811FF36,
61 | 0x3CDB9BDD, 0xCEB018DE, 0xDDE0EB2A, 0x2F8B6829,
62 | 0x82F63B78, 0x709DB87B, 0x63CD4B8F, 0x91A6C88C,
63 | 0x456CAC67, 0xB7072F64, 0xA457DC90, 0x563C5F93,
64 | 0x082F63B7, 0xFA44E0B4, 0xE9141340, 0x1B7F9043,
65 | 0xCFB5F4A8, 0x3DDE77AB, 0x2E8E845F, 0xDCE5075C,
66 | 0x92A8FC17, 0x60C37F14, 0x73938CE0, 0x81F80FE3,
67 | 0x55326B08, 0xA759E80B, 0xB4091BFF, 0x466298FC,
68 | 0x1871A4D8, 0xEA1A27DB, 0xF94AD42F, 0x0B21572C,
69 | 0xDFEB33C7, 0x2D80B0C4, 0x3ED04330, 0xCCBBC033,
70 | 0xA24BB5A6, 0x502036A5, 0x4370C551, 0xB11B4652,
71 | 0x65D122B9, 0x97BAA1BA, 0x84EA524E, 0x7681D14D,
72 | 0x2892ED69, 0xDAF96E6A, 0xC9A99D9E, 0x3BC21E9D,
73 | 0xEF087A76, 0x1D63F975, 0x0E330A81, 0xFC588982,
74 | 0xB21572C9, 0x407EF1CA, 0x532E023E, 0xA145813D,
75 | 0x758FE5D6, 0x87E466D5, 0x94B49521, 0x66DF1622,
76 | 0x38CC2A06, 0xCAA7A905, 0xD9F75AF1, 0x2B9CD9F2,
77 | 0xFF56BD19, 0x0D3D3E1A, 0x1E6DCDEE, 0xEC064EED,
78 | 0xC38D26C4, 0x31E6A5C7, 0x22B65633, 0xD0DDD530,
79 | 0x0417B1DB, 0xF67C32D8, 0xE52CC12C, 0x1747422F,
80 | 0x49547E0B, 0xBB3FFD08, 0xA86F0EFC, 0x5A048DFF,
81 | 0x8ECEE914, 0x7CA56A17, 0x6FF599E3, 0x9D9E1AE0,
82 | 0xD3D3E1AB, 0x21B862A8, 0x32E8915C, 0xC083125F,
83 | 0x144976B4, 0xE622F5B7, 0xF5720643, 0x07198540,
84 | 0x590AB964, 0xAB613A67, 0xB831C993, 0x4A5A4A90,
85 | 0x9E902E7B, 0x6CFBAD78, 0x7FAB5E8C, 0x8DC0DD8F,
86 | 0xE330A81A, 0x115B2B19, 0x020BD8ED, 0xF0605BEE,
87 | 0x24AA3F05, 0xD6C1BC06, 0xC5914FF2, 0x37FACCF1,
88 | 0x69E9F0D5, 0x9B8273D6, 0x88D28022, 0x7AB90321,
89 | 0xAE7367CA, 0x5C18E4C9, 0x4F48173D, 0xBD23943E,
90 | 0xF36E6F75, 0x0105EC76, 0x12551F82, 0xE03E9C81,
91 | 0x34F4F86A, 0xC69F7B69, 0xD5CF889D, 0x27A40B9E,
92 | 0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E,
93 | 0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351,
94 | };
95 |
96 | private static final long LONG_MASK = 0xFFFFFFFFL;
97 | private static final int BYTE_MASK = 0xFF;
98 |
99 | private int crc = ~0;
100 |
101 | @Override
102 | public void update(int b) {
103 | crc = crc32c(crc, b);
104 | }
105 |
106 | @Override
107 | public void update(byte[] buffer, int offset, int length) {
108 | for (int i = offset; i < offset + length; i++) {
109 | crc = crc32c(crc, buffer[i]);
110 | }
111 | }
112 |
113 | @Override
114 | public long getValue() {
115 | return (crc ^ LONG_MASK) & LONG_MASK;
116 | }
117 |
118 | @Override
119 | public void reset() {
120 | crc = ~0;
121 | }
122 |
123 | private static int crc32c(int crc, int b) {
124 | return crc >>> 8 ^ CRC_TABLE[(crc ^ b & BYTE_MASK) & BYTE_MASK];
125 | }
126 | }
127 |
128 |
--------------------------------------------------------------------------------
/src/main/java/pe/pi/sctp4j/sctp/AssociationListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 pi.pe gmbh .
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 | */
17 | package pe.pi.sctp4j.sctp;
18 |
19 | /**
20 | *
21 | * @author Westhawk Ltd
22 | */
23 | public interface AssociationListener {
24 |
25 | public void onAssociated(Association a);
26 |
27 | public void onDisAssociated(Association a);
28 |
29 | public void onDCEPStream(SCTPStream s, String label, int type) throws Exception ;
30 |
31 | public void onRawStream(SCTPStream s);
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/java/pe/pi/sctp4j/sctp/MessageCompleteHandler.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 pi.pe gmbh .
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 | */
17 |
18 | package pe.pi.sctp4j.sctp;
19 |
20 | import pe.pi.sctp4j.sctp.messages.exceptions.MessageException;
21 |
22 | /**
23 | *
24 | * @author Westhawk Ltd
25 | */
26 | public interface MessageCompleteHandler {
27 | /**
28 | *
29 | * @param m message which has completed
30 | * @param me Null if message was delivered - or indicates failure mode
31 | */
32 | public void messageComplete(SCTPMessage m, MessageException me);
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/java/pe/pi/sctp4j/sctp/ReconfigState.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 pi.pe gmbh .
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 | */
17 | package pe.pi.sctp4j.sctp;
18 |
19 | import pe.pi.sctp4j.sctp.messages.Chunk;
20 | import pe.pi.sctp4j.sctp.messages.ReConfigChunk;
21 | import pe.pi.sctp4j.sctp.messages.params.IncomingSSNResetRequestParameter;
22 | import pe.pi.sctp4j.sctp.messages.params.OutgoingSSNResetRequestParameter;
23 | import pe.pi.sctp4j.sctp.messages.params.ReconfigurationResponseParameter;
24 | import com.phono.srtplight.Log;
25 | import java.util.concurrent.ConcurrentLinkedQueue;
26 |
27 | /**
28 | *
29 | * @author thp
30 | */
31 | class ReconfigState {
32 |
33 | ReConfigChunk recentInbound = null;
34 | ReConfigChunk recentOutboundRequest = null;
35 | ReConfigChunk sentReply = null;
36 | boolean timerRunning = false;
37 | long nearSeqno = 0;
38 | long farSeqno = 0;
39 | Association assoc;
40 | ConcurrentLinkedQueue listOfStreamsToReset;
41 |
42 | ReconfigState(Association a, long farTSN) {
43 | nearSeqno = a.getNearTSN();
44 | farSeqno = farTSN;
45 | assoc = a;
46 | listOfStreamsToReset = new ConcurrentLinkedQueue();
47 | }
48 |
49 | private boolean haveSeen(ReConfigChunk rconf) {
50 | return rconf.sameAs(recentInbound);
51 | }
52 |
53 | private ReConfigChunk getPrevious(ReConfigChunk rconf) {
54 | return rconf.sameAs(recentInbound) ? sentReply : null;
55 | }
56 |
57 | private boolean timerIsRunning() {
58 | return timerRunning;
59 | }
60 |
61 | private void markAsAcked(ReConfigChunk rconf) {
62 | // ooh, what does this button do ??? To Do
63 | }
64 |
65 | private long nextNearNo() {
66 | return nearSeqno++;
67 | }
68 |
69 | private long nextFarNo() {
70 | return farSeqno++;
71 | }
72 |
73 | public long nextDue() {
74 | return 1000L;
75 | }
76 |
77 | /*
78 | * https://tools.ietf.org/html/rfc6525
79 | */
80 | Chunk[] deal(ReConfigChunk rconf) {
81 | Chunk[] ret = new Chunk[1];
82 | ReConfigChunk reply = null;
83 | Log.debug("Got a reconfig message to deal with");
84 | if (haveSeen(rconf)) {
85 | // if not - is this a repeat
86 | reply = getPrevious(rconf); // then send the same reply
87 | }
88 | if (reply == null) {
89 | // not a repeat then
90 | reply = new ReConfigChunk(); // create a new thing
91 | if (rconf.hasOutgoingReset()) {
92 | OutgoingSSNResetRequestParameter oreset = rconf.getOutgoingReset();
93 | int[] streams = oreset.getStreams();
94 | if (streams.length == 0) {
95 | streams = assoc.allStreams();
96 | }
97 | if (timerIsRunning()) {
98 | markAsAcked(rconf);
99 | }
100 | // if we are behind, we are supposed to wait untill we catch up.
101 | if (oreset.getLastAssignedTSN() > assoc.getCumAckPt()) {
102 | Log.debug("Last assigned > farTSN " + oreset.getLastAssignedTSN() + " v " + assoc.getCumAckPt());
103 | for (int s : streams) {
104 | SCTPStream defstr = assoc.getStream(s);
105 | defstr.setDeferred(true);
106 | }
107 | ReconfigurationResponseParameter rep = new ReconfigurationResponseParameter();
108 | rep.setSeq(oreset.getReqSeqNo());
109 | rep.setResult(rep.IN_PROGRESS);
110 | reply.addParam(rep);
111 | } else {
112 | // somehow invoke this when TSN catches up ?!?! ToDo
113 | Log.debug("we are up-to-date ");
114 | ReconfigurationResponseParameter rep = new ReconfigurationResponseParameter();
115 | rep.setSeq(oreset.getReqSeqNo());
116 | int result = streams.length > 0 ? rep.SUCCESS_PERFORMED : rep.SUCCESS_NOTHING_TO_DO;
117 | rep.setResult(result); // assume all good
118 | for (int s : streams) {
119 | SCTPStream cstrm = assoc.delStream(s);
120 | if (cstrm == null) {
121 | Log.error("(re)Close a non existant stream ="+s);
122 | //rep.setResult(rep.ERROR_WRONG_SSN);
123 | //break;
124 | // bidriectional might be a problem here...
125 | } else {
126 | cstrm.reset();
127 | }
128 | }
129 | reply.addParam(rep);
130 | }
131 | }
132 | // ponder putting this in a second chunk ?
133 | if (rconf.hasIncomingReset()) {
134 | IncomingSSNResetRequestParameter ireset = rconf.getIncomingReset();
135 | /*The Re-configuration
136 | Response Sequence Number of the Outgoing SSN Reset Request
137 | Parameter MUST be the Re-configuration Request Sequence Number
138 | of the Incoming SSN Reset Request Parameter. */
139 | OutgoingSSNResetRequestParameter rep = new OutgoingSSNResetRequestParameter(nextNearNo(), ireset.getReqNo(), assoc.getNearTSN());
140 | int[] streams = ireset.getStreams();
141 | rep.setStreams(streams);
142 | if (streams.length == 0) {
143 | streams = assoc.allStreams();
144 | }
145 | for (int s : streams) {
146 | SCTPStream st = assoc.getStream(s);
147 | if (st != null) {
148 | st.setClosing(true);
149 | }
150 | }
151 | reply.addParam(rep);
152 | // set outbound timer running here ???
153 | Log.debug("Ireset " + ireset);
154 | }
155 | }
156 | if (reply.hasParam()) {
157 | ret[0] = reply;
158 | // todo should add sack here
159 | Log.debug("about to reply with " + reply.toString());
160 | } else {
161 | ret = null;
162 | }
163 | return ret;
164 | }
165 |
166 | /* we can only demand they close their outbound streams */
167 | /* we can request they start to close inbound (ie ask us to shut our outbound */
168 | /* DCEP treats streams as bi-directional - so this is somewhat of an inpedance mis-match */
169 | /* resulting in a temporary 'half closed' state */
170 | /* mull this over.... */
171 | ReConfigChunk makeClose(SCTPStream st) throws Exception {
172 | ReConfigChunk ret = null;
173 | Log.debug("building reconfig so close stream " + st);
174 | st.setClosing(true);
175 | listOfStreamsToReset.add(st);
176 | if (!timerIsRunning()) {
177 | ret = makeSSNResets();
178 | }
179 | return ret;
180 | }
181 |
182 | private ReConfigChunk makeSSNResets() throws Exception {
183 |
184 | ReConfigChunk reply = new ReConfigChunk(); // create a new thing
185 | Log.debug("closing streams n=" + listOfStreamsToReset.size());
186 | int[] streams = listOfStreamsToReset.stream().filter((SCTPStream s) -> {
187 | return s.InboundIsOpen();
188 | }).mapToInt((SCTPStream s) -> {
189 | return s.getNum();
190 | }).toArray();
191 | if (streams.length > 0) {
192 | OutgoingSSNResetRequestParameter rep = new OutgoingSSNResetRequestParameter(nextNearNo(), farSeqno - 1, assoc.getNearTSN());
193 | rep.setStreams(streams);
194 | reply.addParam(rep);
195 | }
196 | streams = listOfStreamsToReset.stream().filter((SCTPStream s) -> {
197 | return s.OutboundIsOpen();
198 | }).mapToInt((SCTPStream s) -> {
199 | return s.getNum();
200 | }).toArray();
201 | if (streams.length > 0) {
202 | IncomingSSNResetRequestParameter rep = new IncomingSSNResetRequestParameter(nextNearNo());
203 | rep.setStreams(streams);
204 | reply.addParam(rep);
205 | }
206 | Log.debug("reconfig chunk is " + reply.toString());
207 | return reply;
208 | }
209 |
210 |
211 | }
212 |
--------------------------------------------------------------------------------
/src/main/java/pe/pi/sctp4j/sctp/SCTPByteStreamListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 pi.pe gmbh .
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 | */
17 |
18 | package pe.pi.sctp4j.sctp;
19 |
20 | /**
21 | *
22 | * @author Westhawk Ltd
23 | */
24 | public interface SCTPByteStreamListener extends SCTPStreamListener{
25 | public void onMessage(SCTPStream s, byte[] message);
26 | }
27 |
--------------------------------------------------------------------------------
/src/main/java/pe/pi/sctp4j/sctp/SCTPMessage.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 pi.pe gmbh .
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 | */
17 | package pe.pi.sctp4j.sctp;
18 |
19 | import pe.pi.sctp4j.sctp.messages.DataChunk;
20 | import com.phono.srtplight.Log;
21 | import java.nio.ByteBuffer;
22 | import java.util.SortedSet;
23 | import pe.pi.sctp4j.sctp.behave.SCTPStreamBehaviour;
24 | import pe.pi.sctp4j.sctp.dataChannel.DECP.DCOpen;
25 |
26 | /**
27 | *
28 | * @author Westhawk Ltd
29 | */
30 | public class SCTPMessage implements Runnable {
31 |
32 | private final SCTPStream _stream;
33 | private final byte[] _data;
34 | private int _offset = 0;
35 | private int _pPid = 0;
36 | private int _mseq; // note do we need these ?
37 | private SCTPStreamListener _li;
38 | private boolean _delivered;
39 | private Runnable onAcked;
40 |
41 | /**
42 | * Outbound message - note that we assume no one will mess with data between
43 | * calls to fill()
44 | *
45 | * @param data
46 | * @param s
47 | */
48 | public SCTPMessage(byte[] data, SCTPStream s) {
49 | _data = (data.length > 0) ? data : new byte[1];
50 | _stream = s;
51 | _pPid = (data.length > 0) ? DataChunk.WEBRTCBINARY : DataChunk.WEBRTCBINARYEMPTY;
52 | }
53 |
54 | public SCTPMessage(String data, SCTPStream s) {
55 | _data = (data.length() > 0) ? data.getBytes() : new byte[1];
56 | _stream = s;
57 | _pPid = (data.length() > 0) ? DataChunk.WEBRTCSTRING : DataChunk.WEBRTCSTRINGEMPTY;
58 | }
59 |
60 | public SCTPMessage(DCOpen dcep, SCTPStream s) {
61 | byte[] data = dcep.getBytes();
62 | _data = (data.length > 0) ? data : new byte[1];
63 | _stream = s;
64 | _pPid = (data.length > 0) ? DataChunk.WEBRTCCONTROL : DataChunk.WEBRTCBINARYEMPTY;
65 | }
66 |
67 | public SCTPMessage(SCTPStream s, SortedSet chunks) {
68 | _stream = s;
69 | int tot = 0;
70 | if ((chunks.first().getFlags() & DataChunk.BEGINFLAG) == 0) {
71 | throw new IllegalArgumentException("must start with 'start' chunk");
72 | }
73 | if ((chunks.last().getFlags() & DataChunk.ENDFLAG) == 0) {
74 | throw new IllegalArgumentException("must end with 'end' chunk");
75 | }
76 | _pPid = chunks.first().getPpid();
77 | for (DataChunk dc : chunks) {
78 | tot += dc.getDataSize();
79 | if (_pPid != dc.getPpid()) {
80 | // aaagh
81 | throw new IllegalArgumentException("chunk has wrong ppid" + dc.getPpid() + " vs " + _pPid);
82 | }
83 | }
84 | _data = new byte[tot];
85 | int offs = 0;
86 | for (DataChunk dc : chunks) {
87 | System.arraycopy(dc.getData(), 0, _data, offs, dc.getDataSize());
88 | offs += dc.getDataSize();
89 | }
90 | }
91 |
92 | public SCTPMessage(SCTPStream s, DataChunk singleChunk) {
93 | _stream = s;
94 | int flags = singleChunk.getFlags();
95 | if ((flags & singleChunk.SINGLEFLAG) > 0) {
96 | _data = singleChunk.getData();
97 | _pPid = singleChunk.getPpid();
98 | } else {
99 | throw new IllegalArgumentException("must use a 'single' chunk");
100 | }
101 | }
102 |
103 | public void setCompleteHandler(MessageCompleteHandler mch) {
104 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
105 | }
106 |
107 | public boolean hasMoreData() {
108 | return (_offset < _data.length);
109 | }
110 |
111 | /**
112 | * available datachunks are put here to be filled with data from this
113 | * outbound message
114 | *
115 | * @param dc
116 | */
117 | public void fill(DataChunk dc) {
118 | int dsz = dc.getCapacity();
119 | int remain = _data.length - _offset;
120 | if (_offset == 0) {
121 | if (remain <= dsz) {
122 | // only one chunk
123 | dc.setFlags(dc.SINGLEFLAG);
124 | dc.setData(_data);
125 | _offset = _data.length;
126 | } else {
127 | // first chunk of many
128 | dc.setFlags(dc.BEGINFLAG);
129 | dc.setData(_data, _offset, dsz);
130 | _offset += dsz;
131 | }
132 | } else {// not first
133 | if (remain <= dsz) {
134 | // last chunk, this will all fit.
135 | dc.setFlags(dc.ENDFLAG);
136 | dc.setData(_data, _offset, remain);
137 | _offset += remain; // should be _data_length now
138 | } else {
139 | // middle chunk.
140 | dc.setFlags(0);
141 | dc.setData(_data, _offset, dsz);
142 | _offset += dsz;
143 | }
144 | }
145 | dc.setPpid(_pPid);
146 | dc.setsSeqNo(_mseq);
147 | _stream.outbound(dc);
148 | }
149 |
150 | public boolean deliver(SCTPStreamListener li) {
151 | _li = li;
152 | _delivered = false;
153 | Log.debug("delegating message delivery to stream of type " + _stream.getClass().getSimpleName());
154 | _stream.deliverMessage(this);
155 | return true;
156 | }
157 |
158 | public byte[] getData() {
159 | return _data;
160 | }
161 |
162 | public void setSeq(int mseq) {
163 | _mseq = mseq;
164 | }
165 |
166 | public int getSeq() {
167 | return _mseq;
168 | }
169 |
170 | private void dcepMessageDeal(byte[] data) {
171 | ByteBuffer bb = ByteBuffer.wrap(data);
172 | try {
173 | DCOpen dcep = new DCOpen(bb);
174 | SCTPStreamBehaviour behave = dcep.mkStreamBehaviour();
175 | _stream.setBehave(behave);
176 | if (!dcep.isAck()) {
177 | Log.debug("decp open " + dcep.toString());
178 | _stream.setLabel(dcep.getLabel());
179 | try {
180 | _stream.openAck(dcep);
181 | _stream.alOnDCEPStream(_stream, _stream.getLabel(), _pPid);
182 | // really you would rather have these two the other way around. Not acking
183 | // unless the creation fully works, But this is a 0-rtt protocol - so
184 | // so you have to ack before the stream can send anything.
185 | } catch (Exception x) {
186 | Log.error("Dcep ack failed to send");
187 | if (Log.getLevel() >= Log.DEBUG) {x.printStackTrace();}
188 | try {
189 | _stream.close();
190 | } catch (Exception sx) {
191 | Log.error("Can't close " + _stream.toString() + " because " + x.getMessage());
192 | }
193 | }
194 | } else {
195 | Log.debug("got a dcep ack for " + _stream.getLabel());
196 | if ((_li != null) && (_li instanceof SCTPOutboundStreamOpenedListener)) {
197 | ((SCTPOutboundStreamOpenedListener) _li).opened(_stream);
198 | }
199 | }
200 | } catch (Exception x) {
201 | Log.error("Problem with DCOpen " + x.getMessage());
202 | if (Log.getLevel() >= Log.DEBUG) {x.printStackTrace();}
203 |
204 | }
205 | }
206 |
207 | @Override
208 | public void run() {
209 | Log.debug("delegated message delivery from stream of type " + _stream.getClass().getSimpleName());
210 | if (_li != null){
211 | Log.debug("delegated message delivery to listener of type " + _li.getClass().getSimpleName());
212 | }
213 | byte data[] = _data;
214 | switch (_pPid) {
215 | case DataChunk.WEBRTCBINARYEMPTY:
216 | data = new byte[0];
217 | case DataChunk.WEBRTCBINARY:
218 | if ((_li != null) && (_li instanceof SCTPByteStreamListener)) {
219 | ((SCTPByteStreamListener) _li).onMessage(_stream, data);
220 | _delivered = true;
221 | } else {
222 | _stream.earlyMessageEnqueue(this);
223 | }
224 | break;
225 | case DataChunk.WEBRTCSTRINGEMPTY:
226 | data = new byte[0];
227 | case DataChunk.WEBRTCSTRING:
228 | if (_li != null) {
229 | _li.onMessage(_stream, new String(data));
230 | _delivered = true;
231 | } else {
232 | _stream.earlyMessageEnqueue(this);
233 | }
234 | break;
235 | case DataChunk.WEBRTCCONTROL:
236 | dcepMessageDeal(data);
237 | _delivered = true;
238 | break;
239 | }
240 |
241 | if (!_delivered) {
242 | Log.debug("Undelivered message to " + (_stream == null ? "null stream" : _stream.getLabel()) + " via " + (_li == null ? "null listener" : _li.getClass().getSimpleName()) + " ppid is " + _pPid);
243 | }
244 | }
245 |
246 | public void setAckCallBack(Runnable r) {
247 | onAcked = r;
248 | }
249 |
250 | public void acked() {
251 | if (onAcked != null) {
252 | onAcked.run();
253 | }
254 | }
255 |
256 | }
257 |
--------------------------------------------------------------------------------
/src/main/java/pe/pi/sctp4j/sctp/SCTPOutboundStreamOpenedListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this license header, choose License Headers in Project Properties.
3 | * To change this template file, choose Tools | Templates
4 | * and open the template in the editor.
5 | */
6 | package pe.pi.sctp4j.sctp;
7 |
8 | /**
9 | *
10 | * @author thp
11 | */
12 | public interface SCTPOutboundStreamOpenedListener {
13 | public void opened(SCTPStream s);
14 | }
15 |
--------------------------------------------------------------------------------
/src/main/java/pe/pi/sctp4j/sctp/SCTPStream.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 pi.pe gmbh .
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 | */
17 | package pe.pi.sctp4j.sctp;
18 |
19 | import pe.pi.sctp4j.sctp.behave.OrderedStreamBehaviour;
20 | import pe.pi.sctp4j.sctp.behave.SCTPStreamBehaviour;
21 | import pe.pi.sctp4j.sctp.messages.Chunk;
22 | import pe.pi.sctp4j.sctp.messages.DataChunk;
23 | import com.phono.srtplight.Log;
24 | import java.util.concurrent.ConcurrentSkipListSet;
25 | import java.util.concurrent.LinkedBlockingQueue;
26 | import pe.pi.sctp4j.sctp.dataChannel.DECP.DCOpen;
27 |
28 | /**
29 | *
30 | * @author Westhawk Ltd
31 | */
32 | public abstract class SCTPStream {
33 |
34 | /* unfortunately a webRTC SCTP stream can change it's reliability rules etc post creation
35 | so we can't encapsulate the streams into multiple implementations of the same interface/abstract
36 | So what we do is put the bulk of the stream code here, then delegate the variant rules off to the
37 | behave class - which has to be stateless since it can be swapped out - it is ugly
38 | - and I wonder if closures would do it better.
39 | */
40 | private SCTPStreamBehaviour _behave;
41 | Association _ass;
42 | private Integer _sno;
43 | private String _label;
44 | private ConcurrentSkipListSet _stash;
45 | private SCTPStreamListener _sl;
46 | private int _nextMessageSeqIn;
47 | private int _nextMessageSeqOut;
48 | protected LinkedBlockingQueue _earlyQueue;
49 | private boolean closing;
50 | private State state = State.OPEN;
51 |
52 | public boolean InboundIsOpen() {
53 | return ((state == State.OPEN) || (state == State.INBOUNDONLY));
54 | }
55 |
56 | public boolean OutboundIsOpen() {
57 | return ((state == State.OPEN) || (state == State.OUTBOUNDONLY));
58 | }
59 |
60 | public Chunk immediateClose() {
61 | Chunk ret = null;
62 | try {
63 | ret = _ass.addToCloseList(this);
64 | } catch (Exception ex) {
65 | Log.error("Can't make immediate close for " + this._sno + " because " + ex.getMessage());
66 | }
67 | return ret;
68 | }
69 |
70 | abstract public void delivered(DataChunk d);
71 |
72 | public SCTPStreamListener getSCTPStreamListener() {
73 | return _sl;
74 | }
75 |
76 | @Override
77 | public String toString() {
78 | return this.getClass().getSimpleName()
79 | + "[" + this._sno + "]"
80 | + "=" + this._label
81 | + "|" + _behave.getClass().getSimpleName() + "|"
82 | + "->"
83 | + ((_sl != null) ? _sl.getClass().getSimpleName() : "null");
84 | }
85 |
86 | public String getBehave(){
87 | return (_behave==null)?"unknown":_behave.getClass().getSimpleName();
88 | }
89 | /*
90 | void send(SCTPMessage mess) {
91 | try {
92 | _ass.sendAndBlock(mess);
93 | } catch (Exception ex) {
94 | Log.warn("Can't send SCTPmessage because "+ex.getMessage());
95 | }
96 | }
97 | */
98 | synchronized void setAsNextMessage(SCTPMessage m) {
99 | int mseq = getNextMessageSeqOut();
100 | setNextMessageSeqOut(mseq + 1);
101 | m.setSeq(mseq);
102 | }
103 |
104 | public void openAck(DCOpen dcep) throws Exception {
105 | DCOpen ack = DCOpen.mkAck();
106 | Log.debug("made a dcep ack for "+_label);
107 | send(ack);
108 | }
109 |
110 | protected void alOnDCEPStream(SCTPStream _stream, String label, int _pPid) throws Exception {
111 | _ass.alOnDCEPStream(_stream, label, _pPid);
112 | }
113 |
114 | void earlyMessageEnqueue(SCTPMessage early) {
115 | Log.debug("enqueue an early message seq "+early.getSeq()+" on "+this.toString());
116 | _earlyQueue.add(early);
117 | }
118 |
119 | enum State {
120 | CLOSED, INBOUNDONLY, OUTBOUNDONLY, OPEN
121 | }
122 |
123 | public SCTPStream(Association a, Integer id) {
124 | _ass = a;
125 | _sno = id;
126 | _stash = new ConcurrentSkipListSet(); // sort bt tsn
127 | _behave = new OrderedStreamBehaviour(); // default 'till we know different
128 | _earlyQueue = new LinkedBlockingQueue(100);
129 | }
130 |
131 | public void setLabel(String l) {
132 | _label = l;
133 | }
134 |
135 | public Integer getNum() {
136 | return _sno;
137 | }
138 |
139 | public Chunk[] append(DataChunk dc) {
140 | Log.debug("adding data to stash on stream " + ((_label == null) ? "*unnamed*" : _label) + "(" + dc + ")");
141 | _stash.add(dc);
142 | return _behave.respond(this);
143 | }
144 |
145 | /**
146 | * note that behaviours must be stateless - since they can be swapped out
147 | * when we finally get the 'open'
148 | *
149 | * @param behave
150 | */
151 | public void setBehave(SCTPStreamBehaviour behave) {
152 | _behave = behave;
153 | }
154 |
155 | // seqno management.
156 | /**
157 | * annotate the outgoing chunk with stuff this stream knows.
158 | *
159 | * @param chunk
160 | */
161 | public void outbound(DataChunk chunk) {
162 | chunk.setStreamId(_sno);
163 | // roll seqno here.... hopefully....
164 | }
165 |
166 | void inbound(DataChunk dc) {
167 | if (_behave != null) {
168 | _behave.deliver(this, _stash, _sl);
169 | } else {
170 | Log.warn("No behaviour set");
171 | }
172 | }
173 |
174 | public String getLabel() {
175 | return _label;
176 | }
177 |
178 | int stashCap() {
179 | int ret = 0;
180 | for (DataChunk d : _stash) {
181 | ret += d.getData().length;
182 | }
183 | return ret;
184 | }
185 |
186 | public void setSCTPStreamListener(SCTPStreamListener sl) {
187 | _sl = sl;
188 | Log.debug("adding listener for "+this._label+" of "+sl.getClass().getName());
189 | if (_earlyQueue != null) {
190 | Log.debug("delivering early " + _earlyQueue.size() + " messages to "+sl.getClass().getName());
191 | SCTPMessage e = null;
192 | while (null != (e = _earlyQueue.poll())) {
193 | e.deliver(_sl);
194 | }
195 | } else {
196 | Log.debug("no early queue for "+_label);
197 | }
198 | }
199 |
200 | abstract public void send(String message) throws Exception;
201 |
202 | abstract public void send(byte[] message) throws Exception;
203 |
204 | abstract public void send(DCOpen message) throws Exception;
205 |
206 | public Association getAssociation() {
207 | return _ass;
208 | }
209 |
210 | public void close() throws Exception {
211 | Log.debug("closing stream " + this._label + " " + this._sno);
212 | _ass.closeStream(this);
213 | }
214 |
215 | public void setNextMessageSeqIn(int expectedSeq) {
216 | _nextMessageSeqIn = (expectedSeq == 1 + Character.MAX_VALUE) ? 0 : expectedSeq;
217 | }
218 |
219 | public int getNextMessageSeqIn() {
220 | return _nextMessageSeqIn;
221 | }
222 |
223 | public void setNextMessageSeqOut(int expectedSeq) {
224 | _nextMessageSeqOut = (expectedSeq == 1 + Character.MAX_VALUE) ? 0 : expectedSeq;
225 | }
226 |
227 | public int getNextMessageSeqOut() {
228 | return _nextMessageSeqOut;
229 | }
230 |
231 | abstract public void deliverMessage(SCTPMessage message);
232 |
233 | void setDeferred(boolean b) {
234 | boolean deferred = true;
235 | }
236 |
237 | void reset() {
238 | Log.debug("Resetting stream " + this._sno);
239 | if (this._sl != null) {
240 | _sl.close(this);
241 | }
242 | }
243 |
244 | void setClosing(boolean b) {
245 | closing = b;
246 | }
247 |
248 | boolean isClosing() {
249 | return closing;
250 | }
251 |
252 | void setOutboundClosed() {
253 | switch (state) {
254 | case OPEN:
255 | state = State.INBOUNDONLY;
256 | break;
257 | case OUTBOUNDONLY:
258 | state = State.CLOSED;
259 | break;
260 | case CLOSED:
261 | case INBOUNDONLY:
262 | break;
263 | }
264 | Log.debug("Stream State for " + _sno + " is now " + state);
265 | }
266 |
267 | void setInboundClosed() {
268 | switch (state) {
269 | case OPEN:
270 | state = State.OUTBOUNDONLY;
271 | break;
272 | case INBOUNDONLY:
273 | state = State.CLOSED;
274 | break;
275 | case CLOSED:
276 | case OUTBOUNDONLY:
277 | break;
278 | }
279 | Log.debug("Stream State for " + _sno + " is now " + state);
280 | }
281 |
282 | State getState() {
283 | Log.debug("Stream State for " + _sno + " is currently " + state);
284 | return state;
285 | }
286 |
287 | public boolean idle() {
288 | return true;
289 | }
290 | }
291 |
--------------------------------------------------------------------------------
/src/main/java/pe/pi/sctp4j/sctp/SCTPStreamListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 pi.pe gmbh .
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 | */
17 |
18 | package pe.pi.sctp4j.sctp;
19 |
20 | /**
21 | *
22 | * @author Westhawk Ltd
23 | */
24 | public interface SCTPStreamListener {
25 | public void onMessage(SCTPStream s, String message);
26 |
27 | public void close(SCTPStream aThis);
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/pe/pi/sctp4j/sctp/SCTPTimer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 pi.pe gmbh .
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 | */
17 |
18 | package pe.pi.sctp4j.sctp;
19 |
20 | /**
21 | * interface that hides the threading implementation.
22 | * @author Westhawk Ltd
23 | */
24 | public interface SCTPTimer {
25 | public void setRunnable(Runnable r,long at);
26 | }
27 |
--------------------------------------------------------------------------------
/src/main/java/pe/pi/sctp4j/sctp/StreamNumberInUseException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 pi.pe gmbh .
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 | */
17 |
18 | package pe.pi.sctp4j.sctp;
19 |
20 | /**
21 | *
22 | * @author Westhawk Ltd
23 | */
24 | public class StreamNumberInUseException extends Exception {
25 |
26 | public StreamNumberInUseException() {
27 | }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/pe/pi/sctp4j/sctp/behave/OldDCEPStreamBehaviour.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 pi.pe gmbh .
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 | */
17 | package pe.pi.sctp4j.sctp.behave;
18 |
19 | import pe.pi.sctp4j.sctp.SCTPStream;
20 | import pe.pi.sctp4j.sctp.SCTPStreamListener;
21 | import pe.pi.sctp4j.sctp.messages.Chunk;
22 | import pe.pi.sctp4j.sctp.messages.DataChunk;
23 | import com.phono.srtplight.Log;
24 | import java.util.SortedSet;
25 | import pe.pi.sctp4j.sctp.AssociationListener;
26 | import pe.pi.sctp4j.sctp.SCTPOutboundStreamOpenedListener;
27 | import pe.pi.sctp4j.sctp.dataChannel.DECP.DCOpen;
28 |
29 | /**
30 | *
31 | * @author tim what DCEPS do
32 | */
33 | public class OldDCEPStreamBehaviour implements
34 | SCTPStreamBehaviour {
35 |
36 | private final AssociationListener al;
37 |
38 | public OldDCEPStreamBehaviour(AssociationListener associationListener) {
39 | al = associationListener;
40 | Log.debug("DCEPStreamBehaviour");
41 | }
42 |
43 | @Override
44 | public Chunk[] respond(SCTPStream a) {
45 | return null;
46 | }
47 |
48 | @Override
49 | public void deliver(SCTPStream s, SortedSet a, SCTPStreamListener l) {
50 | DataChunk dc = a.first();
51 | int flags = dc.getFlags() & DataChunk.SINGLEFLAG; // mask to the bits we want
52 | long tsn = dc.getTsn();
53 | int messageNo = s.getNextMessageSeqIn();
54 |
55 |
56 |
57 | // only interested in the first chunk which should be an ack or an open.
58 | DCOpen dcep = dc.getDCEP();
59 | if (dcep != null) {
60 | Log.debug("DCEPStreamBehaviour has a dcep first.");
61 | if(flags != DataChunk.SINGLEFLAG){
62 | Log.error("Dcep isn't a single !!?!");
63 | }
64 | messageNo++;
65 | s.setNextMessageSeqIn(messageNo);
66 | a.remove(dc);
67 | SCTPStreamBehaviour behave = dcep.mkStreamBehaviour();
68 | s.setBehave(behave);
69 | if (!dcep.isAck()) {
70 | Log.debug("decp open " + dcep.toString());
71 | s.setLabel(dcep.getLabel());
72 | try {
73 | s.openAck(dcep);
74 | al.onDCEPStream(s, s.getLabel(), dc.getPpid());
75 | // really you would rather have these two the other way around. Not acking
76 | // unless the creation fully works, But this is a 0-rtt protocol - so
77 | // it is best to ack asap.
78 | } catch (Exception x) {
79 | try {
80 | s.close();
81 | } catch (Exception sx) {
82 | Log.error("Can't close " + s.toString() + " because " + x.getMessage());
83 | }
84 | }
85 | } else {
86 | Log.debug("got a dcep ack for " + s.getLabel());
87 | if ((l != null) && (l instanceof SCTPOutboundStreamOpenedListener)) {
88 | ((SCTPOutboundStreamOpenedListener) l).opened(s);
89 | }
90 | }
91 |
92 | // and consume the rest using the new behave.
93 | if (behave != null) {
94 | behave.deliver(s, a, l);
95 | }
96 | } else {
97 | Log.debug("Cant deliver chunks before DCEP");
98 | }
99 | }
100 |
101 | }
102 |
--------------------------------------------------------------------------------
/src/main/java/pe/pi/sctp4j/sctp/behave/OrderedStreamBehaviour.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 pi.pe gmbh .
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 | */
17 | package pe.pi.sctp4j.sctp.behave;
18 |
19 | import pe.pi.sctp4j.sctp.SCTPMessage;
20 | import pe.pi.sctp4j.sctp.SCTPStream;
21 | import pe.pi.sctp4j.sctp.SCTPStreamListener;
22 | import pe.pi.sctp4j.sctp.messages.Chunk;
23 | import pe.pi.sctp4j.sctp.messages.DataChunk;
24 | import com.phono.srtplight.Log;
25 | import java.util.ArrayList;
26 | import java.util.SortedSet;
27 | import java.util.TreeSet;
28 |
29 | /**
30 | *
31 | * @author tim
32 | */
33 | public class OrderedStreamBehaviour implements SCTPStreamBehaviour {
34 |
35 | protected boolean _ordered = true;
36 |
37 | @Override
38 | public void deliver(SCTPStream s, SortedSet stash, SCTPStreamListener l) {
39 | //stash is the list of all DataChunks that have not yet been turned into whole messages
40 | //we assume that it is sorted by stream sequence number.
41 | ArrayList delivered = new ArrayList();
42 | SortedSet message = null;
43 | if (stash.isEmpty()){
44 | return; // I'm not fond of these early returns
45 | }
46 | long expectedTsn = stash.first().getTsn(); // This ignores gaps - but _hopefully_ messageNo will catch any
47 | // gaps we care about - ie gaps in the sequence for _this_ stream
48 | // we can deliver ordered messages on this stream even if earlier messages from other streams are missing
49 | // - this does assume that the tsn's of a message are contiguous -which is odd.
50 |
51 |
52 | for (DataChunk dc : stash) {
53 | int messageNo = s.getNextMessageSeqIn();
54 |
55 | int flags = dc.getFlags() & DataChunk.SINGLEFLAG; // mask to the bits we want
56 | long tsn = dc.getTsn();
57 | boolean lookingForOrderedMessages = _ordered || (message != null);
58 | // which is to say for unordered messages we can tolerate gaps _between_ messages
59 | // but not within them
60 | if (lookingForOrderedMessages && (tsn != expectedTsn)) {
61 | Log.debug("Hole in chunk sequence " + tsn + " expected " + expectedTsn);
62 | break;
63 | }
64 | switch (flags) {
65 | case DataChunk.SINGLEFLAG:
66 | // singles are easy - just dispatch.
67 | if (_ordered && (messageNo != dc.getSSeqNo())) {
68 | Log.debug("Hole (single) in message sequence " + dc.getSSeqNo() + " expected " + messageNo);
69 | break; // not the message we are looking for...
70 | }
71 | SCTPMessage single = new SCTPMessage(s, dc);
72 | if (single.deliver(l)) {
73 | delivered.add(dc);
74 | messageNo++;
75 | s.setNextMessageSeqIn(messageNo);
76 | }
77 | break;
78 | case DataChunk.BEGINFLAG:
79 | if (_ordered && (messageNo != dc.getSSeqNo())) {
80 | Log.debug("Hole (begin) in message sequence " + dc.getSSeqNo() + " expected " + messageNo);
81 | break; // not the message we are looking for...
82 | }
83 | message = new TreeSet();
84 | message.add(dc);
85 | Log.verb("new message no" + dc.getSSeqNo() + " starts with " + dc.getTsn());
86 | break;
87 | case 0: // middle
88 | if (message != null) {
89 | message.add(dc);
90 | Log.verb("continued message no" + dc.getSSeqNo() + " with " + dc.getTsn());
91 | } else {
92 | // perhaps check sno ?
93 | Log.debug("Middle with no start" + dc.getSSeqNo() + " tsn " + dc.getTsn());
94 | }
95 | break;
96 | case DataChunk.ENDFLAG:
97 | if (message != null) {
98 | message.add(dc);
99 | Log.verb("finished message no" + dc.getSSeqNo() + " with " + dc.getTsn());
100 | SCTPMessage deliverable = new SCTPMessage(s, message);
101 | if (deliverable.deliver(l)) {
102 | delivered.addAll(message);
103 | messageNo++;
104 | s.setNextMessageSeqIn(messageNo);
105 | }
106 | message = null;
107 | } else {
108 | Log.debug("End with no start" + dc.getSSeqNo() + " tsn " + dc.getTsn());
109 | message = null;
110 | }
111 | break;
112 | default:
113 | throw new IllegalStateException("Impossible value in stream logic");
114 | }
115 | expectedTsn = tsn + 1;
116 | }
117 | stash.removeAll(delivered);
118 | }
119 |
120 | @Override
121 | public Chunk[] respond(SCTPStream a) {
122 | return null;
123 | }
124 |
125 | }
126 |
--------------------------------------------------------------------------------
/src/main/java/pe/pi/sctp4j/sctp/behave/SCTPStreamBehaviour.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 pi.pe gmbh .
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 | */
17 | package pe.pi.sctp4j.sctp.behave;
18 |
19 | import pe.pi.sctp4j.sctp.SCTPStream;
20 | import pe.pi.sctp4j.sctp.SCTPStreamListener;
21 | import pe.pi.sctp4j.sctp.messages.Chunk;
22 | import pe.pi.sctp4j.sctp.messages.DataChunk;
23 | import java.util.SortedSet;
24 |
25 | /**
26 | *
27 | * @author tim
28 | */
29 | public interface SCTPStreamBehaviour {
30 |
31 | // Something has happend to the stream, this is our chance to respond.
32 | // typically this means sending nothing
33 | public Chunk[] respond(SCTPStream a);
34 |
35 | // we have a sorted queue of datachunks for this stream to deliver
36 | // according to the appropriate behaviour.
37 | public void deliver(SCTPStream s, SortedSet a, SCTPStreamListener l) ;
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/src/main/java/pe/pi/sctp4j/sctp/behave/UnorderedStreamBehaviour.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 pi.pe gmbh .
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 | */
17 | package pe.pi.sctp4j.sctp.behave;
18 |
19 | /**
20 | *
21 | * @author tim
22 | */
23 | public class UnorderedStreamBehaviour extends OrderedStreamBehaviour {
24 |
25 | public UnorderedStreamBehaviour() {
26 | _ordered = false;
27 | }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/pe/pi/sctp4j/sctp/dataChannel/DECP/DCOpen.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 pi.pe gmbh .
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 | */
17 | package pe.pi.sctp4j.sctp.dataChannel.DECP;
18 |
19 | import pe.pi.sctp4j.sctp.behave.SCTPStreamBehaviour;
20 | import pe.pi.sctp4j.sctp.behave.OrderedStreamBehaviour;
21 | import pe.pi.sctp4j.sctp.behave.UnorderedStreamBehaviour;
22 | import pe.pi.sctp4j.sctp.messages.Packet;
23 | import pe.pi.sctp4j.sctp.messages.exceptions.InvalidDataChunkException;
24 | import com.phono.srtplight.Log;
25 | import java.nio.Buffer;
26 | import java.nio.ByteBuffer;
27 |
28 | /**
29 | *
30 | * @author Westhawk Ltd
31 | */
32 | public class DCOpen {
33 |
34 | /*
35 | +------------------------------------------------+------+-----------+
36 | | Name | Type | Reference |
37 | +------------------------------------------------+------+-----------+
38 | | DATA_CHANNEL_RELIABLE | 0x00 | [RFCXXXX] |
39 | | DATA_CHANNEL_RELIABLE_UNORDERED | 0x80 | [RFCXXXX] |
40 | | DATA_CHANNEL_PARTIAL_RELIABLE_REXMIT | 0x01 | [RFCXXXX] |
41 | | DATA_CHANNEL_PARTIAL_RELIABLE_REXMIT_UNORDERED | 0x81 | [RFCXXXX] |
42 | | DATA_CHANNEL_PARTIAL_RELIABLE_TIMED | 0x02 | [RFCXXXX] |
43 | | DATA_CHANNEL_PARTIAL_RELIABLE_TIMED_UNORDERED | 0x82 | [RFCXXXX] |
44 | | Reserved | 0x7f | [RFCXXXX] |
45 | | Reserved | 0xff | [RFCXXXX] |
46 | | Unassigned | rest | |
47 | +------------------------------------------------+------+-----------+
48 | */
49 | public final static byte RELIABLE = 0x0;
50 | public final static byte PARTIAL_RELIABLE_REXMIT = 0x01;
51 | public final static byte PARTIAL_RELIABLE_REXMIT_UNORDERED = (byte) 0x81;
52 | public final static byte PARTIAL_RELIABLE_TIMED = 0x02;
53 | public final static byte PARTIAL_RELIABLE_TIMED_UNORDERED = (byte) 0x82;
54 | public final static byte RELIABLE_UNORDERED = (byte) 0x80;
55 |
56 | /*
57 | 5.1. DATA_CHANNEL_OPEN Message
58 |
59 | This message is sent initially on the stream used for user messages
60 | using the channel.
61 |
62 | 0 1 2 3
63 | 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
64 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
65 | | Message Type | Channel Type | Priority |
66 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
67 | | Reliability Parameter |
68 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
69 | | Label Length | Protocol Length |
70 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
71 | \ /
72 | | Label |
73 | / \
74 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
75 | \ /
76 | | Protocol |
77 | / \
78 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
79 | */
80 | private byte _messType;
81 | private byte _chanType;
82 | private int _priority;
83 | private long _reliablity;
84 | int _labLen;
85 | int _protLen;
86 | private byte[] _label;
87 | private byte[] _protocol;
88 | final static int OPEN = 0x03;
89 | final static int ACK = 0x02;
90 | boolean _isAck = false;
91 |
92 | public DCOpen(String label) {
93 | this((byte) RELIABLE, 0, 0, label, "");
94 | }
95 |
96 | // used to make Acks only
97 | private DCOpen() {
98 | }
99 |
100 | public DCOpen(
101 | byte chanType,
102 | int priority,
103 | long reliablity,
104 | String label,
105 | String protocol) {
106 | _messType = (byte) OPEN;
107 | _chanType = chanType;
108 | _priority = priority;
109 | _reliablity = reliablity;
110 | _label = label.getBytes();
111 | _protocol = protocol.getBytes();
112 | _labLen = _label.length;
113 | _protLen = _protocol.length;
114 | }
115 |
116 | public byte[] getBytes() {
117 | int sz = 12 + _labLen + pad(_labLen) + _protLen + pad(_protLen);
118 | Log.verb("dcopen needs " + sz + " bytes ");
119 |
120 | byte[] ret = new byte[sz];
121 | ByteBuffer buff = ByteBuffer.wrap(ret);
122 | buff.put((byte) _messType);
123 | buff.put((byte) _chanType);
124 | buff.putChar((char) _priority);
125 | buff.putInt((int) _reliablity);
126 | buff.putChar((char) _labLen);
127 | buff.putChar((char) _protLen);
128 | buff.put(_label);
129 | Buffer bu = (Buffer)buff; // work around for needless incompatibility between JDK 11 and 8
130 | bu.position(bu.position() + pad(_labLen));
131 | buff.put(_protocol);
132 | bu.position(bu.position() + pad(_protLen));
133 |
134 | return ret;
135 | }
136 |
137 | final static public int pad(int len) {
138 | int mod = len % 4;
139 | int res = 0;
140 | Log.verb("field of " + len + " mod 4 is " + mod);
141 |
142 | if (mod > 0) {
143 | res = (4 - mod);
144 | }
145 | Log.verb("padded by " + res);
146 | return res;
147 | }
148 |
149 | public DCOpen(ByteBuffer bb) throws InvalidDataChunkException {
150 | _messType = bb.get();
151 | switch (_messType) {
152 | case OPEN:
153 | _chanType = bb.get();
154 | _priority = bb.getChar();
155 | _reliablity = bb.getInt();
156 | _labLen = bb.getChar();
157 | _protLen = bb.getChar();
158 | _label = new byte[_labLen];
159 | bb.get(_label);
160 | _protocol = new byte[_protLen];
161 | bb.get(_protocol);
162 | break;
163 | case ACK:
164 | _isAck = true;
165 | break;
166 | default:
167 | throw new InvalidDataChunkException("Unexpected DCEP message type " + _messType);
168 | //break;
169 |
170 | }
171 | }
172 |
173 | public String toString() {
174 | return _isAck ? "Ack " : "Open "
175 | + " _chanType =" + (int) _chanType
176 | + " _priority = " + _priority
177 | + " _reliablity = " + _reliablity
178 | + " _label = " + new String(_label)
179 | + " _protocol = " + Packet.getHex(_protocol);
180 | }
181 |
182 | public boolean isAck() {
183 | return _isAck;
184 | }
185 |
186 | public SCTPStreamBehaviour mkStreamBehaviour() {
187 | String loglab = _label == null?"_null_":new String(_label);
188 | Log.debug("Making a behaviour for dcep stream " + loglab);
189 | SCTPStreamBehaviour behave = null;
190 | switch (_chanType) {
191 | case RELIABLE:
192 | behave = new OrderedStreamBehaviour();
193 | break;
194 | case RELIABLE_UNORDERED:
195 | behave = new UnorderedStreamBehaviour();
196 | break;
197 | // todo these next 4 are wrong... the odering is atleast correct
198 | // even if the retry is wrong.
199 | case PARTIAL_RELIABLE_REXMIT:
200 | case PARTIAL_RELIABLE_TIMED:
201 | behave = new OrderedStreamBehaviour();
202 | break;
203 | case PARTIAL_RELIABLE_REXMIT_UNORDERED:
204 | case PARTIAL_RELIABLE_TIMED_UNORDERED:
205 | behave = new UnorderedStreamBehaviour();
206 | break;
207 | }
208 | if (behave != null) {
209 | Log.debug(loglab + " behaviour is " + behave.getClass().getSimpleName());
210 | }
211 |
212 | return behave;
213 | }
214 |
215 | public String getLabel() {
216 | return new String(_label);
217 | }
218 |
219 | public static DCOpen mkAck() {
220 | DCOpen ack = new DCOpen() {
221 | @Override
222 | public byte[] getBytes() {
223 | byte[] a = new byte[1];
224 | a[0] = ACK;
225 | return a;
226 | }
227 | };
228 | ack._isAck = true;
229 | return ack;
230 | }
231 |
232 | }
233 |
--------------------------------------------------------------------------------
/src/main/java/pe/pi/sctp4j/sctp/dummy/DummyStream.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this license header, choose License Headers in Project Properties.
3 | * To change this template file, choose Tools | Templates
4 | * and open the template in the editor.
5 | */
6 | package pe.pi.sctp4j.sctp.dummy;
7 |
8 | import pe.pi.sctp4j.sctp.Association;
9 | import pe.pi.sctp4j.sctp.SCTPMessage;
10 | import pe.pi.sctp4j.sctp.SCTPStream;
11 | import pe.pi.sctp4j.sctp.dataChannel.DECP.DCOpen;
12 | import pe.pi.sctp4j.sctp.messages.DataChunk;
13 |
14 | /**
15 | * Concrete stream which mocks the abstract methods - used as a place holder in tests etc
16 | * @author tim
17 | */
18 | public class DummyStream extends SCTPStream{
19 |
20 | public DummyStream(Association a, Integer id) {
21 | super(a, id);
22 | }
23 |
24 | @Override
25 | public void delivered(DataChunk d) {
26 | }
27 |
28 | @Override
29 | public void send(String message) throws Exception {
30 | }
31 |
32 | @Override
33 | public void send(byte[] message) throws Exception {
34 | }
35 |
36 | @Override
37 | public void send(DCOpen message) throws Exception {
38 | }
39 |
40 | @Override
41 | public void deliverMessage(SCTPMessage message) {
42 | }
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/src/main/java/pe/pi/sctp4j/sctp/leakey/LeakyAssociation.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 pi.pe gmbh .
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 | */
17 | package pe.pi.sctp4j.sctp.leakey;
18 |
19 | import pe.pi.sctp4j.sctp.AssociationListener;
20 | import pe.pi.sctp4j.sctp.small.ThreadedAssociation;
21 | import org.bouncycastle.tls.DatagramTransport;
22 |
23 | /**
24 | *
25 | * @author Westhawk Ltd
26 | */
27 | public class LeakyAssociation extends ThreadedAssociation {
28 |
29 | public LeakyAssociation(DatagramTransport transport, AssociationListener al) {
30 | super(new LeakyTransport(transport), al);
31 | }
32 |
33 | }
34 |
35 |
--------------------------------------------------------------------------------
/src/main/java/pe/pi/sctp4j/sctp/leakey/LeakyTransport.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 pi.pe gmbh .
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 | */
17 | package pe.pi.sctp4j.sctp.leakey;
18 |
19 | import com.phono.srtplight.Log;
20 | import java.io.IOException;
21 | import java.net.DatagramPacket;
22 | import java.net.DatagramSocket;
23 | import java.net.InetAddress;
24 | import java.net.InetSocketAddress;
25 | import org.bouncycastle.tls.DatagramTransport;
26 |
27 | /**
28 | *
29 | * @author Westhawk Ltd
30 | *
31 | * class that taps off the DTLS decoded SCTP traffic and echoes it to a pair of
32 | * UDP ports so they can be pcaped by wireshark Do not use this class in
33 | * production code. test/debug only!
34 | *
35 | */
36 | class LeakyTransport implements DatagramTransport {
37 |
38 | DatagramTransport _dtls;
39 | DatagramSocket _logrec;
40 | DatagramSocket _logsend;
41 | static short SCTP = 9800;
42 |
43 | public LeakyTransport(DatagramTransport transport) {
44 | InetAddress me = java.net.Inet4Address.getLoopbackAddress();
45 | try {
46 | _dtls = transport;
47 | _logrec = new DatagramSocket(SCTP, me);
48 | _logsend = new DatagramSocket(SCTP + 1, me);
49 |
50 | InetSocketAddress s = (InetSocketAddress) _logsend.getLocalSocketAddress();
51 | Log.warn("Leaking to send address " + s.getHostString() + ":" + s.getPort());
52 | InetSocketAddress r = (InetSocketAddress) _logrec.getLocalSocketAddress();
53 | Log.warn("Leaking to recv address " + r.getHostString() + ":" + r.getPort());
54 | } catch (Exception ex) {
55 | Log.error("exception in making Leaky socket "+SCTP+" loopback "+me);
56 | }
57 | SCTP +=10;
58 | }
59 |
60 | @Override
61 | public int getReceiveLimit() throws IOException {
62 | return _dtls.getReceiveLimit();
63 | }
64 |
65 | @Override
66 | public int getSendLimit() throws IOException {
67 | return _dtls.getSendLimit();
68 | }
69 |
70 | @Override
71 | public int receive(byte[] bytes, int offs, int len, int sleep) throws IOException {
72 | int sz = _dtls.receive(bytes, offs, len, sleep);
73 | if (sz > 0) {
74 | DatagramPacket p = new DatagramPacket(bytes, offs, sz, _logsend.getLocalSocketAddress());
75 | _logrec.send(p);
76 | }
77 | return sz;
78 | }
79 |
80 | @Override
81 | public void send(byte[] bytes, int offs, int len) throws IOException {
82 | if ((bytes == null) || (bytes.length < offs + len) || (bytes.length <1)){
83 | Log.error("Implausible packet for encryption ");
84 | if (bytes == null) {
85 | Log.error("null buffer");
86 | }else {
87 | Log.error("Length ="+bytes.length+" len ="+len+" offs="+offs);
88 | }
89 | return;
90 | }
91 | try {
92 | DatagramPacket p = new DatagramPacket(bytes, offs, len, _logrec.getLocalSocketAddress());
93 | _logsend.send(p);
94 | } catch (Exception x) {
95 | Log.error("can't leak to " + _logrec.getLocalSocketAddress());
96 | x.printStackTrace();
97 | }
98 | _dtls.send(bytes, offs, len);
99 | }
100 |
101 | @Override
102 | public void close() throws IOException {
103 | _dtls.close();
104 | _logrec.close();
105 | _logsend.close();
106 | }
107 |
108 | }
109 |
--------------------------------------------------------------------------------
/src/main/java/pe/pi/sctp4j/sctp/messages/AbortChunk.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 pi.pe gmbh .
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 | */
17 | package pe.pi.sctp4j.sctp.messages;
18 |
19 | import pe.pi.sctp4j.sctp.messages.params.VariableParam;
20 | import com.phono.srtplight.Log;
21 | import java.nio.ByteBuffer;
22 | import java.util.ArrayList;
23 |
24 | /**
25 | *
26 | * @author Westhawk Ltd
27 | */
28 |
29 | /*
30 | 0 1 2 3
31 | 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
32 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
33 | | Type = 6 |Reserved |T| Length |
34 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
35 | \ \
36 | / zero or more Error Causes /
37 | \ \
38 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
39 |
40 |
41 | */
42 | public class AbortChunk extends Chunk {
43 |
44 |
45 |
46 | public AbortChunk() {
47 | super((byte) Chunk.ABORT);
48 | }
49 |
50 |
51 | public AbortChunk(byte type, byte flags, int length, ByteBuffer pkt) {
52 | super(type, flags, length, pkt);
53 | if (_body.remaining() >= 4) {
54 | Log.verb("Abort" + this.toString());
55 | while (_body.hasRemaining()) {
56 | VariableParam v = readErrorParam();
57 | _varList.add(v);
58 | }
59 | }
60 | }
61 |
62 |
63 |
64 | @Override
65 | void putFixedParams(ByteBuffer ret) {
66 |
67 | }
68 |
69 |
70 | }
71 |
--------------------------------------------------------------------------------
/src/main/java/pe/pi/sctp4j/sctp/messages/CookieAckChunk.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 pi.pe gmbh .
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 | */
17 | package pe.pi.sctp4j.sctp.messages;
18 |
19 | import java.nio.ByteBuffer;
20 |
21 | /**
22 | *
23 | * @author Westhawk Ltd
24 | */
25 | public class CookieAckChunk extends Chunk {
26 |
27 | public CookieAckChunk(byte type, byte flags, int length, ByteBuffer pkt) {
28 | super(type, flags, length, pkt);
29 | }
30 |
31 | public CookieAckChunk() {
32 | super((byte) Chunk.COOKIE_ACK);
33 | }
34 |
35 | @Override
36 | void putFixedParams(ByteBuffer ret) {
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/main/java/pe/pi/sctp4j/sctp/messages/CookieEchoChunk.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 pi.pe gmbh .
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 | */
17 | package pe.pi.sctp4j.sctp.messages;
18 |
19 | import pe.pi.sctp4j.sctp.Association;
20 | import pe.pi.sctp4j.sctp.messages.exceptions.SctpPacketFormatException;
21 | import com.phono.srtplight.Log;
22 | import java.nio.ByteBuffer;
23 |
24 | /**
25 | *
26 | * @author Westhawk Ltd
27 | *
28 | *
29 | * 3.3.11. Cookie Echo (COOKIE ECHO) (10)
30 |
31 | This chunk is used only during the initialization of an association.
32 | It is sent by the initiator of an association to its peer to complete
33 | the initialization process. This chunk MUST precede any DATA chunk
34 | sent within the association, but MAY be bundled with one or more DATA
35 | chunks in the same packet.
36 |
37 | 0 1 2 3
38 | 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
39 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
40 | | Type = 10 |Chunk Flags | Length |
41 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
42 | / Cookie /
43 | \ \
44 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
45 |
46 | Chunk Flags: 8 bit
47 |
48 | Set to 0 on transmit and ignored on receipt.
49 |
50 | Length: 16 bits (unsigned integer)
51 |
52 | Set to the size of the chunk in bytes, including the 4 bytes of
53 | the chunk header and the size of the cookie.
54 |
55 |
56 |
57 |
58 |
59 | Stewart Standards Track [Page 50]
60 |
61 | RFC 4960 Stream Control Transmission Protocol September 2007
62 |
63 |
64 | Cookie: variable size
65 |
66 | This field must contain the exact cookie received in the State
67 | Cookie parameter from the previous INIT ACK.
68 |
69 | An implementation SHOULD make the cookie as small as possible to
70 | ensure interoperability.
71 |
72 | Note: A Cookie Echo does NOT contain a State Cookie parameter;
73 | instead, the data within the State Cookie's Parameter Value
74 | becomes the data within the Cookie Echo's Chunk Value. This
75 | allows an implementation to change only the first 2 bytes of the
76 | State Cookie parameter to become a COOKIE ECHO chunk.
77 | *
78 | */
79 | public class CookieEchoChunk extends Chunk {
80 | private byte[] _cookieData;
81 |
82 | public CookieEchoChunk(byte type, byte flags, int length, ByteBuffer pkt) {
83 | super(type, flags, length, pkt);
84 | _cookieData = new byte[_body.remaining()];
85 | _body.get(_cookieData);
86 | }
87 |
88 | public CookieEchoChunk() {
89 | super((byte)COOKIE_ECHO);
90 | }
91 | @Override
92 | public void validate() throws SctpPacketFormatException{
93 | if (_cookieData.length != Association.COOKIESIZE){
94 | throw new SctpPacketFormatException("cookie Echo wrong length for our association "+ _cookieData.length +" != "+ Association.COOKIESIZE);
95 | }
96 | }
97 |
98 | public void setCookieData(byte[] cd){
99 | _cookieData = cd;
100 | }
101 |
102 | public byte [] getCookieData(){
103 | return _cookieData;
104 | }
105 | @Override
106 | void putFixedParams(ByteBuffer ret) {
107 | Log.debug("cookie is "+_cookieData +"and buffer is "+ret);
108 | ret.put(_cookieData);
109 | }
110 |
111 |
112 | }
113 |
--------------------------------------------------------------------------------
/src/main/java/pe/pi/sctp4j/sctp/messages/ErrorChunk.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 pi.pe gmbh .
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 | */
17 | package pe.pi.sctp4j.sctp.messages;
18 |
19 | import pe.pi.sctp4j.sctp.messages.params.KnownError;
20 | import pe.pi.sctp4j.sctp.messages.params.VariableParam;
21 | import com.phono.srtplight.Log;
22 | import java.nio.ByteBuffer;
23 |
24 | /**
25 | *
26 | * @author Westhawk Ltd
27 | */
28 |
29 | /*
30 | 3.3.10. Operation Error (ERROR) (9)
31 |
32 | An endpoint sends this chunk to its peer endpoint to notify it of
33 | certain error conditions. It contains one or more error causes. An
34 | Operation Error is not considered fatal in and of itself, but may be
35 | used with an ABORT chunk to report a fatal condition. It has the
36 | following parameters:
37 |
38 | 0 1 2 3
39 | 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
40 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
41 | | Type = 9 | Chunk Flags | Length |
42 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
43 | \ \
44 | / one or more Error Causes /
45 | \ \
46 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
47 |
48 | Chunk Flags: 8 bits
49 |
50 | Set to 0 on transmit and ignored on receipt.
51 |
52 | Length: 16 bits (unsigned integer)
53 |
54 | Set to the size of the chunk in bytes, including the chunk header
55 | and all the Error Cause fields present.
56 | */
57 | public class ErrorChunk extends Chunk {
58 |
59 | public ErrorChunk() {
60 | super((byte) Chunk.ERROR);
61 | }
62 |
63 | public ErrorChunk(KnownError e) {
64 | this();
65 | _varList.add(e);
66 | }
67 |
68 | public ErrorChunk(KnownError[] el) {
69 | this();
70 | for (KnownError e : el) {
71 | _varList.add(e);
72 | }
73 | }
74 |
75 | public ErrorChunk(byte type, byte flags, int length, ByteBuffer pkt) {
76 | super(type, flags, length, pkt);
77 | if (_body.remaining() >= 4) {
78 | Log.verb("Error" + this.toString());
79 | while (_body.hasRemaining()) {
80 | VariableParam v = readErrorParam();
81 | _varList.add(v);
82 | }
83 | }
84 | }
85 |
86 | @Override
87 | void putFixedParams(ByteBuffer ret) {
88 |
89 | }
90 |
91 | }
92 |
--------------------------------------------------------------------------------
/src/main/java/pe/pi/sctp4j/sctp/messages/HeartBeatAckChunk.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 pi.pe gmbh .
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 | */
17 | package pe.pi.sctp4j.sctp.messages;
18 |
19 | import java.nio.ByteBuffer;
20 |
21 | /**
22 | *
23 | * @author Westhawk Ltd
24 | */
25 | public class HeartBeatAckChunk extends Chunk {
26 |
27 | public HeartBeatAckChunk() {
28 | super((byte) Chunk.HEARTBEAT_ACK);
29 | }
30 |
31 |
32 | @Override
33 | void putFixedParams(ByteBuffer ret) {
34 | // none.
35 | }
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/src/main/java/pe/pi/sctp4j/sctp/messages/HeartBeatChunk.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 pi.pe gmbh .
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 | */
17 | package pe.pi.sctp4j.sctp.messages;
18 |
19 | import com.phono.srtplight.Log;
20 | import pe.pi.sctp4j.sctp.messages.exceptions.SctpPacketFormatException;
21 | import pe.pi.sctp4j.sctp.messages.params.VariableParam;
22 | import java.nio.ByteBuffer;
23 |
24 | /**
25 | *
26 | * @author Westhawk Ltd
27 | */
28 | public class HeartBeatChunk extends Chunk {
29 |
30 | public HeartBeatChunk() throws SctpPacketFormatException {
31 | super((byte) HEARTBEAT);
32 | HeartbeatInfo req = new HeartbeatInfo(1, "HeartbeatInfo");
33 | String t = ""+ System.currentTimeMillis();
34 | req.setData(t.getBytes());
35 | Log.debug("adding "+req+" to "+this);
36 | _varList.add(req);
37 | validate();
38 | }
39 |
40 | public HeartBeatChunk(byte type, byte flags, int length, ByteBuffer pkt) {
41 | super(type, flags, length, pkt);
42 | if (_body.remaining() >= 4) {
43 | while (_body.hasRemaining()) {
44 | VariableParam v = readVariable();
45 | _varList.add(v);
46 | }
47 | }
48 | }
49 |
50 | @Override
51 | public void validate() throws SctpPacketFormatException {
52 | VariableParam hbd;
53 | if ((_varList == null) || (_varList.size() != 1)) {
54 | throw new SctpPacketFormatException("No (or too much content in this heartbeat packet");
55 | }
56 | hbd = _varList.get(0);
57 | if (!(hbd instanceof HeartbeatInfo)) {
58 | throw new SctpPacketFormatException("Expected a heartbeatinfo in this packet");
59 | }
60 | }
61 |
62 | public Chunk[] mkReply() {
63 | Chunk[] rep = new Chunk[1];
64 | HeartBeatAckChunk dub = new HeartBeatAckChunk();
65 | dub._varList = this._varList;
66 | rep[0] = dub;
67 | return rep;
68 | }
69 |
70 | @Override
71 | void putFixedParams(ByteBuffer ret) {
72 | // none
73 | }
74 |
75 | }
76 |
--------------------------------------------------------------------------------
/src/main/java/pe/pi/sctp4j/sctp/messages/InitAckChunk.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 pi.pe gmbh .
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 | */
17 | package pe.pi.sctp4j.sctp.messages;
18 |
19 | import pe.pi.sctp4j.sctp.messages.params.StateCookie;
20 | import pe.pi.sctp4j.sctp.messages.params.VariableParam;
21 | import com.phono.srtplight.Log;
22 | import java.nio.ByteBuffer;
23 |
24 | /**
25 | *
26 | * @author Westhawk Ltd
27 | */
28 |
29 | /*
30 |
31 | The format of the INIT ACK chunk is shown below:
32 |
33 | 0 1 2 3
34 | 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
35 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
36 | | Type = 2 | Chunk Flags | Chunk Length |
37 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
38 | | Initiate Tag |
39 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
40 | | Advertised Receiver Window Credit |
41 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
42 | | Number of Outbound Streams | Number of Inbound Streams |
43 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
44 | | Initial TSN |
45 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
46 | \ \
47 | / Optional/Variable-Length Parameters /
48 | \ \
49 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
50 | */
51 | public class InitAckChunk extends Chunk {
52 |
53 | int _initiateTag;
54 | long _adRecWinCredit;
55 | int _numOutStreams;
56 | int _numInStreams;
57 | long _initialTSN;
58 | private byte[] _cookie;
59 | private byte[] _supportedExtensions;
60 |
61 | public InitAckChunk() {
62 | super((byte) INITACK);
63 | }
64 |
65 | public int getInitiateTag() {
66 | return _initiateTag;
67 | }
68 |
69 | public void setInitiateTag(int v) {
70 | _initiateTag = v;
71 | }
72 |
73 | public long getAdRecWinCredit() {
74 | return _adRecWinCredit;
75 | }
76 |
77 | public void setAdRecWinCredit(int v) {
78 | _adRecWinCredit = v;
79 | }
80 |
81 | public int getNumOutStreams() {
82 | return _numOutStreams;
83 | }
84 |
85 | public void setNumOutStreams(int v) {
86 | _numOutStreams = v;
87 | }
88 |
89 | public int getNumInStreams() {
90 | return _numInStreams;
91 | }
92 |
93 | public void setNumInStreams(int v) {
94 | _numInStreams = v;
95 | }
96 |
97 | public long getInitialTSN() {
98 | return _initialTSN;
99 | }
100 |
101 | public void setInitialTSN(long v) {
102 | _initialTSN = v;
103 | }
104 |
105 | public byte[] getCookie() {
106 | return _cookie;
107 | }
108 |
109 | public void setCookie(byte[] v) {
110 | _cookie = v;
111 | }
112 |
113 | public InitAckChunk(byte type, byte flags, int length, ByteBuffer pkt) {
114 | super(type, flags, length, pkt);
115 | if (_body.remaining() >= 16) {
116 | _initiateTag = _body.getInt();
117 | _adRecWinCredit = getUnsignedInt(_body);
118 | _numOutStreams = _body.getChar();
119 | _numInStreams = _body.getChar();
120 | _initialTSN = getUnsignedInt(_body);
121 | Log.verb("Init Ack" + this.toString());
122 | while (_body.hasRemaining()) {
123 | VariableParam v = readVariable();
124 | _varList.add(v);
125 | }
126 |
127 | for (VariableParam v : _varList) {
128 | // now look for variables we are expecting...
129 | Log.verb("variable of type: " + v.getName() + " " + v.toString());
130 | if (v instanceof StateCookie) {
131 | _cookie = ((StateCookie) v).getData();
132 | } else {
133 | Log.verb("ignored variable of type: " + v.getName());
134 | }
135 | }
136 |
137 | }
138 | }
139 |
140 | public String toString() {
141 | String ret = super.toString();
142 | ret += " initiateTag : " + _initiateTag
143 | + " adRecWinCredit : " + _adRecWinCredit
144 | + " numOutStreams : " + _numOutStreams
145 | + " numInStreams : " + _numInStreams
146 | + " initialTSN : " + _initialTSN
147 | + ((_supportedExtensions == null) ? " no supported extensions" : " supported extensions are: " + chunksToNames(_supportedExtensions));
148 | ;
149 | return ret;
150 | }
151 |
152 | @Override
153 | void putFixedParams(ByteBuffer ret) {
154 | ret.putInt(_initiateTag);
155 | putUnsignedInt(ret, _adRecWinCredit);
156 | ret.putChar((char) _numOutStreams);
157 | ret.putChar((char) _numInStreams);
158 | putUnsignedInt(ret, _initialTSN);
159 | if (_cookie != null) {
160 | StateCookie sc = new StateCookie();
161 | sc.setData(_cookie);
162 | _varList.add(sc);
163 | }
164 | if (_supportedExtensions != null) {
165 | SupportedExtensions se = new SupportedExtensions();
166 | se.setData(_supportedExtensions);
167 | _varList.add(se);
168 | }
169 | }
170 |
171 | public byte[] getSupportedExtensions(byte[] v) {
172 | return _supportedExtensions;
173 | }
174 |
175 | public void setSupportedExtensions(byte[] v) {
176 | _supportedExtensions = v;
177 | }
178 |
179 | }
180 |
--------------------------------------------------------------------------------
/src/main/java/pe/pi/sctp4j/sctp/messages/InitChunk.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 pi.pe gmbh .
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 | */
17 | package pe.pi.sctp4j.sctp.messages;
18 |
19 | import pe.pi.sctp4j.sctp.messages.params.RequestedHMACAlgorithmParameter;
20 | import pe.pi.sctp4j.sctp.messages.params.VariableParam;
21 | import com.phono.srtplight.Log;
22 | import java.nio.ByteBuffer;
23 |
24 | /**
25 | *
26 | * @author tim
27 | */
28 | public class InitChunk extends Chunk {
29 | /*
30 | 0 1 2 3
31 | 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
32 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
33 | | Type = 1 | Chunk Flags | Chunk Length |
34 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
35 | | Initiate Tag |
36 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
37 | | Advertised Receiver Window Credit (a_rwnd) |
38 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
39 | | Number of Outbound Streams | Number of Inbound Streams |
40 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
41 | | Initial TSN |
42 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
43 | \ \
44 | / Optional/Variable-Length Parameters /
45 | \ \
46 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
47 | */
48 |
49 | long _initiateTag;
50 | long _adRecWinCredit;
51 | int _numOutStreams;
52 | int _numInStreams;
53 | long _initialTSN;
54 | byte [] _farSupportedExtensions;
55 | byte [] _farRandom;
56 | boolean _farForwardTSNsupported;
57 | byte[] _farHmacs;
58 | byte[] _farChunks;
59 | public int _outStreams;
60 |
61 | public InitChunk(){
62 | super((byte)INIT);
63 | }
64 |
65 | public InitChunk(byte type, byte flags, int length, ByteBuffer pkt) {
66 | super(type, flags, length, pkt);
67 | if (_body.remaining() >= 16) {
68 | _initiateTag = _body.getInt();
69 | _adRecWinCredit = getUnsignedInt(_body);
70 | _numOutStreams = _body.getChar();
71 | _numInStreams = _body.getChar();
72 | _initialTSN = getUnsignedInt(_body);
73 | Log.verb("Init " + this.toString());
74 | while (_body.hasRemaining()) {
75 | VariableParam v = readVariable();
76 | _varList.add(v);
77 | }
78 | for (VariableParam v : _varList){
79 | // now look for variables we are expecting...
80 | Log.verb("variable of type: "+v.getName()+" "+ v.toString());
81 | if (v instanceof SupportedExtensions){
82 | _farSupportedExtensions = ((SupportedExtensions)v).getData();
83 | } else if (v instanceof RandomParam){
84 | _farRandom = ((RandomParam)v).getData();
85 | } else if (v instanceof ForwardTSNsupported){
86 | _farForwardTSNsupported = true;
87 | } else if (v instanceof RequestedHMACAlgorithmParameter){
88 | _farHmacs = ((RequestedHMACAlgorithmParameter)v).getData();
89 | } else if (v instanceof ChunkListParam){
90 | _farChunks = ((ChunkListParam)v).getData();
91 | } else {
92 | Log.debug("unexpected variable of type: "+v.getName());
93 | }
94 | }
95 | }
96 | }
97 | public String toString() {
98 | String ret = super.toString();
99 | ret += " initiateTag : " + _initiateTag
100 | + " adRecWinCredit : " + _adRecWinCredit
101 | + " numOutStreams : " + _numOutStreams
102 | + " numInStreams : " + _numInStreams
103 | + " initialTSN : " + _initialTSN
104 | + " farForwardTSNsupported : "+_farForwardTSNsupported
105 | + ((_farSupportedExtensions == null) ?" no supported extensions": " supported extensions are: "+chunksToNames(_farSupportedExtensions));
106 | return ret;
107 | }
108 |
109 | @Override
110 | void putFixedParams(ByteBuffer ret) {
111 | ret.putInt((int)_initiateTag);
112 | putUnsignedInt(ret,_adRecWinCredit);
113 | ret.putChar((char) _numOutStreams);
114 | ret.putChar((char) _numInStreams);
115 | Chunk.putUnsignedInt(ret,_initialTSN);
116 | }
117 |
118 | public int getInitiateTag() {
119 | return (int)_initiateTag;
120 | }
121 |
122 | public long getAdRecWinCredit(){
123 | return _adRecWinCredit;
124 | }
125 | public int getNumOutStreams(){
126 | return _numOutStreams;
127 | }
128 | public int getNumInStreams(){
129 | return _numInStreams;
130 | }
131 | public long getInitialTSN(){
132 | return _initialTSN;
133 | }
134 | public void setInitialTSN(long tsn){
135 | _initialTSN = tsn;
136 | }
137 | public void setAdRecWinCredit(long credit){
138 | _adRecWinCredit = credit;
139 | }
140 | public void setNumOutStreams(int outn){
141 | _numOutStreams = outn;
142 | }
143 | public void setNumInStreams(int inn){
144 | _numInStreams = inn;
145 | }
146 | public byte [] getFarSupportedExtensions(){
147 | return _farSupportedExtensions;
148 | }
149 |
150 | public void setInitiate(long tag) {
151 | this._initiateTag = tag;
152 | }
153 |
154 |
155 | }
156 |
--------------------------------------------------------------------------------
/src/main/java/pe/pi/sctp4j/sctp/messages/ReConfigChunk.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 pi.pe gmbh .
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 | */
17 | package pe.pi.sctp4j.sctp.messages;
18 |
19 | import pe.pi.sctp4j.sctp.messages.params.AddIncomingStreamsRequestParameter;
20 | import pe.pi.sctp4j.sctp.messages.params.AddOutgoingStreamsRequestParameter;
21 | import pe.pi.sctp4j.sctp.messages.params.IncomingSSNResetRequestParameter;
22 | import pe.pi.sctp4j.sctp.messages.params.OutgoingSSNResetRequestParameter;
23 | import pe.pi.sctp4j.sctp.messages.params.ReconfigurationResponseParameter;
24 | import pe.pi.sctp4j.sctp.messages.params.VariableParam;
25 | import com.phono.srtplight.Log;
26 | import java.nio.ByteBuffer;
27 |
28 | /**
29 | *
30 | * @author thp
31 | */
32 | public class ReConfigChunk extends Chunk {
33 |
34 | private long sentAt;
35 | private int retries;
36 |
37 | public ReConfigChunk(byte type, byte flags, int length, ByteBuffer pkt) {
38 | super(type, flags, length, pkt);
39 | Log.debug("ReConfig chunk" + this.toString());
40 | if (_body.remaining() >= 4) {
41 | while (_body.hasRemaining()) {
42 | VariableParam v = this.readVariable();
43 | _varList.add(v);
44 | Log.debug("\tParam :" + v.toString());
45 | }
46 | }
47 | }
48 |
49 | public ReConfigChunk() {
50 | super((byte) Chunk.RE_CONFIG);
51 | }
52 |
53 | @Override
54 | void putFixedParams(ByteBuffer ret) {
55 | //throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
56 | }
57 |
58 | public boolean hasIncomingReset() {
59 | return _varList.stream().anyMatch((VariableParam v) -> {
60 | return v instanceof IncomingSSNResetRequestParameter;
61 | });
62 | }
63 |
64 | public IncomingSSNResetRequestParameter getIncomingReset() {
65 | return _varList.stream().filter((VariableParam v) -> {
66 | return v instanceof IncomingSSNResetRequestParameter;
67 | })
68 | .map((VariableParam v) -> {
69 | return (IncomingSSNResetRequestParameter) v;
70 | })
71 | .findFirst().orElse(null);
72 | }
73 |
74 | public boolean hasOutgoingReset() {
75 | return _varList.stream().anyMatch((VariableParam v) -> {
76 | return v instanceof OutgoingSSNResetRequestParameter;
77 | });
78 | }
79 |
80 | private boolean hasOutgoingAdd() {
81 | return _varList.stream().anyMatch((VariableParam v) -> {
82 | return v instanceof AddOutgoingStreamsRequestParameter;
83 | });
84 | }
85 |
86 | private boolean hasResponse() {
87 | return _varList.stream().anyMatch((VariableParam v) -> {
88 | return v instanceof ReconfigurationResponseParameter;
89 | });
90 | }
91 |
92 | public OutgoingSSNResetRequestParameter getOutgoingReset() {
93 | return _varList.stream().filter((VariableParam v) -> {
94 | return v instanceof OutgoingSSNResetRequestParameter;
95 | })
96 | .map((VariableParam v) -> {
97 | return (OutgoingSSNResetRequestParameter) v;
98 | })
99 | .findFirst().orElse(null);
100 | }
101 |
102 | public boolean hasParam() {
103 | return !_varList.isEmpty();
104 | }
105 |
106 | /*
107 | 1. Outgoing SSN Reset Request Parameter.
108 |
109 | 2. Incoming SSN Reset Request Parameter.
110 |
111 | 3. Outgoing SSN Reset Request Parameter, Incoming SSN Reset Request
112 | Parameter.
113 |
114 | 4. SSN/TSN Reset Request Parameter.
115 |
116 | 5. Add Outgoing Streams Request Parameter.
117 |
118 | 6. Add Incoming Streams Request Parameter.
119 |
120 | 7. Add Outgoing Streams Request Parameter, Add Incoming Streams
121 | Request Parameter.
122 |
123 | 8. Re-configuration Response Parameter.
124 |
125 | 9. Re-configuration Response Parameter, Outgoing SSN Reset Request
126 | Parameter.
127 |
128 | 10. Re-configuration Response Parameter, Re-configuration Response
129 | Parameter.
130 | */
131 | @Override
132 | public void validate() {
133 | if (_varList.size() < 1) {
134 | throw new IllegalArgumentException("Too few params " + _varList.size());
135 | }
136 | if (_varList.size() > 2) {
137 | throw new IllegalArgumentException("Too many params " + _varList.size());
138 | }
139 | // now check for invalid combos
140 | if ((_varList.size() == 2)) {
141 | if (this.hasOutgoingReset()) {
142 | VariableParam remain = _varList.stream().filter((VariableParam v) -> {
143 | return !(v instanceof OutgoingSSNResetRequestParameter);
144 | }).findFirst().orElse(null);
145 | if (remain == null) {
146 | throw new IllegalArgumentException("2 OutgoingSSNResetRequestParameter in one Chunk not allowed ");
147 | }
148 | if (!((remain instanceof IncomingSSNResetRequestParameter) //3
149 | || (remain instanceof ReconfigurationResponseParameter))) //9
150 | {
151 | throw new IllegalArgumentException("OutgoingSSNResetRequestParameter and " + remain.getClass().getSimpleName() + " in same Chunk not allowed ");
152 | }
153 | } else if (this.hasOutgoingAdd()) {
154 | VariableParam remain = _varList.stream().filter((VariableParam v) -> {
155 | return !(v instanceof AddOutgoingStreamsRequestParameter);
156 | }).findFirst().orElse(null);
157 | if (remain == null) {
158 | throw new IllegalArgumentException("2 AddOutgoingStreamsRequestParameter in one Chunk not allowed ");
159 | }
160 | if (!(remain instanceof AddIncomingStreamsRequestParameter)) //7
161 | {
162 | throw new IllegalArgumentException("OutgoingSSNResetRequestParameter and " + remain.getClass().getSimpleName() + " in same Chunk not allowed ");
163 | }
164 | } else if (this.hasResponse()) {
165 | VariableParam remain = _varList.stream().filter((VariableParam v) -> {
166 | return !(v instanceof ReconfigurationResponseParameter);
167 | }).findFirst().orElse(null);
168 | if (remain != null) { // 10
169 | throw new IllegalArgumentException("ReconfigurationResponseParameter and " + remain.getClass().getSimpleName() + " in same Chunk not allowed ");
170 | }
171 | }
172 | } // implicitly just one - which is ok 1,2,4,5,6,8
173 | }
174 |
175 | public void addParam(VariableParam rep) {
176 | Log.debug("adding "+rep+" to "+this);
177 | _varList.add(rep);
178 | validate();
179 | }
180 |
181 | public boolean sameAs(ReConfigChunk other) {
182 | // we ignore other var types for now....
183 | boolean ret = false; // assume the negative.
184 | if (other != null) {
185 | // if there are 2 params and both match
186 | if ((this.hasIncomingReset() && other.hasIncomingReset())
187 | && (this.hasOutgoingReset() && other.hasOutgoingReset())) {
188 | ret = this.getIncomingReset().sameAs(other.getIncomingReset())
189 | && this.getOutgoingReset().sameAs(other.getOutgoingReset());
190 | } else {
191 | // there is only one (of these) params
192 | // that has to match too
193 | if (this.hasIncomingReset() && other.hasIncomingReset()) {
194 | ret = this.getIncomingReset().sameAs(other.getIncomingReset());
195 | }
196 | if (this.hasOutgoingReset() && other.hasOutgoingReset()) {
197 | ret = this.getOutgoingReset().sameAs(other.getOutgoingReset());
198 | }
199 | }
200 | }
201 | return ret;
202 | }
203 | // stuff to manage outbound retries
204 | public long getSentTime(){
205 | return sentAt;
206 | }
207 | public void setSentTime(long now){
208 | sentAt = now;
209 | }
210 | public int getAndIncrementRetryCount(){
211 | return retries++;
212 | }
213 |
214 | }
215 |
--------------------------------------------------------------------------------
/src/main/java/pe/pi/sctp4j/sctp/messages/SackChunk.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 pi.pe gmbh .
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 | */
17 | package pe.pi.sctp4j.sctp.messages;
18 |
19 | import java.nio.ByteBuffer;
20 | import java.util.ArrayList;
21 |
22 | /**
23 | *
24 | * @author Westhawk Ltd
25 | */
26 | public class SackChunk extends Chunk {
27 |
28 | /**
29 | * @return the cumuTSNAck
30 | */
31 | public long getCumuTSNAck() {
32 | return _cumuTSNAck;
33 | }
34 |
35 | /**
36 | * @param cumuTSNAck the _cumuTSNAck to set
37 | */
38 | public void setCumuTSNAck(long cumuTSNAck) {
39 | _cumuTSNAck = cumuTSNAck;
40 | }
41 |
42 | /**
43 | * @return the _arWin
44 | */
45 | public long getArWin() {
46 | return _arWin;
47 | }
48 |
49 | /**
50 | * @param _arWin the _arWin to set
51 | */
52 | public void setArWin(long arWin) {
53 | _arWin = Math.max(arWin,0);
54 | }
55 | /*
56 |
57 | 0 1 2 3
58 | 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
59 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
60 | | Type = 3 |Chunk Flags | Chunk Length |
61 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
62 | | Cumulative TSN Ack |
63 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
64 | | Advertised Receiver Window Credit (a_rwnd) |
65 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
66 | | Number of Gap Ack Blocks = N | Number of Duplicate TSNs = X |
67 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
68 | | Gap Ack Block #1 Start | Gap Ack Block #1 End |
69 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
70 | / /
71 | \ ... \
72 | / /
73 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
74 | | Gap Ack Block #N Start | Gap Ack Block #N End |
75 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
76 | | Duplicate TSN 1 |
77 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
78 | / /
79 | \ ... \
80 | / /
81 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
82 | | Duplicate TSN X |
83 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
84 | */
85 |
86 |
87 |
88 | public class GapBlock {
89 | char _start;
90 | char _end;
91 | GapBlock(ByteBuffer b){
92 | _start = b.getChar();
93 | _end = b.getChar();
94 | }
95 | GapBlock(char start){
96 | _start = start;
97 | }
98 | void setEnd(char end){
99 | _end = end;
100 | }
101 |
102 | private void put(ByteBuffer b) {
103 | b.putChar(_start);
104 | b.putChar(_end);
105 | }
106 | public char getStart(){
107 | return _start;
108 | }
109 | public char getEnd(){
110 | return _end;
111 | }
112 | }
113 |
114 | GapBlock[] _gaps;
115 | long[] _duplicateTSNs;
116 | private long _cumuTSNAck;
117 | private long _arWin;
118 |
119 | public SackChunk(byte type, byte flags, int length, ByteBuffer pkt) {
120 | super(type, flags, length, pkt);
121 | _cumuTSNAck = Chunk.getUnsignedInt(_body);
122 | _arWin = Chunk.getUnsignedInt(_body);
123 | int ngaps = _body.getChar();
124 | int nDTSNs = _body.getChar();
125 | _gaps = new GapBlock[ngaps];
126 | _duplicateTSNs = new long[nDTSNs];
127 | for (int i=0;i dups) {
148 | _duplicateTSNs = new long[dups.size()];
149 | int i=0;
150 | for (Long du:dups){
151 | _duplicateTSNs[i++]= du.longValue();
152 | }
153 | }
154 |
155 | public void setGaps(ArrayList seenTsns){
156 | long cuTsn = _cumuTSNAck;
157 | ArrayList gaplist = new ArrayList();
158 | GapBlock currentGap = null;
159 | char prevoff = 0;
160 | for(Long t:seenTsns){
161 | char offs = (char) (t.longValue() - cuTsn);
162 | if (currentGap == null){
163 | currentGap = new GapBlock(offs);
164 | currentGap.setEnd(offs);
165 | gaplist.add(currentGap);
166 | } else {
167 | if (offs == prevoff +1){
168 | currentGap.setEnd(offs);
169 | } else {
170 | currentGap = new GapBlock(offs);
171 | currentGap.setEnd(offs);
172 | gaplist.add(currentGap);
173 | }
174 | }
175 | prevoff = offs;
176 | }
177 | _gaps = new GapBlock[gaplist.size()];
178 | int i=0;
179 | for (GapBlock g:gaplist){
180 | _gaps[i++] = g;
181 | }
182 | }
183 |
184 | @Override
185 | void putFixedParams(ByteBuffer ret) {
186 | Chunk.putUnsignedInt(ret, _cumuTSNAck);
187 | Chunk.putUnsignedInt(ret,_arWin);
188 | ret.putChar((char)_gaps.length);
189 | ret.putChar((char)_duplicateTSNs.length);
190 | for (int i=0;i<_gaps.length;i++){
191 | _gaps[i].put(ret);
192 | }
193 | for (int i=0;i<_duplicateTSNs.length;i++){
194 | Chunk.putUnsignedInt(ret,_duplicateTSNs[i]);
195 | }
196 | }
197 | public String toString(){
198 | StringBuffer ret= new StringBuffer("SACK cumuTSNAck="+_cumuTSNAck)
199 | .append(" _arWin="+_arWin)
200 | .append(" _gaps="+_gaps.length+" [");
201 | for (GapBlock g:_gaps){
202 | ret.append("\n\t{"+(int)g._start+","+(int)g._end+"}");
203 | }
204 | ret.append("]\n _duplicateTSNs="+_duplicateTSNs.length);
205 | for( long t:_duplicateTSNs){
206 | ret.append("\n\t"+t);
207 | }
208 | return ret.toString();
209 | }
210 | }
211 |
--------------------------------------------------------------------------------
/src/main/java/pe/pi/sctp4j/sctp/messages/exceptions/ChecksumException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 pi.pe gmbh .
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 | */
17 |
18 | package pe.pi.sctp4j.sctp.messages.exceptions;
19 |
20 | /**
21 | *
22 | * @author Westhawk Ltd
23 | */
24 | public class ChecksumException extends Exception {
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/src/main/java/pe/pi/sctp4j/sctp/messages/exceptions/InvalidDataChunkException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 pi.pe gmbh .
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 | */
17 |
18 | package pe.pi.sctp4j.sctp.messages.exceptions;
19 |
20 | /**
21 | *
22 | * @author Westhawk Ltd
23 | */
24 | public class InvalidDataChunkException extends Exception {
25 |
26 | public InvalidDataChunkException(String message) {
27 | super(message);
28 | }
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/src/main/java/pe/pi/sctp4j/sctp/messages/exceptions/InvalidSCTPPacketException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 pi.pe gmbh .
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 | */
17 |
18 | package pe.pi.sctp4j.sctp.messages.exceptions;
19 |
20 | /**
21 | *
22 | * @author Westhawk Ltd
23 | */
24 | public class InvalidSCTPPacketException extends Exception {
25 |
26 | public InvalidSCTPPacketException(String reason) {
27 | super(reason);
28 | }
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/src/main/java/pe/pi/sctp4j/sctp/messages/exceptions/MessageException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 pi.pe gmbh .
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 | */
17 |
18 | package pe.pi.sctp4j.sctp.messages.exceptions;
19 |
20 | /**
21 | *
22 | * @author Westhawk Ltd
23 | */
24 | public class MessageException extends Exception{
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/src/main/java/pe/pi/sctp4j/sctp/messages/exceptions/SctpPacketFormatException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 pi.pe gmbh .
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 | */
17 |
18 | package pe.pi.sctp4j.sctp.messages.exceptions;
19 |
20 | /**
21 | *
22 | * @author Westhawk Ltd
23 | */
24 | public class SctpPacketFormatException extends Exception {
25 |
26 | public SctpPacketFormatException(String message) {
27 | super(message);
28 | }
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/src/main/java/pe/pi/sctp4j/sctp/messages/exceptions/StaleCookieException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 pi.pe gmbh .
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 | */
17 | package pe.pi.sctp4j.sctp.messages.exceptions;
18 |
19 | /**
20 | *
21 | * @author Westhawk Ltd
22 | */
23 | public class StaleCookieException extends Exception {
24 |
25 | long _stale;
26 |
27 | public StaleCookieException(long howstale) {
28 | _stale = howstale;
29 | }
30 |
31 | public long getStale() {
32 | return _stale;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/main/java/pe/pi/sctp4j/sctp/messages/exceptions/UnreadyAssociationException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 pi.pe gmbh .
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 | */
17 |
18 | package pe.pi.sctp4j.sctp.messages.exceptions;
19 |
20 | /**
21 | *
22 | * @author Westhawk Ltd
23 | */
24 | public class UnreadyAssociationException extends Exception {
25 |
26 | public UnreadyAssociationException() {
27 | }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/pe/pi/sctp4j/sctp/messages/params/AddIncomingStreamsRequestParameter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 pi.pe gmbh .
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 | */
17 |
18 | package pe.pi.sctp4j.sctp.messages.params;
19 |
20 | /**
21 | *
22 | * @author tim
23 | */
24 | public class AddIncomingStreamsRequestParameter extends AddStreamsRequestParameter {
25 | public AddIncomingStreamsRequestParameter(int t, String n) {
26 | super(t, n);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/pe/pi/sctp4j/sctp/messages/params/AddOutgoingStreamsRequestParameter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 pi.pe gmbh .
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 | */
17 |
18 | package pe.pi.sctp4j.sctp.messages.params;
19 |
20 | /**
21 | *
22 | * @author tim
23 | */
24 | public class AddOutgoingStreamsRequestParameter extends AddStreamsRequestParameter {
25 |
26 | public AddOutgoingStreamsRequestParameter(int t, String n) {
27 | super(t, n);
28 | }
29 |
30 |
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/pe/pi/sctp4j/sctp/messages/params/AddStreamsRequestParameter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 pi.pe gmbh .
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 | */
17 | package pe.pi.sctp4j.sctp.messages.params;
18 |
19 | import pe.pi.sctp4j.sctp.messages.Chunk;
20 | import java.nio.ByteBuffer;
21 |
22 | /**
23 | *
24 | * @author tim
25 | */
26 | public class AddStreamsRequestParameter extends Unknown {
27 |
28 | public AddStreamsRequestParameter(int t, String n) {
29 | super(t, n);
30 | }
31 | /*
32 | 0 1 2 3
33 | 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
34 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
35 | | Parameter Type = 17 | Parameter Length = 12 |
36 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
37 | | Re-configuration Request Sequence Number |
38 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
39 | | Number of new streams | Reserved |
40 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
41 | */
42 |
43 | long reconfReqSeqNo;
44 | int numNewStreams;
45 | int reserved;
46 |
47 | @Override
48 | public void readBody(ByteBuffer body, int blen) {
49 | reconfReqSeqNo = Chunk.getUnsignedInt(body);
50 | numNewStreams = body.getChar();
51 | reserved = body.getChar();
52 | }
53 |
54 | @Override
55 | public void writeBody(ByteBuffer body) {
56 | Chunk.putUnsignedInt(body,reconfReqSeqNo);
57 | body.putChar((char) numNewStreams);
58 | body.putChar((char) reserved);
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/main/java/pe/pi/sctp4j/sctp/messages/params/CookiePreservative.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 pi.pe gmbh .
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 | */
17 |
18 | package pe.pi.sctp4j.sctp.messages.params;
19 |
20 | import pe.pi.sctp4j.sctp.messages.exceptions.SctpPacketFormatException;
21 | import java.nio.ByteBuffer;
22 |
23 | /**
24 | *
25 | * @author tim
26 | */
27 | public class CookiePreservative extends KnownParam {
28 | Long time ;
29 | public CookiePreservative(int t, String n) {
30 | super(t, n);
31 | }
32 | @Override
33 | public void readBody(ByteBuffer body, int blen) throws SctpPacketFormatException {
34 | int ctime = body.getInt();
35 | time = new Long(ctime);
36 | }
37 |
38 | @Override
39 | public void writeBody(ByteBuffer body) throws SctpPacketFormatException {
40 | body.putInt(time.intValue());
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/java/pe/pi/sctp4j/sctp/messages/params/HostNameAddress.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 pi.pe gmbh .
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 | */
17 | package pe.pi.sctp4j.sctp.messages.params;
18 |
19 | import java.nio.ByteBuffer;
20 |
21 | /**
22 | *
23 | * @author tim
24 | */
25 | public class HostNameAddress extends KnownParam {
26 |
27 | String hostname;
28 |
29 | public HostNameAddress(int t, String n) {
30 | super(t, n);
31 | }
32 |
33 | public void readBody(ByteBuffer body, int blen) {
34 | byte data[] = new byte[blen];
35 | body.get(data);
36 | int off = blen - 1;
37 | // trim any 0 bytes off the end.
38 | while ((off > 0) && (data[off--] == 0)) {
39 | blen--;
40 | }
41 | hostname = new String(data, 0, blen);
42 | }
43 | public void writeBody(ByteBuffer body) {
44 | // gonz up a C style string.
45 | byte [] b = hostname.getBytes();
46 | _data = new byte[b.length+1];
47 | System.arraycopy(b, 0, _data, 0, b.length);
48 | body.put(_data);
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/main/java/pe/pi/sctp4j/sctp/messages/params/IPv4Address.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 pi.pe gmbh .
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 | */
17 | package pe.pi.sctp4j.sctp.messages.params;
18 |
19 | import pe.pi.sctp4j.sctp.messages.exceptions.SctpPacketFormatException;
20 | import java.net.Inet4Address;
21 | import java.net.UnknownHostException;
22 | import java.nio.ByteBuffer;
23 |
24 | /**
25 | *
26 | * @author tim
27 | */
28 | public class IPv4Address extends KnownParam {
29 |
30 | Inet4Address addr;
31 |
32 | public IPv4Address(int t, String n) {
33 | super(t, n);
34 | }
35 |
36 | @Override
37 | public void readBody(ByteBuffer body, int blen) throws SctpPacketFormatException {
38 | byte[] data = new byte[blen];
39 | body.get(data);
40 | try {
41 | addr = (Inet4Address) Inet4Address.getByAddress(data);
42 | } catch (UnknownHostException ex) {
43 | throw new SctpPacketFormatException(ex.getMessage());
44 | }
45 | }
46 |
47 | @Override
48 | public void writeBody(ByteBuffer body) throws SctpPacketFormatException {
49 | body.put(addr.getAddress());
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/main/java/pe/pi/sctp4j/sctp/messages/params/IPv6Address.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 pi.pe gmbh .
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 | */
17 | package pe.pi.sctp4j.sctp.messages.params;
18 |
19 | import pe.pi.sctp4j.sctp.messages.exceptions.SctpPacketFormatException;
20 | import java.net.Inet6Address;
21 | import java.net.UnknownHostException;
22 | import java.nio.ByteBuffer;
23 |
24 | /**
25 | *
26 | * @author tim
27 | */
28 | public class IPv6Address extends KnownParam {
29 |
30 | Inet6Address addr;
31 |
32 | public IPv6Address(int t, String n) {
33 | super(t, n);
34 | }
35 |
36 | @Override
37 | public void readBody(ByteBuffer body, int blen) throws SctpPacketFormatException {
38 | byte[] data = new byte[blen];
39 | body.get(data);
40 | try {
41 | addr = (Inet6Address) Inet6Address.getByAddress(data);
42 | } catch (UnknownHostException ex) {
43 | throw new SctpPacketFormatException(ex.getMessage());
44 | }
45 | }
46 |
47 | @Override
48 | public void writeBody(ByteBuffer body) throws SctpPacketFormatException {
49 | body.put(addr.getAddress());
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/main/java/pe/pi/sctp4j/sctp/messages/params/IncomingSSNResetRequestParameter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 pi.pe gmbh .
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 | */
17 | package pe.pi.sctp4j.sctp.messages.params;
18 |
19 | import pe.pi.sctp4j.sctp.messages.Chunk;
20 | import com.phono.srtplight.Log;
21 | import java.nio.ByteBuffer;
22 |
23 | /**
24 | *
25 | * @author tim
26 | */
27 | public class IncomingSSNResetRequestParameter extends KnownParam {
28 |
29 | /*
30 | 0 1 2 3
31 | 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
32 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
33 | | Parameter Type = 14 | Parameter Length = 8 + 2 * N |
34 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
35 | | Re-configuration Request Sequence Number |
36 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
37 | | Stream Number 1 (optional) | Stream Number 2 (optional) |
38 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
39 | / ...... /
40 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
41 | | Stream Number N-1 (optional) | Stream Number N (optional) |
42 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
43 | */
44 | long reqSeqNo;
45 | int streams[];
46 |
47 | public IncomingSSNResetRequestParameter(int t, String n) {
48 | super(t, n);
49 | }
50 |
51 | public IncomingSSNResetRequestParameter() {
52 | super(14, "IncomingSSNResetRequestParameter");
53 | }
54 |
55 | public IncomingSSNResetRequestParameter(long reqNo) {
56 | this();
57 | this.reqSeqNo = reqNo;
58 | }
59 |
60 | @Override
61 | public void readBody(ByteBuffer body, int blen) {
62 | if (blen < 4) {
63 | Log.error("Huh ? No body to this " + this.getName());
64 | return;
65 | }
66 | reqSeqNo = Chunk.getUnsignedInt(body);
67 | if (blen > 4) {
68 | this.streams = new int[(blen - 4) / 2];
69 | for (int i = 0; i < streams.length; i++) {
70 | streams[i] = body.getChar();
71 | }
72 | } else {
73 | this.streams = new int[0];
74 | Log.warn("No inbound stream mentioned");
75 | }
76 | }
77 |
78 | @Override
79 | public void writeBody(ByteBuffer body) {
80 | Chunk.putUnsignedInt(body, reqSeqNo);
81 | if (streams != null) {
82 | for (int i = 0; i < streams.length; i++) {
83 | body.putChar((char) streams[i]);
84 | }
85 | }
86 | }
87 |
88 | @Override
89 | public String toString() {
90 | StringBuffer ret = new StringBuffer();
91 | ret.append(this.getClass().getSimpleName()).append(" ");
92 | ret.append("seq:" + this.reqSeqNo);
93 | if (streams != null) {
94 | ret.append("streams {");
95 | for (int s : streams) {
96 | ret.append("" + s);
97 | }
98 | ret.append("}");
99 | } else {
100 | ret.append("no streams");
101 | }
102 | return ret.toString();
103 | }
104 |
105 | public boolean sameAs(IncomingSSNResetRequestParameter other) {
106 | return this.reqSeqNo == other.reqSeqNo;
107 | }
108 |
109 | public int[] getStreams() {
110 | return streams;
111 | }
112 |
113 | public long getReqNo() {
114 | return this.reqSeqNo;
115 | }
116 | public void setStreams(int[] ss) {
117 | this.streams =ss;
118 | }
119 | }
120 |
--------------------------------------------------------------------------------
/src/main/java/pe/pi/sctp4j/sctp/messages/params/KnownError.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 pi.pe gmbh .
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 | */
17 |
18 | package pe.pi.sctp4j.sctp.messages.params;
19 |
20 | import pe.pi.sctp4j.sctp.messages.Packet;
21 |
22 | /**
23 | *
24 | * @author tim
25 | */
26 | public class KnownError extends Unknown {
27 |
28 | public KnownError(int t, String n) {
29 | super(t, n);
30 | }
31 |
32 | public byte[] getData(){
33 | return _data;
34 | }
35 | public void setData(byte [] data){
36 | _data = data;
37 | }
38 | @Override
39 | public String toString(){
40 | return "Variable error "+this.getName() + " data "+new String(_data) + " "+ Packet.getHex(_data);
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/java/pe/pi/sctp4j/sctp/messages/params/KnownParam.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 pi.pe gmbh .
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 | */
17 |
18 | package pe.pi.sctp4j.sctp.messages.params;
19 |
20 | /**
21 | *
22 | * @author tim
23 | */
24 | public class KnownParam extends Unknown {
25 |
26 | public KnownParam(int t, String n) {
27 | super(t, n);
28 | }
29 |
30 | public byte[] getData(){
31 | return _data;
32 | }
33 | public void setData(byte [] data){
34 | _data = data;
35 | }
36 | @Override
37 | public String toString(){
38 | return "Variable param "+this.getName();
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/main/java/pe/pi/sctp4j/sctp/messages/params/OutgoingSSNResetRequestParameter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 pi.pe gmbh .
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 | */
17 | package pe.pi.sctp4j.sctp.messages.params;
18 |
19 | import pe.pi.sctp4j.sctp.messages.Chunk;
20 | import java.nio.ByteBuffer;
21 |
22 | /**
23 | *
24 | * @author tim
25 | */
26 | public class OutgoingSSNResetRequestParameter extends KnownParam {
27 |
28 |
29 |
30 | /*
31 | 0 1 2 3
32 | 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
33 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
34 | | Parameter Type = 13 | Parameter Length = 16 + 2 * N |
35 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
36 | | Re-configuration Request Sequence Number |
37 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
38 | | Re-configuration Response Sequence Number |
39 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
40 | | Sender's Last Assigned TSN |
41 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
42 | | Stream Number 1 (optional) | Stream Number 2 (optional) |
43 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
44 | / ...... /
45 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
46 | | Stream Number N-1 (optional) | Stream Number N (optional) |
47 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
48 | */
49 | long reqSeqNo;
50 | long respSeqNo;
51 | long lastTsn;
52 | int streams[];
53 |
54 | public OutgoingSSNResetRequestParameter(int t, String n) {
55 | super(t, n);
56 | }
57 | public OutgoingSSNResetRequestParameter() {
58 | super(13, "OutgoingSSNResetRequestParameter");
59 | }
60 | public OutgoingSSNResetRequestParameter(long reqNo,long respNo, long lastTsn) {
61 | this();
62 | this.respSeqNo = respNo;
63 | this.lastTsn = lastTsn;
64 | this.reqSeqNo = reqNo;
65 | }
66 |
67 | public long getRespSeqNo() {
68 | return respSeqNo;
69 | }
70 |
71 | public long getReqSeqNo() {
72 | return reqSeqNo;
73 | }
74 |
75 | @Override
76 | public void readBody(ByteBuffer body, int blen) {
77 | reqSeqNo = Chunk.getUnsignedInt(body);
78 | respSeqNo = Chunk.getUnsignedInt(body);
79 | lastTsn = Chunk.getUnsignedInt(body);
80 | streams = new int[(blen - 12) / 2];
81 | for (int i = 0; i < streams.length; i++) {
82 | streams[i] = body.getChar();
83 | }
84 | }
85 |
86 | @Override
87 | public void writeBody(ByteBuffer body) {
88 | Chunk.putUnsignedInt(body, reqSeqNo);
89 | Chunk.putUnsignedInt(body, respSeqNo);
90 | Chunk.putUnsignedInt(body, lastTsn);
91 | if (streams != null) {
92 | for (int i = 0; i < streams.length; i++) {
93 | body.putChar((char) streams[i]);
94 | }
95 | }
96 | }
97 |
98 | @Override
99 | public String toString() {
100 | StringBuffer ret = new StringBuffer();
101 | ret.append(this.getClass().getSimpleName()).append(" ");
102 | ret.append("reqseq:").append(this.reqSeqNo).append(" ");
103 | ret.append("respseq:").append(this.respSeqNo).append(" ");
104 | ret.append("latsTSN:").append(this.lastTsn).append(" ");
105 |
106 | if (streams != null) {
107 | ret.append("streams {");
108 | for (int s : streams) {
109 | ret.append("" + s);
110 | }
111 | ret.append("}");
112 | } else {
113 | ret.append("no streams");
114 | }
115 | return ret.toString();
116 | }
117 |
118 | public long getLastAssignedTSN() {
119 | return lastTsn;
120 | }
121 |
122 | public int[] getStreams() {
123 | return streams;
124 | }
125 | public void setStreams(int[] ss) {
126 | this.streams =ss;
127 | }
128 |
129 | public boolean sameAs(OutgoingSSNResetRequestParameter other) {
130 | return this.reqSeqNo == other.reqSeqNo;
131 | }
132 | }
133 |
--------------------------------------------------------------------------------
/src/main/java/pe/pi/sctp4j/sctp/messages/params/ProtocolViolationError.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 pi.pe gmbh .
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 | */
17 |
18 | package pe.pi.sctp4j.sctp.messages.params;
19 |
20 | /**
21 | *
22 | * @author Westhawk Ltd
23 | */
24 | public class ProtocolViolationError extends KnownError {
25 |
26 | public ProtocolViolationError(int t, String n) {
27 | super(t, n);
28 | }
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/src/main/java/pe/pi/sctp4j/sctp/messages/params/ReconfigurationResponseParameter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 pi.pe gmbh .
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 | */
17 | package pe.pi.sctp4j.sctp.messages.params;
18 |
19 | import pe.pi.sctp4j.sctp.messages.Chunk;
20 | import java.nio.ByteBuffer;
21 |
22 | /**
23 | *
24 | * @author tim
25 | */
26 | public class ReconfigurationResponseParameter extends KnownParam {
27 |
28 | /*
29 | 0 1 2 3
30 | 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
31 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
32 | | Parameter Type = 16 | Parameter Length |
33 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
34 | | Re-configuration Response Sequence Number |
35 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
36 | | Result |
37 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
38 | | Sender's Next TSN (optional) |
39 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
40 | | Receiver's Next TSN (optional) |
41 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
42 | */
43 | long seqNo;
44 | long result;
45 | long senderNextTSN;
46 | long receiverNextTSN;
47 | boolean hasTSNs;
48 | public final static int SUCCESS_NOTHING_TO_DO = 0;
49 | public final static int SUCCESS_PERFORMED = 1;
50 | public final static int DENIED = 2;
51 | public final static int ERROR_WRONG_SSN = 3;
52 | public final static int ERROR_REQUEST_ALREADY_IN_PROGESS = 4;
53 | public final static int ERROR_BAD_SEQUENCE_NUMBER = 5;
54 | public final static int IN_PROGRESS = 6;
55 | final static String valuenames[] = {
56 | "Success - Nothing to do",
57 | "Success - Performed",
58 | "Denied",
59 | "Error - Wrong SSN",
60 | "Error - Request already in progress",
61 | "Error - Bad Sequence Number",
62 | "In progress"
63 | };
64 |
65 | /*
66 | +--------+-------------------------------------+
67 | | Result | Description |
68 | +--------+-------------------------------------+
69 | | 0 | Success - Nothing to do |
70 | | 1 | Success - Performed |
71 | | 2 | Denied |
72 | | 3 | Error - Wrong SSN |
73 | | 4 | Error - Request already in progress |
74 | | 5 | Error - Bad Sequence Number |
75 | | 6 | In progress |
76 | +--------+-------------------------------------+
77 | */
78 | public ReconfigurationResponseParameter(int t, String n) {
79 | super(t, n);
80 | }
81 |
82 | public ReconfigurationResponseParameter() {
83 | this(16, "ReconfigurationResponseParameter");
84 | }
85 |
86 | @Override
87 | public void readBody(ByteBuffer body, int blen) {
88 | this.seqNo = Chunk.getUnsignedInt(body);
89 | this.result = Chunk.getUnsignedInt(body);
90 | if (blen == 16) {
91 | this.senderNextTSN = Chunk.getUnsignedInt(body);
92 | this.receiverNextTSN = Chunk.getUnsignedInt(body);
93 | hasTSNs = true;
94 | }
95 | }
96 |
97 | @Override
98 | public void writeBody(ByteBuffer body) {
99 | Chunk.putUnsignedInt(body, seqNo);
100 | Chunk.putUnsignedInt(body, result);
101 | if (hasTSNs) {
102 | Chunk.putUnsignedInt(body, senderNextTSN);
103 | Chunk.putUnsignedInt(body, receiverNextTSN);
104 | }
105 | }
106 |
107 | private String resultToName() {
108 | return ((result >= 0) && (result < valuenames.length))
109 | ? valuenames[(int) result] : "invalid value";
110 | }
111 |
112 | public String toString() {
113 | StringBuffer ret = new StringBuffer();
114 | ret.append(this.getClass().getSimpleName()).append(" ");
115 | ret.append("seqNo:").append(this.seqNo).append(" ");
116 | ret.append("result:").append(resultToName()).append(" ");
117 | if (hasTSNs) {
118 | ret.append("senderNextTSN:").append(this.senderNextTSN).append(" ");
119 | ret.append("receiverNextTSN:").append(this.receiverNextTSN).append(" ");
120 | }
121 | return ret.toString();
122 | }
123 |
124 | public void setResult(int res) {
125 | result = res;
126 | }
127 |
128 | public void setSeq(long reqSeqNo) {
129 | seqNo = reqSeqNo;
130 | }
131 |
132 | }
133 |
--------------------------------------------------------------------------------
/src/main/java/pe/pi/sctp4j/sctp/messages/params/RequestedHMACAlgorithmParameter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 pi.pe gmbh .
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 | */
17 | package pe.pi.sctp4j.sctp.messages.params;
18 |
19 | import java.nio.ByteBuffer;
20 |
21 | /**
22 | *
23 | * @author tim
24 | */
25 | public class RequestedHMACAlgorithmParameter extends KnownParam {
26 | /*
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 | | Parameter Type = 0x8004 | Parameter Length |
32 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
33 | | HMAC Identifier 1 | HMAC Identifier 2 |
34 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
35 | / /
36 | \ ... \
37 | / /
38 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
39 | | HMAC Identifier n | Padding |
40 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
41 | */
42 |
43 | int hmacs[];
44 | /*
45 | +-----------------+--------------------------+
46 | | HMAC Identifier | Message Digest Algorithm |
47 | +-----------------+--------------------------+
48 | | 0 | Reserved |
49 | | 1 | SHA-1 defined in [8] |
50 | | 2 | Reserved |
51 | | 3 | SHA-256 defined in [8] |
52 | +-----------------+--------------------------+
53 | */
54 |
55 | public RequestedHMACAlgorithmParameter(int t, String n) {
56 | super(t, n);
57 | }
58 |
59 | public void readBody(ByteBuffer body, int blen) {
60 | hmacs = new int[blen / 2];
61 | for (int i = 0; i < hmacs.length; i++) {
62 | hmacs[i] = body.getChar();
63 | }
64 | }
65 |
66 | public void writeBody(ByteBuffer body) {
67 | if (hmacs != null) {
68 | for (int i = 0; i < hmacs.length; i++) {
69 | body.putChar((char) hmacs[i]);
70 | }
71 | }
72 | }
73 |
74 | public String toString() {
75 | String ret = " Hmacs are ";
76 | for (int i = 0; i < hmacs.length; i++) {
77 | switch (hmacs[i]) {
78 | case 0:
79 | case 2:
80 | ret += " Reserved ";
81 | break;
82 | case 1:
83 | ret += " SHA-1 ";
84 | break;
85 | case 3:
86 | ret += " SHA-256 ";
87 | break;
88 | }
89 | }
90 | return super.toString() + ret;
91 | }
92 |
93 | public boolean doesSha256() {
94 | boolean ret = false;
95 | for (int i = 0; i < hmacs.length; i++) {
96 | if (3 == hmacs[i]) {
97 | ret = true;
98 | }
99 | }
100 | return ret;
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/src/main/java/pe/pi/sctp4j/sctp/messages/params/SSNTSNResetRequestParameter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 pi.pe gmbh .
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 | */
17 |
18 | package pe.pi.sctp4j.sctp.messages.params;
19 |
20 | import pe.pi.sctp4j.sctp.messages.Chunk;
21 | import pe.pi.sctp4j.sctp.messages.exceptions.SctpPacketFormatException;
22 | import java.nio.ByteBuffer;
23 |
24 | /**
25 | *
26 | * @author tim
27 | */
28 | public class SSNTSNResetRequestParameter extends Unknown {
29 |
30 | long _seqno;
31 | public SSNTSNResetRequestParameter(int t, String n) {
32 | super(t, n);
33 | }
34 | /*
35 | 0 1 2 3
36 | 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
37 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
38 | | Parameter Type = 15 | Parameter Length = 8 |
39 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
40 | | Re-configuration Request Sequence Number |
41 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
42 | */
43 | @Override
44 | public void readBody(ByteBuffer body, int blen) throws SctpPacketFormatException {
45 | _seqno = Chunk.getUnsignedInt(body);
46 | }
47 | @Override
48 | public void writeBody(ByteBuffer body) throws SctpPacketFormatException {
49 | Chunk.putUnsignedInt(body, _seqno);
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/main/java/pe/pi/sctp4j/sctp/messages/params/StaleCookieError.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 pi.pe gmbh .
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 | */
17 | package pe.pi.sctp4j.sctp.messages.params;
18 |
19 | import pe.pi.sctp4j.sctp.messages.Chunk;
20 | import java.nio.ByteBuffer;
21 |
22 | /**
23 | *
24 | * @author Westhawk Ltd
25 | */
26 | public class StaleCookieError extends KnownError {
27 | private long _measure;
28 | /*
29 |
30 | Stale Cookie Error (3)
31 |
32 | Cause of error
33 | --------------
34 |
35 | Stale Cookie Error: Indicates the receipt of a valid State Cookie
36 | that has expired.
37 |
38 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
39 | | Cause Code=3 | Cause Length=8 |
40 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
41 | | Measure of Staleness (usec.) |
42 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
43 |
44 | Measure of Staleness: 32 bits (unsigned integer)
45 |
46 | This field contains the difference, in microseconds, between the
47 | current time and the time the State Cookie expired.
48 |
49 | The sender of this error cause MAY choose to report how long past
50 | expiration the State Cookie is by including a non-zero value in
51 | the Measure of Staleness field. If the sender does not wish to
52 | provide this information, it should set the Measure of Staleness
53 | field to the value of zero.
54 |
55 | */
56 |
57 | public StaleCookieError() {
58 | super(3, "StaleCookieError");
59 | }
60 |
61 | @Override
62 | public void readBody(ByteBuffer body, int blen) {
63 | _measure = Chunk.getUnsignedInt(body);
64 | }
65 |
66 |
67 | @Override
68 | public void writeBody(ByteBuffer body) {
69 | Chunk.putUnsignedInt(body,_measure);
70 | }
71 |
72 | public long getMeasure(){
73 | return _measure;
74 | }
75 |
76 | public void setMeasure(long mes){
77 | _measure = mes;
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/src/main/java/pe/pi/sctp4j/sctp/messages/params/StateCookie.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 pi.pe gmbh .
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 | */
17 | package pe.pi.sctp4j.sctp.messages.params;
18 |
19 | /**
20 | *
21 | * @author tim
22 | */
23 | public class StateCookie extends KnownParam {
24 |
25 | public StateCookie() {
26 | this(7, "StateCookie");
27 | }
28 |
29 | public StateCookie(int t, String n) {
30 | super(t, n);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/pe/pi/sctp4j/sctp/messages/params/SupportedAddressTypes.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 pi.pe gmbh .
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 | */
17 | package pe.pi.sctp4j.sctp.messages.params;
18 |
19 | import java.nio.ByteBuffer;
20 |
21 | /**
22 | *
23 | * @author tim
24 | */
25 | public class SupportedAddressTypes extends KnownParam {
26 |
27 | int supported[];
28 |
29 | public SupportedAddressTypes(int t, String n) {
30 | super(t, n);
31 | }
32 |
33 | public void readBody(ByteBuffer body, int blen) {
34 | supported = new int[blen / 2];
35 | for (int i = 0; i < supported.length; i++) {
36 | supported[i] = body.getChar();
37 | }
38 | }
39 |
40 | public void writeBody(ByteBuffer body) {
41 | if (supported != null) {
42 | for (int i = 0; i < supported.length; i++) {
43 | body.putChar((char) supported[i]);
44 | }
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/main/java/pe/pi/sctp4j/sctp/messages/params/Unknown.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 pi.pe gmbh .
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 | */
17 | package pe.pi.sctp4j.sctp.messages.params;
18 |
19 | import pe.pi.sctp4j.sctp.messages.exceptions.SctpPacketFormatException;
20 | import java.nio.ByteBuffer;
21 |
22 | /**
23 | *
24 | * @author tim
25 | */
26 | public class Unknown implements VariableParam {
27 |
28 | byte _data[];
29 | final int _type;
30 | final String _name;
31 |
32 | public Unknown(int t,String n){
33 | _type = t;
34 | _name = n;
35 | }
36 |
37 | @Override
38 | public void readBody(ByteBuffer b, int len) throws SctpPacketFormatException {
39 | _data = new byte[len];
40 | b.get(_data);
41 | }
42 |
43 | @Override
44 | public void writeBody(ByteBuffer b) throws SctpPacketFormatException {
45 | b.put(this._data);
46 | }
47 |
48 | @Override
49 | public int getType() {
50 | return _type;
51 | }
52 |
53 | @Override
54 | public String getName() {
55 | return _name;
56 | }
57 |
58 | }
59 |
--------------------------------------------------------------------------------
/src/main/java/pe/pi/sctp4j/sctp/messages/params/UnrecognizedParameters.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 pi.pe gmbh .
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 | */
17 |
18 | package pe.pi.sctp4j.sctp.messages.params;
19 |
20 | import pe.pi.sctp4j.sctp.messages.params.Unknown;
21 |
22 | /**
23 | *
24 | * @author tim
25 | */
26 | public class UnrecognizedParameters extends KnownParam {
27 |
28 | public UnrecognizedParameters(int t, String n) {
29 | super(t, n);
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/pe/pi/sctp4j/sctp/messages/params/VariableParam.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 pi.pe gmbh .
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 | */
17 |
18 | package pe.pi.sctp4j.sctp.messages.params;
19 |
20 | import pe.pi.sctp4j.sctp.messages.exceptions.SctpPacketFormatException;
21 | import java.nio.ByteBuffer;
22 |
23 | /**
24 | *
25 | * @author tim
26 | */
27 | public interface VariableParam {
28 | public void readBody(ByteBuffer b, int len) throws SctpPacketFormatException;
29 | public void writeBody(ByteBuffer b) throws SctpPacketFormatException;
30 |
31 | public int getType();
32 |
33 | public String getName();
34 | }
35 |
--------------------------------------------------------------------------------
/src/main/java/pe/pi/sctp4j/sctp/small/BlockingSCTPStream.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 pi.pe gmbh .
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 | */
17 | package pe.pi.sctp4j.sctp.small;
18 |
19 | import pe.pi.sctp4j.sctp.SCTPMessage;
20 | import pe.pi.sctp4j.sctp.SCTPStream;
21 | import pe.pi.sctp4j.sctp.messages.DataChunk;
22 | import java.util.HashMap;
23 | import java.util.concurrent.Executors;
24 | import pe.pi.sctp4j.sctp.dataChannel.DECP.DCOpen;
25 | import com.phono.srtplight.Log;
26 | import java.util.concurrent.ExecutorService;
27 |
28 | /**
29 | *
30 | * @author Westhawk Ltd
31 | */
32 | public class BlockingSCTPStream extends SCTPStream {
33 |
34 | private HashMap undeliveredOutboundMessages = new HashMap();
35 | private final ThreadedAssociation _ta;
36 | private final ExecutorService _ex;
37 |
38 | BlockingSCTPStream(ThreadedAssociation a, Integer id) {
39 | super(a, id);
40 | _ex = Executors.newSingleThreadExecutor((Runnable r) -> new Thread(r, "Stream-" + id + "-Exec"));
41 | _ta = a;
42 | }
43 |
44 | @Override
45 | synchronized public void send(String message) throws Exception {
46 | SCTPMessage m = _ta.makeMessage(message, this);
47 | undeliveredOutboundMessages.put(m.getSeq(), m);
48 | _ta.sendAndBlock(m);
49 | }
50 |
51 | @Override
52 | synchronized public void send(byte[] message) throws Exception {
53 | SCTPMessage m = _ta.makeMessage(message, this);
54 | undeliveredOutboundMessages.put(m.getSeq(), m);
55 | _ta.sendAndBlock(m);
56 | }
57 |
58 | @Override
59 | public void send(DCOpen message) throws Exception {
60 | SCTPMessage m = _ta.makeMessage(message, this);
61 | undeliveredOutboundMessages.put(m.getSeq(), m);
62 | Log.debug("About to send message for dcep size is " + m.getData().length);
63 | _ta.sendAndBlock(m);
64 | }
65 |
66 | @Override
67 | public void deliverMessage(SCTPMessage message) {
68 | _ex.execute(message);
69 | }
70 |
71 | @Override
72 | protected void alOnDCEPStream(SCTPStream _stream, String label, int _pPid) throws Exception {
73 | _ex.execute(() -> {
74 | try {
75 | super.alOnDCEPStream(_stream, label, _pPid);
76 | } catch (Exception ex) {
77 | Log.error("can't notify DCEPStream " + ex.getMessage());
78 | }
79 | });
80 | }
81 |
82 | @Override
83 | public void delivered(DataChunk d) {
84 | int f = d.getFlags();
85 | if ((f & DataChunk.ENDFLAG) > 0) {
86 | int ssn = d.getSSeqNo();
87 | SCTPMessage st = undeliveredOutboundMessages.remove(ssn);
88 | if (st != null) {
89 | st.acked();
90 | }
91 | }
92 | }
93 |
94 | @Override
95 | public boolean idle() {
96 | return undeliveredOutboundMessages.isEmpty();
97 | }
98 |
99 | @Override
100 | public void close() throws Exception {
101 | super.close();
102 | if ((_ex != null) && (!_ex.isShutdown())) {
103 | _ex.shutdownNow();
104 | Log.debug("shutdown of Stream-" + this.getNum() + "-Exec");
105 | }
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/src/main/java/pe/pi/sctp4j/sctp/small/MessageSizeExceededException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 pi.pe gmbh .
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 | */
17 |
18 | package pe.pi.sctp4j.sctp.small;
19 |
20 | /**
21 | *
22 | * @author Westhawk Ltd
23 | */
24 | class MessageSizeExceededException extends Exception {
25 |
26 | public MessageSizeExceededException() {
27 | }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/pe/pi/sctp4j/sctp/small/SimpleSCTPTimer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 pi.pe gmbh .
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 | */
17 | package pe.pi.sctp4j.sctp.small;
18 |
19 | import com.phono.srtplight.Log;
20 | import java.util.Timer;
21 | import java.util.TimerTask;
22 |
23 | /**
24 | *
25 | * @author tim Only one queued invocation. New requests replace queued ones if
26 | * they are earlier.
27 | */
28 | abstract class SimpleSCTPTimer {
29 |
30 | protected static Timer _timer = new Timer("SCTPTimer", true);
31 | static int tno = 1;
32 | long scheduledAt = Long.MAX_VALUE;
33 | TimerTask task = null;
34 |
35 | public abstract void tick();
36 |
37 | public void setNextRun(long by) {
38 | long now = System.currentTimeMillis();
39 | long when = now + by;
40 | if (when < scheduledAt) {
41 | if (task != null) {
42 | task.cancel();
43 | Log.verb("cancelled future task scheduled for " + scheduledAt + " because new task at " + when);
44 | }
45 | task = new TimerTask() {
46 | @Override
47 | public void run() {
48 | try {
49 | Log.verb("running task");
50 | tick();
51 | scheduledAt = Long.MAX_VALUE;
52 | } catch (Throwable t) {
53 | Log.error("SCTPTimerTask threw Exception " + t);
54 | if (Log.getLevel() >= Log.DEBUG) {
55 | t.printStackTrace();
56 | }
57 | }
58 | }
59 | };
60 | _timer.schedule(task, by);
61 | Log.verb("SCTPTimer task now scheduled at " + when);
62 | scheduledAt = when;
63 | } else {
64 | Log.verb ("already have a task scheduled for "+scheduledAt+" which is earlier than "+when);
65 | }
66 | }
67 |
68 | }
69 |
--------------------------------------------------------------------------------
/src/main/java/pe/pi/sctp4j/sctp/small/UDPForwardingStream.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 pi.pe gmbh .
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 | */
17 | package pe.pi.sctp4j.sctp.small;
18 |
19 | import pe.pi.sctp4j.sctp.Association;
20 | import pe.pi.sctp4j.sctp.behave.SCTPStreamBehaviour;
21 | import pe.pi.sctp4j.sctp.behave.UnorderedStreamBehaviour;
22 | import com.phono.srtplight.Log;
23 | import java.net.DatagramPacket;
24 | import java.net.DatagramSocket;
25 | import java.net.InetSocketAddress;
26 | import java.net.SocketAddress;
27 | import java.net.SocketException;
28 | import java.net.SocketTimeoutException;
29 |
30 | /**
31 | *
32 | * @author tim
33 | */
34 | public class UDPForwardingStream extends BlockingSCTPStream implements Runnable {
35 |
36 | DatagramSocket _udpSock;
37 | private final Thread _rcv;
38 |
39 | public UDPForwardingStream(Association a, Integer id, Integer toPort) throws SocketException {
40 | super((ThreadedAssociation)a, id);
41 | _udpSock = new DatagramSocket();
42 | SocketAddress addr = new InetSocketAddress("localhost", toPort.shortValue());
43 | _udpSock.bind(addr);
44 | _rcv = new Thread(this, "UDPForwarding_rcv");
45 | _rcv.start();
46 | SCTPStreamBehaviour behave = mkBehave();
47 | super.setBehave(behave);
48 | }
49 |
50 | @Override
51 | public void run() {
52 | try {
53 | _udpSock.setSoTimeout(1000);
54 | byte buff[] = new byte[4096];
55 | DatagramPacket dgp = new DatagramPacket(buff, buff.length);
56 | while (_rcv != null) {
57 | try {
58 | _udpSock.receive(dgp);
59 | int l = dgp.getLength();
60 | if (l > buff.length) {
61 | Log.warn("truncated packet from " + _udpSock.getRemoteSocketAddress().toString());
62 | l = buff.length;
63 | }
64 | byte pkt[] = new byte[l];
65 | System.arraycopy(buff, 0, pkt, 0, l);
66 | send(pkt);
67 | } catch (SocketTimeoutException stx) {
68 | ; // ignore - lets us check for close....
69 | }
70 | }
71 | } catch (Exception x) {
72 |
73 | }
74 | // clean up here.....
75 | }
76 |
77 |
78 | private SCTPStreamBehaviour mkBehave() {
79 | return new UnorderedStreamBehaviour();
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/src/test/java/pe/pi/sctp4j/sctp/SCTPMessageTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 pi.pe gmbh .
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 | */
17 | package pe.pi.sctp4j.sctp;
18 |
19 | import pe.pi.sctp4j.sctp.messages.*;
20 | import pe.pi.sctp4j.sctp.messages.exceptions.SctpPacketFormatException;
21 | import pe.pi.sctp4j.sctp.small.BlockingSCTPStream;
22 | import java.io.IOException;
23 | import java.util.Random;
24 | import java.util.TreeSet;
25 | import org.bouncycastle.tls.DatagramTransport;
26 | import org.junit.After;
27 | import org.junit.AfterClass;
28 | import org.junit.Before;
29 | import org.junit.BeforeClass;
30 | import org.junit.Test;
31 | import static org.junit.Assert.*;
32 | import pe.pi.sctp4j.sctp.dataChannel.DECP.DCOpen;
33 | import pe.pi.sctp4j.sctp.dummy.DummyStream;
34 |
35 | /**
36 | *
37 | * @author tim
38 | */
39 | public class SCTPMessageTest {
40 |
41 | private Random _rand = new Random(1); // deterministic non crypto quality random for repeatable tests
42 | private SCTPStream _fakeStream;
43 |
44 | public SCTPMessageTest() {
45 | }
46 |
47 | @BeforeClass
48 | public static void setUpClass() {
49 | }
50 |
51 | @AfterClass
52 | public static void tearDownClass() {
53 | }
54 | Association _fakeAssociation;
55 |
56 | @Before
57 | public void setUp() {
58 | DatagramTransport _fakedt = new DatagramTransport() {
59 |
60 | @Override
61 | public int getReceiveLimit() throws IOException {
62 | return 1200;
63 | }
64 |
65 | @Override
66 | public int getSendLimit() throws IOException {
67 | return 1200;
68 | }
69 |
70 | @Override
71 | public int receive(byte[] bytes, int i, int i1, int waitMs) throws IOException {
72 | try {
73 | Thread.sleep(waitMs);
74 | } catch (Exception x) {
75 | }
76 | throw new java.io.InterruptedIOException("empty");
77 | }
78 |
79 | @Override
80 | public void send(byte[] bytes, int i, int i1) throws IOException {
81 | }
82 |
83 | @Override
84 | public void close() throws IOException {
85 | }
86 |
87 | };
88 | _fakeAssociation = new Association(_fakedt, null) {
89 | @Override
90 | public void associate() throws SctpPacketFormatException, IOException {
91 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
92 | }
93 |
94 | @Override
95 | public void enqueue(DataChunk d) {
96 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
97 | }
98 |
99 | @Override
100 | public SCTPStream mkStream(int id) {
101 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
102 | }
103 |
104 | @Override
105 | protected Chunk[] sackDeal(SackChunk sackChunk) {
106 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
107 | }
108 | };
109 | _fakeStream = new DummyStream(_fakeAssociation, new Integer(22)) {
110 | @Override
111 | public void deliverMessage(SCTPMessage message) {
112 | message.run();
113 | }
114 | };
115 | }
116 |
117 | @After
118 | public void tearDown() {
119 | }
120 |
121 | /**
122 | * Test of setCompleteHandler method, of class SCTPMessage.
123 | */
124 | /*
125 | @Test
126 | public void testSetCompleteHandler() {
127 | System.out.println("setCompleteHandler");
128 | MessageCompleteHandler mch = null;
129 | SCTPMessage instance = null;
130 | instance.setCompleteHandler(mch);
131 | // TODO review the generated test code and remove the default call to fail.
132 | fail("The test case is a prototype.");
133 | }
134 | */
135 | /**
136 | * Test of hasMoreData method, of class SCTPMessage.
137 | */
138 | /*
139 | @Test
140 | public void testHasMoreData() {
141 |
142 | }
143 | */
144 | /**
145 | * Test of fill method, of class SCTPMessage.
146 | */
147 | @Test
148 | public void testFillShortString() {
149 | System.out.println("--> fill short string ");
150 | String testString = "This is a short test";
151 | SCTPMessage instance = new SCTPMessage(testString, _fakeStream);
152 | TreeSet chunks = new TreeSet();
153 | while (instance.hasMoreData()) {
154 | DataChunk dc = new DataChunk();
155 | instance.fill(dc);
156 | chunks.add(dc);
157 | }
158 | assertEquals(chunks.size(), 1);
159 | int ppid = ((DataChunk)chunks.first()).getPpid();
160 | assertEquals(ppid,DataChunk.WEBRTCSTRING);
161 | }
162 | @Test
163 | public void testFillShortBlob() {
164 | System.out.println("--> fill short blob ");
165 | byte [] testBlob = new byte[21];
166 | _rand.nextBytes(testBlob);
167 | SCTPMessage instance = new SCTPMessage(testBlob, _fakeStream);
168 | TreeSet chunks = new TreeSet();
169 | while (instance.hasMoreData()) {
170 | DataChunk dc = new DataChunk();
171 | instance.fill(dc);
172 | chunks.add(dc);
173 | }
174 | assertEquals(chunks.size(), 1);
175 | int ppid = ((DataChunk)chunks.first()).getPpid();
176 | assertEquals(ppid,DataChunk.WEBRTCBINARY);
177 | }
178 | @Test
179 | public void testFillLongString() {
180 | System.out.println("--> fill long");
181 | StringBuffer sb = new StringBuffer("This is a");
182 | for (int i = 0; i < 1030; i++) {
183 | sb.append(" long");
184 | }
185 | sb.append(" test.");
186 | String testString = sb.toString();
187 | SCTPMessage instance = new SCTPMessage(testString, _fakeStream);
188 | TreeSet chunks = new TreeSet();
189 | long tsn = 111;
190 |
191 | while (instance.hasMoreData()) {
192 | DataChunk dc = new DataChunk();
193 | dc.setTsn(tsn++);
194 | instance.fill(dc);
195 | chunks.add(dc);
196 | }
197 | double pktsz = chunks.first().getDataSize();
198 | int estimate = (int) Math.ceil(testString.length() / pktsz);
199 | assertEquals(chunks.size(), estimate);
200 | }
201 |
202 | @Test
203 | public void testEmptyString() {
204 | System.out.println("--> fill empty string");
205 | StringBuffer sb = new StringBuffer("");
206 | String testString = sb.toString();
207 | SCTPMessage instance = new SCTPMessage(testString, _fakeStream);
208 | TreeSet chunks = new TreeSet();
209 | long tsn = 111;
210 |
211 | while (instance.hasMoreData()) {
212 | DataChunk dc = new DataChunk();
213 | dc.setTsn(tsn++);
214 | instance.fill(dc);
215 | chunks.add(dc);
216 | }
217 | int pktsz = chunks.first().getDataSize();
218 | assertEquals(chunks.size(), 1);
219 | assertEquals(pktsz,1);
220 | int ppid = ((DataChunk)chunks.first()).getPpid();
221 | assertEquals(ppid,DataChunk.WEBRTCSTRINGEMPTY);
222 | }
223 |
224 | @Test
225 | public void testEmptyBlob() {
226 | System.out.println("--> fill empty blob");
227 | byte [] testBlob = new byte[0];
228 | SCTPMessage instance = new SCTPMessage(testBlob, _fakeStream);
229 | TreeSet chunks = new TreeSet();
230 | long tsn = 111;
231 |
232 | while (instance.hasMoreData()) {
233 | DataChunk dc = new DataChunk();
234 | dc.setTsn(tsn++);
235 | instance.fill(dc);
236 | chunks.add(dc);
237 | }
238 | assertEquals(chunks.size(), 1);
239 | int pktsz = chunks.first().getDataSize();
240 | assertEquals(pktsz,1);
241 | int ppid = ((DataChunk)chunks.first()).getPpid();
242 | assertEquals(ppid,DataChunk.WEBRTCBINARYEMPTY);
243 | }
244 |
245 | /**
246 | * Test of getData method, of class SCTPMessage.
247 | */
248 | /*
249 | @Test
250 | public void testGetData() {
251 | System.out.println("getData");
252 | SCTPMessage instance = null;
253 | byte[] expResult = null;
254 | byte[] result = instance.getData();
255 | assertArrayEquals(expResult, result);
256 | // TODO review the generated test code and remove the default call to fail.
257 | fail("The test case is a prototype.");
258 | }*/
259 | }
260 |
--------------------------------------------------------------------------------
/test/com/ipseorama/sctp/messages/TestPacket.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 Westhawk Ltd
3 | *
4 | * This program is free software; you can redistribute it and/or
5 | * modify it under the terms of the GNU General Public License
6 | * as published by the Free Software Foundation; either version 2
7 | * of the License, or (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program; if not, write to the Free Software
16 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 | */
18 |
19 | package com.ipseorama.sctp.messages
20 |
21 | import com.ipseorama.sctp.Association
22 | import com.ipseorama.sctp.MockAssociation
23 | import com.ipseorama.sctp.messages.exceptions.SctpPacketFormatException;
24 | import java.nio.Buffer
25 | import java.nio.ByteBuffer;
26 | import org.bouncycastle.crypto.tls.DatagramTransport
27 |
28 | import com.phono.srtplight.Log;
29 | /**
30 | *
31 | * @author Westhawk Ltd
32 | */
33 | class TestPacket extends GroovyTestCase {
34 | byte [] sampleInit = [
35 | (byte)0x13, (byte)0x88, (byte)0x13, (byte)0x88, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x68,
36 | (byte)0x1c, (byte)0xb9, (byte)0xa0, (byte)0x01, (byte)0x00, (byte)0x00, (byte)0x56, (byte)0x95,
37 | (byte)0xaa, (byte)0x39, (byte)0xc0, (byte)0x00, (byte)0x02, (byte)0x00, (byte)0x00, (byte)0x03,
38 | (byte)0xff, (byte)0x08, (byte)0x00, (byte)0x83, (byte)0x14, (byte)0xf5, (byte)0xb3, (byte)0xc0,
39 | (byte)0x00, (byte)0x00, (byte)0x04, (byte)0x80, (byte)0x08, (byte)0x00, (byte)0x0a, (byte)0xc1,
40 | (byte)0x80, (byte)0xc0, (byte)0x81, (byte)0x82, (byte)0x0f, (byte)0x00, (byte)0x00, (byte)0x80,
41 | (byte)0x02, (byte)0x00, (byte)0x24, (byte)0x8e, (byte)0xb2, (byte)0x16, (byte)0x46, (byte)0x28,
42 | (byte)0xe1, (byte)0xaf, (byte)0x0d, (byte)0xf7, (byte)0x19, (byte)0xef, (byte)0x53, (byte)0xa7,
43 | (byte)0xa7, (byte)0x7c, (byte)0x6c, (byte)0x0e, (byte)0x93, (byte)0x73, (byte)0x60, (byte)0x54,
44 | (byte)0x73, (byte)0xee, (byte)0x2c, (byte)0x6f, (byte)0x8c, (byte)0x23, (byte)0x6c, (byte)0x51,
45 | (byte)0xe1, (byte)0xbe, (byte)0x5f, (byte)0x80, (byte)0x04, (byte)0x00, (byte)0x06, (byte)0x00,
46 | (byte)0x01, (byte)0x00, (byte)0x00, (byte)0x80, (byte)0x03, (byte)0x00, (byte)0x06, (byte)0x80,
47 | (byte)0xc1, (byte)0x00, (byte)0x00 ];
48 |
49 | byte [] sampleAbort = [(byte)0x13, (byte)0x88, (byte)0x13, (byte)0x88, (byte)0x27, (byte)0x44, (byte)0xfa, (byte)0x52, (byte)0xb0, (byte)0x85
50 | , (byte)0xdd, (byte)0x7b, (byte)0x06, (byte)0x01, (byte)0x00, (byte)0x0c, (byte)0x00, (byte)0x0d, (byte)0x00, (byte)0x08, (byte)0x40, (byte)0x00, (byte)0x00
51 | , (byte)0x01];
52 | byte [] sampleAbort2 = [(byte)0x13,(byte)0x88,(byte)0x13,(byte)0x88,(byte)0x53,(byte)0x05,(byte)0x6d,(byte)0xb5,(byte)0x97,(byte)0xe0,(byte)0xd0
53 | ,(byte)0x20,(byte)0x06,(byte)0x00,(byte)0x00,(byte)0x14,(byte)0x00,(byte)0x0d,(byte)0x00,(byte)0x10,(byte)0x30,(byte)0x00,(byte)0x00,(byte)0x02
54 | ,(byte)0x44,(byte)0x15,(byte)0xd2,(byte)0x71,(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00];
55 |
56 | byte [] sampleData = [(byte)0x13, (byte)0x88, (byte)0x13, (byte)0x88, (byte)0x13, (byte)0xfc, (byte)0x3a, (byte)0x88, (byte)0x87, (byte)0xa9
57 | , (byte)0x5b, (byte)0xfc, (byte)0x00, (byte)0x03, (byte)0x00, (byte)0x20, (byte)0xf8, (byte)0x13, (byte)0x18, (byte)0x5b, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x32, (byte)0x03, (byte)0x00
58 | , (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x04, (byte)0x00, (byte)0x00, (byte)0x63, (byte)0x68, (byte)0x61, (byte)0x74];
59 |
60 | byte [] sampleHeartBeat = [(byte)0x13, (byte)0x88, (byte)0x13, (byte)0x88, (byte)0x00, (byte)0x6f, (byte)0x0e, (byte)0x57, (byte)0x9a, (byte)0x69, (byte)0x21, (byte)0x26
61 | , (byte)0x04, (byte)0x00, (byte)0x00, (byte)0x2c, (byte)0x00, (byte)0x01, (byte)0x00, (byte)0x28, (byte)0xd7, (byte)0x47, (byte)0x62, (byte)0x53, (byte)0x88, (byte)0xc4, (byte)0x0d, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x7b, (byte)0x08, (byte)0x00, (byte)0x00, (byte)0xa0, (byte)0x82
62 | , (byte)0x07, (byte)0x7c, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00];
63 |
64 | byte [] dcepack = [(byte)0x13,(byte)0x88,(byte)0x13,(byte)0x88,(byte)0x96,(byte)0x83,(byte)0x0e,(byte)0xe2,(byte)0xa4,(byte)0xed,(byte)0x62,(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x11,(byte)0x57,(byte)0xd3,(byte)0x59,(byte)0x0a,(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x32,(byte)0x02];
65 | byte [] cookieEcho = [(byte)0x13,(byte)0x88,(byte)0x13,(byte)0x88,(byte)0xf5,(byte)0x36,(byte)0xd8,(byte)0x68,(byte)0x23,(byte)0xf0,(byte)0x16,(byte)0x11,(byte)0x0a,(byte)0x00
66 | ,(byte)0x00,(byte)0x24,(byte)0x59,(byte)0xfe,(byte)0xc8,(byte)0x5b,(byte)0xf0,(byte)0x2c,(byte)0x25,(byte)0xe6,(byte)0x97,(byte)0x23,(byte)0x33,(byte)0xa7,(byte)0x71,(byte)0x5e,(byte)0xb0,(byte)0x42,(byte)0x16,(byte)0x5f
67 | ,(byte)0xdd,(byte)0xa9,(byte)0x0a,(byte)0x5a,(byte)0xfa,(byte)0xa1,(byte)0x90,(byte)0xfe,(byte)0x0f,(byte)0x2b,(byte)0xd0,(byte)0x08,(byte)0x56,(byte)0xd4,(byte)0x00,(byte)0x03,(byte)0x00,(byte)0x20,(byte)0xad
68 | ,(byte)0xac,(byte)0x5b,(byte)0xe2,(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x32,(byte)0x03,(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00
69 | ,(byte)0x00,(byte)0x04,(byte)0x00,(byte)0x00,(byte)0x63,(byte)0x68,(byte)0x61,(byte)0x74];
70 | void setUp(){
71 | Log.setLevel(Log.ALL);
72 | }
73 |
74 | class NonvalidatingPacket extends Packet{
75 | NonvalidatingPacket(ByteBuffer pkt){
76 | super(pkt);
77 | }
78 | void setChecksum(ByteBuffer pkt){}
79 | void checkChecksum(ByteBuffer pkt){
80 | // some of the tests would produce invalid checksums - we don't care - for the moment.
81 | }
82 | }
83 | void testValidHeader(){
84 | ByteBuffer b = ByteBuffer.wrap(sampleInit,0,12);
85 | Packet p = new NonvalidatingPacket(b);
86 | assertEquals("DestPort should be 5000", 5000, p.getDestPort());
87 | assertEquals("SrcPort should be 5000", 5000, p.getSrcPort());
88 | assertEquals("verTag should be 0", 0, p.getVerTag());
89 | }
90 | void testShortHeader(){
91 | ByteBuffer b = ByteBuffer.allocate(1);
92 | Exception x = null;
93 | try {
94 | Packet p = new NonvalidatingPacket(b);
95 | } catch (Exception e){
96 | x = e;
97 | }
98 | assertEquals("Exception should be thrown ",false,(x==null));
99 | assertEquals("Expecting exception SctpPacketException ",x.getClass(),SctpPacketFormatException.class);
100 | }
101 |
102 | void testRecycleHeader(){
103 | ByteBuffer b = ByteBuffer.wrap(sampleInit,0,12);
104 | Packet p = new NonvalidatingPacket(b);
105 | Buffer bb = p.getByteBuffer();
106 | assertEquals("Expecting same content in packets ",p.getHex(b),p.getHex(bb));
107 | }
108 |
109 | void testChunks(){
110 | ByteBuffer b = ByteBuffer.wrap(sampleInit);
111 | Packet p = new Packet(b);
112 | assertEquals("Expecting 1 chunk ",1,p.getChunkList().size())
113 | }
114 |
115 | void testInitWrite(){
116 | ByteBuffer b = ByteBuffer.wrap(sampleInit);
117 | Packet p = new Packet(b);
118 | List chunks = p.getChunkList();
119 | assertEquals("Expecting 1 chunk ",1,chunks.size());
120 | Chunk init = chunks.get(0);
121 | assertEquals("Expecting an init chunk",init.getType(),Chunk.INIT);
122 | ByteBuffer bout = ByteBuffer.allocate(sampleInit.length-12);
123 | init.write(bout);
124 | byte[]sin = new byte[sampleInit.length-12];
125 | System.arraycopy(sampleInit,12,sin,0, sin.length);
126 | assertEquals("Expected to re-make same packet",Packet.getHex(sin),Packet.getHex(bout.array()));
127 | }
128 |
129 | void testAbort(){
130 | ByteBuffer b = ByteBuffer.wrap(sampleAbort);
131 | Log.debug("Sample Abort is " + sampleAbort.length);
132 |
133 | Packet p = new Packet(b);
134 | List chunks = p.getChunkList();
135 | assertEquals("Expecting 1 chunk ",1,chunks.size());
136 | Chunk abort = chunks.get(0);
137 | assertEquals("Expecting an abort chunk",abort.getType(),Chunk.ABORT);
138 | }
139 |
140 | void testAbort2(){
141 | ByteBuffer b = ByteBuffer.wrap(sampleAbort2);
142 | Log.debug("Sample Abort is " + sampleAbort2.length);
143 |
144 | Packet p = new Packet(b);
145 | List chunks = p.getChunkList();
146 | assertEquals("Expecting 1 chunk ",1,chunks.size());
147 | Chunk abort = chunks.get(0);
148 | assertEquals("Expecting an abort chunk",abort.getType(),Chunk.ABORT);
149 | }
150 |
151 | void testCookieEcho(){
152 | ByteBuffer b = ByteBuffer.wrap(cookieEcho);
153 | Packet p = new Packet(b);
154 | List chunks = p.getChunkList();
155 | assertEquals("Expecting 2 chunks ",2,chunks.size());
156 | Chunk ic = chunks.get(0);
157 | assertEquals("Expecting a cookie echo chunk",ic.getType(),Chunk.COOKIE_ECHO);
158 | Chunk dopen = chunks.get(1);
159 | assertEquals("Expecting a data chunk",dopen.getType(),Chunk.DATA);
160 |
161 | }
162 | void testInitAck(){
163 | ByteBuffer b = ByteBuffer.wrap(sampleInit);
164 | Packet p = new Packet(b);
165 | List chunks = p.getChunkList();
166 | assertEquals("Expecting 1 chunk ",1,chunks.size());
167 | Chunk ic = chunks.get(0);
168 | assertEquals("Expecting an init chunk",ic.getType(),Chunk.INIT);
169 |
170 | Association ass = new MockAssociation(null,null);
171 | Chunk [] ca = ass.inboundInit(ic);
172 | assertEquals("Expecting a single reply chunk",1,ca.length);
173 | ByteBuffer iacbb = ass.mkPkt(ca);
174 | Packet iac = new Packet(iacbb);
175 | chunks = iac.getChunkList();
176 | assertEquals("Expecting 1 chunk ",1,chunks.size());
177 | ic = chunks.get(0);
178 | assertEquals("Expecting an InitAck chunk",ic.getType(),Chunk.INITACK);
179 |
180 | }
181 |
182 |
183 | void testOpenDataChunk(){
184 | ByteBuffer b = ByteBuffer.wrap(sampleData);
185 | Packet p = new Packet(b);
186 | List chunks = p.getChunkList();
187 | assertEquals("Expecting 1 chunk ",1,chunks.size());
188 | DataChunk dat = chunks.get(0);
189 | assertEquals("Expecting a Data chunk",dat.getType(),Chunk.DATA);
190 | Log.debug("got "+dat.getClass().getName()+ " chunk" + dat.toString());
191 | assertEquals("Expecting seqno of zero",dat.getSSeqNo(),0);
192 | assertEquals("Expecting stream of zero",dat.getStreamId(),0);
193 | assertEquals("Expecting an DCEP",dat.getPpid(),50);
194 | assertEquals("Data should be zero",dat.getData(),null);
195 | assertEquals("Expected to parse a DCEP packet",dat.getDCEP()!=null,true);
196 | assertEquals("Expected an open DCEP packet ",dat.getDCEP().isAck(),false);
197 |
198 |
199 | }
200 |
201 | void testHeartBeatChunk(){
202 | ByteBuffer b = ByteBuffer.wrap(sampleHeartBeat);
203 | Packet p = new Packet(b);
204 | List chunks = p.getChunkList();
205 | assertEquals("Expecting 1 chunk ",1,chunks.size());
206 | HeartBeatChunk dat = chunks.get(0);
207 | assertEquals("Expecting a HeartBeatChunk",dat.getType(),Chunk.HEARTBEAT);
208 | Chunk[] r = dat.mkReply();
209 | assertEquals("Expecting 1 chunk ",1,r.length);
210 | assertEquals("Expecting a HeartBeatAckChunk",r[0].getType(),Chunk.HEARTBEAT_ACK);
211 | }
212 |
213 | void testDCEPAckChunk(){
214 | ByteBuffer b = ByteBuffer.wrap(dcepack);
215 | Packet p = new Packet(b);
216 | List chunks = p.getChunkList();
217 | assertEquals("Expecting 1 chunk ",1,chunks.size());
218 | DataChunk dat = chunks.get(0);
219 | assertEquals("Expecting a DataChunk",dat.getType(),Chunk.DATA);
220 | }
221 |
222 | }
223 |
224 |
--------------------------------------------------------------------------------
/test/main/groovy/com/ipseorama/sctp/TestAssociation.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 Westhawk Ltd
3 | *
4 | * This program is free software; you can redistribute it and/or
5 | * modify it under the terms of the GNU General Public License
6 | * as published by the Free Software Foundation; either version 2
7 | * of the License, or (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program; if not, write to the Free Software
16 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 | */
18 |
19 | package com.ipseorama.sctp
20 |
21 | import com.ipseorama.sctp.Association
22 | import com.ipseorama.sctp.AssociationListener
23 | import com.ipseorama.sctp.messages.DataChunk
24 | import com.ipseorama.sctp.messages.Packet
25 | import com.ipseorama.sctp.messages.SackChunk
26 | import com.ipseorama.sctp.messages.exceptions.SctpPacketFormatException;
27 | import com.ipseorama.base.dataChannel.DECP.DCOpen;
28 | import java.nio.Buffer
29 | import java.nio.ByteBuffer;
30 | import java.security.SecureRandom
31 | import org.bouncycastle.crypto.tls.DTLSTransport
32 | import org.bouncycastle.crypto.tls.DatagramTransport
33 |
34 | import com.phono.srtplight.Log;
35 | /**
36 | *
37 | * @author Westhawk Ltd
38 | */
39 | class TestAssociation extends GroovyTestCase {
40 |
41 | byte [] sampleDataOpen = [(byte)0x13, (byte)0x88, (byte)0x13, (byte)0x88, (byte)0x13, (byte)0xfc, (byte)0x3a, (byte)0x88, (byte)0x8d, (byte)0xa9
42 | , (byte)0xa7, (byte)0x20, (byte)0x00, (byte)0x03, (byte)0x00, (byte)0x20, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x32, (byte)0x03, (byte)0x00
43 | , (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x04, (byte)0x00, (byte)0x00, (byte)0x63, (byte)0x68, (byte)0x61, (byte)0x74];
44 |
45 | void setUp(){
46 | Log.setLevel(Log.ALL);
47 | }
48 |
49 |
50 | void testAss(){
51 | ByteBuffer sent;
52 | DatagramTransport mock = new DatagramTransport(){
53 |
54 | public int getReceiveLimit() throws IOException{
55 | return 1200;
56 | }
57 |
58 | public int getSendLimit() throws IOException{
59 | return 1200;
60 | }
61 |
62 | public int receive(byte[] bytes, int i, int i1, int i2) throws IOException{
63 | Thread.sleep(i2);
64 | return 0;
65 | }
66 |
67 | public void send(byte[] ou, int off, int pos) throws IOException{
68 | byte [] bsent = new byte[pos-off];
69 | java.lang.System.arraycopy(ou,off,bsent,(int)0,bsent.length);
70 | sent = ByteBuffer.wrap(bsent)
71 | }
72 |
73 | public void close() throws IOException{
74 |
75 | }
76 | };
77 | SCTPStream stream ;
78 | AssociationListener al = new AssociationListener(){
79 |
80 | public void onAssociated(Association a){
81 | Log.debug("Associated");
82 |
83 | }
84 | public void onDisAssociated(Association a){
85 | Log.debug("Disssociated");
86 |
87 | }
88 | public void onStream(SCTPStream s){
89 | Log.debug("Association opened stream ");
90 | stream = s;
91 | }
92 | };
93 | MockAssociation ass = new MockAssociation(mock,al);
94 | ass.setMyVerTag(335297160);
95 | ByteBuffer b = ByteBuffer.wrap(sampleDataOpen);
96 | Packet p = new Packet(b);
97 | ass.deal(p);
98 |
99 | Packet ack = new Packet(sent);
100 | List chunks = ack.getChunkList();
101 | assertEquals("Expecting 1 chunk ",1,chunks.size());
102 | DataChunk dat = chunks.get(0);
103 | assertEquals("Expecting a Data chunk",dat.getType(),DataChunk.DATA);
104 | Log.debug("got "+dat.getClass().getName()+ " chunk" + dat.toString());
105 | assertEquals("Expecting seqno of zero",dat.getSSeqNo(),0);
106 | assertEquals("Expecting stream of zero",dat.getStreamId(),0);
107 | assertEquals("Expecting an DCEP",dat.getPpid(),50);
108 | assertEquals("Data should be zero",dat.getData(),null);
109 | assertEquals("Expected to parse a DCEP packet",dat.getDCEP()!=null,true);
110 | assertEquals("Expected an ack DCEP packet ",dat.getDCEP().isAck(),true);
111 |
112 | assertEquals("expecting a stream",(stream == null), false);
113 | stream.send("hello");
114 | // ugh - uses a side effect on the sent buffer, which we capture.
115 | Packet pack = new Packet(sent);
116 | chunks = pack.getChunkList();
117 | assertEquals("Expecting 1 chunk ",1,chunks.size());
118 | dat = chunks.get(0);
119 | assertEquals("Expecting a Data chunk",dat.getType(),DataChunk.DATA);
120 | Log.debug("got "+dat.getClass().getName()+ " chunk" + dat.toString());
121 | assertEquals("Expecting seqno of one",dat.getSSeqNo(),1); // we've done a DCEP ack by now.
122 | assertEquals("Expecting stream of zero",dat.getStreamId(),0);
123 | assertEquals("Expecting hello in the data",dat.getDataAsString(),"hello");
124 |
125 | }
126 | }
127 |
128 |
--------------------------------------------------------------------------------
/test/main/groovy/com/ipseorama/sctp/TestMessage.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 Westhawk Ltd
3 | *
4 | * This program is free software; you can redistribute it and/or
5 | * modify it under the terms of the GNU General Public License
6 | * as published by the Free Software Foundation; either version 2
7 | * of the License, or (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program; if not, write to the Free Software
16 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 | */
18 |
19 | package com.ipseorama.sctp
20 |
21 | import com.ipseorama.sctp.Association
22 | import com.ipseorama.sctp.AssociationListener
23 | import com.ipseorama.sctp.messages.DataChunk
24 | import com.ipseorama.sctp.messages.Packet
25 | import com.ipseorama.sctp.messages.SackChunk
26 | import com.ipseorama.sctp.messages.exceptions.SctpPacketFormatException;
27 | import com.ipseorama.base.dataChannel.DECP.DCOpen;
28 | import java.nio.Buffer
29 | import java.nio.ByteBuffer;
30 | import java.security.SecureRandom
31 | import org.bouncycastle.crypto.tls.DTLSTransport
32 | import org.bouncycastle.crypto.tls.DatagramTransport
33 |
34 | import com.phono.srtplight.Log;
35 | /**
36 | *
37 | * @author Westhawk Ltd
38 | */
39 | class TestMessage extends GroovyTestCase {
40 | def data = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
41 | Association a;
42 | SCTPStream stream;
43 | def id;
44 |
45 | void setUp(){
46 | Log.setLevel(Log.ALL);
47 | a = null;
48 | id = 1000;
49 | stream = new SCTPStream(a, id){
50 | public void send(String message){
51 | }
52 | };
53 | }
54 |
55 | void testMessFillSingle(){
56 | // assume capacity > 52
57 | SCTPMessage m = new SCTPMessage(data,stream);
58 | def chunks = [];
59 | while (m.hasMoreData()) {
60 | DataChunk dc = new DataChunk()
61 | m.fill(dc);
62 | chunks += dc;
63 | }
64 | Log.debug("chunks "+chunks.size);
65 | assertEquals ("Wrong number of chunks",chunks.size,1);
66 |
67 | assertEquals ("First (and only) chunk should have single flag set",chunks[0].getFlags(),DataChunk.SINGLEFLAG);
68 |
69 | }
70 |
71 | void testMessFill1(){
72 |
73 | SCTPMessage m = new SCTPMessage(data,stream);
74 | def chunks = [];
75 | while (m.hasMoreData()) {
76 | DataChunk dc = new DataChunk(){
77 | public int getCapacity() {
78 | return 1; // shrug
79 | }
80 | };
81 | m.fill(dc);
82 | chunks += dc;
83 | }
84 | Log.debug("chunks "+chunks.size);
85 | assertEquals ("Wrong number of chunks",chunks.size,data.length());
86 |
87 | assertEquals ("Start chunk should have start flag set",chunks[0].getFlags(),DataChunk.BEGINFLAG);
88 | assertEquals ("End chunk should have end flag set",chunks[data.length()-1].getFlags(),DataChunk.ENDFLAG);
89 | for (int i = 1; i< data.length()-1;i++){
90 | assertEquals ("middle chunk should have no flag set",chunks[i].getFlags(),0);
91 | assertEquals ("middle data should match input",chunks[i].getDataAsString(),data[i]);
92 | }
93 | }
94 |
95 | }
96 |
--------------------------------------------------------------------------------
/test/main/java/com/ipseorama/sctp/MockAssociation.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 Westhawk Ltd
3 | *
4 | * This program is free software; you can redistribute it and/or
5 | * modify it under the terms of the GNU General Public License
6 | * as published by the Free Software Foundation; either version 2
7 | * of the License, or (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program; if not, write to the Free Software
16 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 | */
18 | package com.ipseorama.sctp;
19 |
20 | import com.ipseorama.sctp.messages.Chunk;
21 | import com.ipseorama.sctp.messages.DataChunk;
22 | import com.ipseorama.sctp.messages.InitChunk;
23 | import com.ipseorama.sctp.messages.SackChunk;
24 | import com.ipseorama.sctp.small.BlockingSCTPStream;
25 | import org.bouncycastle.crypto.tls.DatagramTransport;
26 |
27 | /**
28 | *
29 | * @author Westhawk Ltd
30 | */
31 | public class MockAssociation extends Association {
32 |
33 | public MockAssociation(DatagramTransport transport, AssociationListener al) {
34 | super(transport, al);
35 | }
36 |
37 |
38 |
39 | @Override
40 | public void enqueue(DataChunk d) {
41 | throw new UnsupportedOperationException("Not supported yet. (enqueue)"); //To change body of generated methods, choose Tools | Templates.
42 | }
43 |
44 | @Override
45 | public SCTPStream mkStream(int id) {
46 | return new SCTPStream(this, id) {
47 |
48 | @Override
49 | public void send(String message) throws Exception {
50 | SCTPMessage m = new SCTPMessage(message, this);
51 | _ass.sendAndBlock(m);
52 | }
53 |
54 | };
55 | }
56 |
57 | @Override
58 | public void sendAndBlock(SCTPMessage m) throws Exception {
59 | Chunk[] dar = new Chunk[1];
60 |
61 | DataChunk dc = new DataChunk();
62 | m.fill(dc);
63 | dc.setTsn(_nearTSN++);
64 | // check rollover - will break at maxint.
65 | dar[0] = dc;
66 | send(dar);
67 |
68 | }
69 |
70 | @Override
71 | public SCTPMessage makeMessage(byte[] bytes, BlockingSCTPStream aThis) {
72 | throw new UnsupportedOperationException("Not supported yet. (makeMessage)"); //To change body of generated methods, choose Tools | Templates.
73 | }
74 |
75 | @Override
76 | public Chunk[] inboundInit(InitChunk i) {
77 | return super.inboundInit(i);
78 | }
79 |
80 | public void setMyVerTag(int v) {
81 | super._myVerTag = v;
82 | }
83 |
84 | @Override
85 | public SCTPMessage makeMessage(String s, BlockingSCTPStream aThis) {
86 | throw new UnsupportedOperationException("Not supported yet.(Make Message - string"); //To change body of generated methods, choose Tools | Templates.
87 | }
88 |
89 | @Override
90 | protected Chunk[] sackDeal(SackChunk sackChunk) {
91 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
92 | }
93 |
94 |
95 | }
96 |
--------------------------------------------------------------------------------