This commit is contained in:
kamhung
2015-12-03 13:22:46 +08:00
parent a4573d0921
commit 38d56bd897
17 changed files with 0 additions and 1065 deletions

View File

@@ -1,37 +0,0 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package com.wentch.redkale.net.icep;
import com.wentch.redkale.net.icep.attr.*;
import com.wentch.redkale.net.icep.stun.*;
import com.wentch.redkale.util.*;
import java.io.*;
import java.nio.*;
/**
*
* @author zhangjx
*/
public class BindingIcepServlet extends IcepServlet {
@Override
public void execute(IcepRequest request, IcepResponse response) throws IOException {
StunPacket packet = request.getStunPacket();
ByteBuffer buffer = response.getContext().pollBuffer();
packet.addAttribute(new XorMappedAddressAttribute(request.getRemoteAddress()));
packet.getHeader().setRequestid((StunHeader.TYPE_SUCCESS | StunHeader.ACTION_BINDING));
packet.encode(buffer);
buffer.flip();
Utility.println("响应结果: ", buffer);
response.finish(buffer);
}
@Override
public short getRequestid() {
return 0x0001;
}
}

View File

@@ -1,20 +0,0 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package com.wentch.redkale.net.icep;
import java.nio.*;
/**
*
* @author zhangjx
* @param <T>
*/
public interface IcepCoder<T> {
public T decode(final ByteBuffer buffer);
public ByteBuffer encode(final ByteBuffer buffer);
}

View File

@@ -1,33 +0,0 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package com.wentch.redkale.net.icep;
import com.wentch.redkale.convert.bson.*;
import com.wentch.redkale.net.*;
import com.wentch.redkale.util.*;
import com.wentch.redkale.watch.*;
import java.net.*;
import java.nio.*;
import java.nio.charset.*;
import java.util.concurrent.*;
import java.util.logging.*;
/**
*
* @author zhangjx
*/
public final class IcepContext extends Context {
protected final BsonFactory bsonFactory;
public IcepContext(long serverStartTime, Logger logger, ExecutorService executor, int bufferCapacity, ObjectPool<ByteBuffer> bufferPool,
ObjectPool<Response> responsePool, int maxbody, Charset charset, InetSocketAddress address, PrepareServlet prepare,
WatchFactory watch, int readTimeoutSecond, int writeTimeoutSecond) {
super(serverStartTime, logger, executor, bufferCapacity, bufferPool, responsePool, maxbody, charset,
address, prepare, watch, readTimeoutSecond, writeTimeoutSecond);
this.bsonFactory = BsonFactory.root();
}
}

View File

@@ -1,29 +0,0 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package com.wentch.redkale.net.icep;
/**
*
* @author zhangjx
*/
public class IcepException extends RuntimeException {
public IcepException() {
super();
}
public IcepException(String s) {
super(s);
}
public IcepException(String message, Throwable cause) {
super(message, cause);
}
public IcepException(Throwable cause) {
super(cause);
}
}

View File

@@ -1,44 +0,0 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package com.wentch.redkale.net.icep;
import com.wentch.redkale.net.*;
import com.wentch.redkale.util.*;
import java.io.*;
import java.util.*;
/**
*
* @author zhangjx
*/
public class IcepPrepareServlet extends PrepareServlet<IcepRequest, IcepResponse> {
private final HashMap<Short, IcepServlet> servletmaps = new HashMap<>();
public IcepPrepareServlet() {
}
@Override
public void init(Context context, AnyValue config) {
}
public void addIcepServlet(IcepServlet servlet, AnyValue conf) {
servlet.conf = conf;
this.servletmaps.put(servlet.getRequestid(), servlet);
}
// 28.[00,03,00,08, 21,12,a4,42,45,6f,4e,77,4e,47,71,55,32,37,77,39, 00,19,00,04,11,00,00,00]
@Override
public void execute(IcepRequest request, IcepResponse response) throws IOException {
IcepServlet servlet = servletmaps.get(request.getRequestid());
if (servlet != null) {
servlet.execute(request, response);
} else {
response.finish();
}
}
}

View File

@@ -1,70 +0,0 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package com.wentch.redkale.net.icep;
import com.wentch.redkale.net.*;
import com.wentch.redkale.net.icep.stun.*;
import com.wentch.redkale.util.*;
import java.net.*;
import java.nio.*;
/**
*
* @author zhangjx
*/
public class IcepRequest extends Request {
private short requestid;
private StunPacket stunPacket;
protected IcepRequest(IcepContext context) {
super(context);
}
// 20.[00,01,00,00,21,12,a4,42,63,6a,30,65,62,43,44,57,67,76,68,58]
@Override
protected int readHeader(ByteBuffer buffer) {
Utility.println(Utility.now() + "-------" + getRemoteAddress() + " ", buffer);
if (buffer.remaining() < 20) return -1;
this.requestid = buffer.getShort();
char bodysize = buffer.getChar();
byte[] bytes = new byte[16];
buffer.get(bytes);
StunHeader header = new StunHeader(this.requestid, bytes);
this.stunPacket = new StunPacket(header);
return 0;
}
public InetSocketAddress getRemoteAddress() {
return (InetSocketAddress) channel.getRemoteAddress();
}
@Override
protected int readBody(ByteBuffer buffer) {
return buffer.remaining();
}
@Override
protected void prepare() {
}
@Override
protected void recycle() {
this.requestid = 0;
this.stunPacket = null;
super.recycle();
}
public short getRequestid() {
return requestid;
}
public StunPacket getStunPacket() {
return stunPacket;
}
}

View File

@@ -1,25 +0,0 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package com.wentch.redkale.net.icep;
import com.wentch.redkale.net.*;
import com.wentch.redkale.util.*;
import java.util.concurrent.atomic.*;
/**
*
* @author zhangjx
*/
public class IcepResponse extends Response<IcepRequest> {
protected IcepResponse(Context context, IcepRequest request) {
super(context, request);
}
public static ObjectPool<Response> createPool(AtomicLong creatCounter, AtomicLong cycleCounter, int max, Creator<Response> creator) {
return new ObjectPool<>(creatCounter, cycleCounter, max, creator, (x) -> ((IcepResponse) x).prepare(), (x) -> ((IcepResponse) x).recycle());
}
}

View File

@@ -1,58 +0,0 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package com.wentch.redkale.net.icep;
import com.wentch.redkale.net.*;
import com.wentch.redkale.util.*;
import com.wentch.redkale.watch.*;
import java.nio.*;
import java.util.concurrent.atomic.*;
/**
*
* @author zhangjx
*/
public final class IcepServer extends Server {
public IcepServer() {
this(System.currentTimeMillis(), null);
}
public IcepServer(long serverStartTime, final WatchFactory watch) {
super(serverStartTime, "UDP", new IcepPrepareServlet(), watch);
}
@Override
public void init(AnyValue config) throws Exception {
super.init(config);
}
public void addIcepServlet(IcepServlet servlet, AnyValue conf) {
((IcepPrepareServlet) this.prepare).addIcepServlet(servlet, conf);
}
@Override
@SuppressWarnings("unchecked")
protected Context createContext() {
final int port = this.address.getPort();
AtomicLong createBufferCounter = watch == null ? new AtomicLong() : watch.createWatchNumber("ICEP_" + port + ".Buffer.creatCounter");
AtomicLong cycleBufferCounter = watch == null ? new AtomicLong() : watch.createWatchNumber("ICEP_" + port + ".Buffer.cycleCounter");
int rcapacity = Math.max(this.capacity, 8 * 1024);
ObjectPool<ByteBuffer> bufferPool = new ObjectPool<>(createBufferCounter, cycleBufferCounter, this.bufferPoolSize,
(Object... params) -> ByteBuffer.allocateDirect(rcapacity), null, (e) -> {
if (e == null || e.isReadOnly() || e.capacity() != rcapacity) return false;
e.clear();
return true;
});
AtomicLong createResponseCounter = watch == null ? new AtomicLong() : watch.createWatchNumber("ICEP_" + port + ".Response.creatCounter");
AtomicLong cycleResponseCounter = watch == null ? new AtomicLong() : watch.createWatchNumber("ICEP_" + port + ".Response.cycleCounter");
ObjectPool<Response> responsePool = IcepResponse.createPool(createResponseCounter, cycleResponseCounter, this.responsePoolSize, null);
IcepContext localcontext = new IcepContext(this.serverStartTime, this.logger, executor, rcapacity, bufferPool, responsePool,
this.maxbody, this.charset, this.address, this.prepare, this.watch, this.readTimeoutSecond, this.writeTimeoutSecond);
responsePool.setCreator((Object... params) -> new IcepResponse(localcontext, new IcepRequest(localcontext)));
return localcontext;
}
}

View File

@@ -1,30 +0,0 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package com.wentch.redkale.net.icep;
import com.wentch.redkale.net.*;
import com.wentch.redkale.util.*;
/**
*
* @author zhangjx
*/
public abstract class IcepServlet implements Servlet<IcepRequest, IcepResponse> {
AnyValue conf; //当前Servlet的配置
public abstract short getRequestid();
@Override
public final boolean equals(Object obj) {
return obj != null && obj.getClass() == this.getClass();
}
@Override
public final int hashCode() {
return this.getClass().hashCode();
}
}

View File

@@ -1,72 +0,0 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package com.wentch.redkale.net.icep;
import com.wentch.redkale.boot.*;
import com.wentch.redkale.boot.ClassFilter.FilterEntry;
import com.wentch.redkale.net.*;
import com.wentch.redkale.util.*;
import com.wentch.redkale.util.AnyValue.DefaultAnyValue;
import java.lang.reflect.*;
import java.net.*;
import java.util.logging.*;
/**
*
* @author zhangjx
*/
@NodeProtocol({"ICEP"})
public class NodeIcepServer extends NodeServer {
private final IcepServer icepServer;
public NodeIcepServer(Application application, AnyValue serconf) {
super(application, application.getResourceFactory().createChild(), createServer(application, serconf));
this.icepServer = (IcepServer) server;
}
private static Server createServer(Application application, AnyValue serconf) {
return new IcepServer(application.getStartTime(), application.getWatchFactory());
}
@Override
public InetSocketAddress getSocketAddress() {
return icepServer == null ? null : icepServer.getSocketAddress();
}
@Override
protected ClassFilter<Servlet> createServletClassFilter() {
return createClassFilter(null, null, IcepServlet.class, null, "servlets", "servlet");
}
@Override
protected void loadServlet(ClassFilter<? extends Servlet> servletFilter) throws Exception {
if (icepServer != null) loadIcepServlet(this.nodeConf.getAnyValue("servlets"), servletFilter);
}
protected void loadIcepServlet(final AnyValue conf, ClassFilter<? extends Servlet> filter) throws Exception {
final StringBuilder sb = logger.isLoggable(Level.FINE) ? new StringBuilder() : null;
final String threadName = "[" + Thread.currentThread().getName() + "] ";
for (FilterEntry<? extends Servlet> en : filter.getFilterEntrys()) {
Class<IcepServlet> clazz = (Class<IcepServlet>) en.getType();
if (Modifier.isAbstract(clazz.getModifiers())) continue;
final IcepServlet servlet = clazz.newInstance();
factory.inject(servlet);
DefaultAnyValue servletConf = (DefaultAnyValue) en.getProperty();
this.icepServer.addIcepServlet(servlet, servletConf);
if (sb != null) sb.append(threadName).append(" Loaded ").append(clazz.getName()).append(" --> ").append(format(servlet.getRequestid())).append(LINE_SEPARATOR);
}
if (sb != null && sb.length() > 0) logger.log(Level.FINE, sb.toString());
}
private static String format(short value) {
String str = Integer.toHexString(value);
if (str.length() == 1) return "0x000" + str;
if (str.length() == 2) return "0x00" + str;
if (str.length() == 3) return "0x0" + str;
return "0x" + str;
}
}

View File

@@ -1,112 +0,0 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package com.wentch.redkale.net.icep.attr;
import com.wentch.redkale.net.icep.*;
import com.wentch.redkale.net.icep.stun.*;
import com.wentch.redkale.util.*;
import java.net.*;
import java.nio.*;
/**
*
* @author zhangjx
*/
public class MappedAddressAttribute extends StunAttribute {
protected InetSocketAddress address;
public MappedAddressAttribute() {
}
public MappedAddressAttribute(InetSocketAddress address) {
this.address = address;
}
/**
0000 b8 2a 72 c8 7c 7e 08 57 00 60 3b f6 08 00 45 00 .*r.|~.W.`;...E.
0010 00 78 00 00 40 00 30 11 6f 1a d8 5d f6 12 0a 1c .x..@.0.o..]....
0020 02 cf 0d 96 e2 ba 00 64 f0 b3
01 01 00 48 21 12 a4 42 50 38 69 55 2b 65 78 66 4e 68 76 32 00 01 .BP8iU+exfNhv2..
0040 00 08 00 01 e2 ba 71 5c fb ed 00 04 00 08 00 01 ......q\........
0050 0d 96 d8 5d f6 12 00 05 00 08 00 01 0d 97 d8 5d ...]...........]
0060 f6 0f 80 20 00 08 00 01 c3 a8 50 4e 5f af 80 22 ... ......PN_.."
0070 00 14 56 6f 76 69 64 61 2e 6f 72 67 20 30 2e 39 ..Vovida.org 0.9
0080 37 2d 43 50 43 00 7-CPC.
@param args
@throws Exception
*/
public static void main(String[] args) throws Exception {
final byte[] transactionid = format("21 12 a4 42 50 38 69 55 2b 65 78 66 4e 68 76 32");
byte[] attrs = format("80 20 00 08 00 01 c3 a8 50 4e 5f af");
XorMappedAddressAttribute attr = new XorMappedAddressAttribute().decode(ByteBuffer.wrap(attrs), transactionid);
System.out.println(attr);
ByteBuffer buffer = ByteBuffer.allocate(1024);
attr.encode(buffer, transactionid);
buffer.flip();
Utility.println(null, buffer);
}
protected static byte[] format(String string) {
String[] strs = string.split("\\s+");
byte[] bs = new byte[strs.length];
for (int i = 0; i < bs.length; i++) {
bs[i] = (byte) Integer.parseInt(strs[i], 16);
}
return bs;
}
@Override
public MappedAddressAttribute decode(final ByteBuffer buffer, final byte[] transactionid) {
final short attrid = (short) (buffer.getShort() & 0x00ff);
if (attrid != getAttributeid()) throw new IcepException(this.getClass().getSimpleName() + " has illegal attributeid " + attrid);
final int bodysize = buffer.getShort() & 0xffff;
final short family = buffer.getShort();
if (family == 0x0001 && bodysize != 8) throw new IcepException("family = " + family + " but bodysize = " + bodysize);
if (family == 0x0002 && bodysize != 20) throw new IcepException("family = " + family + " but bodysize = " + bodysize);
final int port = buffer.getShort() & 0xffff;
byte[] bytes = new byte[family == 0x0002 ? 16 : 4];
buffer.get(bytes);
try {
this.address = new InetSocketAddress(InetAddress.getByAddress(bytes), port);
} catch (UnknownHostException e) {
throw new IcepException("port = " + port + " and address = " + Utility.binToHexString(bytes), e);
}
return this;
}
@Override
public ByteBuffer encode(final ByteBuffer buffer, final byte[] transactionid) {
final boolean ipv6 = this.address.getAddress() instanceof Inet6Address;
buffer.putShort((short) getAttributeid());
buffer.putShort((short) (ipv6 ? 20 : 8));
buffer.putShort((short) (ipv6 ? 0x0002 : 0x0001));
buffer.putShort((short) this.address.getPort());
final byte[] bytes = this.address.getAddress().getAddress();
buffer.put(bytes);
return buffer;
}
@Override
public short getAttributeid() {
return 0x0001;
}
@Override
public String getName() {
return "MAPPED-ADDRESS";
}
public InetSocketAddress getInetSocketAddress() {
return address;
}
@Override
public String toString() {
return getName() + ":" + address;
}
}

View File

@@ -1,97 +0,0 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package com.wentch.redkale.net.icep.attr;
import com.wentch.redkale.net.icep.*;
import com.wentch.redkale.util.*;
import java.net.*;
import java.nio.*;
/**
*
* @author zhangjx
*/
public class XorMappedAddressAttribute extends MappedAddressAttribute {
public XorMappedAddressAttribute() {
}
public XorMappedAddressAttribute(InetSocketAddress address) {
super(address);
}
/**
0000 b8 2a 72 c8 7c 7e 08 57 00 60 3b f6 08 00 45 00 .*r.|~.W.`;...E.
0010 00 78 00 00 40 00 30 11 6f 1a d8 5d f6 12 0a 1c .x..@.0.o..]....
0020 02 cf 0d 96 e2 ba 00 64 f0 b3
01 01 00 48 21 12 a4 42 50 38 69 55 2b 65 78 66 4e 68 76 32 00 01 .BP8iU+exfNhv2..
0040 00 08 00 01 e2 ba 71 5c fb ed 00 04 00 08 00 01 ......q\........
0050 0d 96 d8 5d f6 12 00 05 00 08 00 01 0d 97 d8 5d ...]...........]
0060 f6 0f 80 20 00 08 00 01 c3 a8 50 4e 5f af 80 22 ... ......PN_.."
0070 00 14 56 6f 76 69 64 61 2e 6f 72 67 20 30 2e 39 ..Vovida.org 0.9
0080 37 2d 43 50 43 00 7-CPC.
@param args
@throws Exception
*/
public static void main(String[] args) throws Exception {
final byte[] transactionid = format("21 12 a4 42 50 38 69 55 2b 65 78 66 4e 68 76 32");
byte[] attrs = format("80 20 00 08 00 01 c3 a8 50 4e 5f af");
XorMappedAddressAttribute attr = new XorMappedAddressAttribute().decode(ByteBuffer.wrap(attrs), transactionid);
System.out.println(attr);
ByteBuffer buffer = ByteBuffer.allocate(1024);
attr.encode(buffer, transactionid);
buffer.flip();
Utility.println(null, buffer);
}
@Override
public XorMappedAddressAttribute decode(final ByteBuffer buffer, final byte[] transactionid) {
final short attrid = (short) (buffer.getShort() & 0x00ff);
if (attrid != getAttributeid()) throw new IcepException(this.getClass().getSimpleName() + " has illegal attributeid " + attrid);
final int bodysize = buffer.getShort() & 0xffff;
final short family = buffer.getShort();
if (family == 0x0001 && bodysize != 8) throw new IcepException("family = " + family + " but bodysize = " + bodysize);
if (family == 0x0002 && bodysize != 20) throw new IcepException("family = " + family + " but bodysize = " + bodysize);
final int port = (buffer.getShort() ^ ((transactionid[0] << 8 & 0x0000FF00) | (transactionid[1] & 0x000000FF))) & 0xffff;
byte[] bytes = new byte[family == 0x0002 ? 16 : 4];
buffer.get(bytes);
for (int i = 0; i < bytes.length; i++) {
bytes[i] ^= transactionid[i];
}
try {
this.address = new InetSocketAddress(InetAddress.getByAddress(bytes), port);
} catch (UnknownHostException e) {
throw new IcepException("port = " + port + " and address = " + Utility.binToHexString(bytes), e);
}
return this;
}
@Override
public ByteBuffer encode(final ByteBuffer buffer, final byte[] transactionid) {
final boolean ipv6 = this.address.getAddress() instanceof Inet6Address;
buffer.putShort((short) getAttributeid());
buffer.putShort((short) (ipv6 ? 20 : 8));
buffer.putShort((short) (ipv6 ? 0x0002 : 0x0001));
buffer.putShort((short) (this.address.getPort() ^ ((transactionid[0] << 8 & 0x0000FF00) | (transactionid[1] & 0x000000FF))));
final byte[] bytes = this.address.getAddress().getAddress();
for (int i = 0; i < bytes.length; i++) {
bytes[i] ^= transactionid[i];
}
buffer.put(bytes);
return buffer;
}
@Override
public short getAttributeid() {
return 0x0020;
}
@Override
public String getName() {
return "XOR-MAPPED-ADDRESS";
}
}

View File

@@ -1,203 +0,0 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package com.wentch.redkale.net.icep.rtp;
import com.wentch.redkale.net.icep.*;
import java.nio.*;
/**
* The RTP header has the following format:
*
* 0 1 2 3
* 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
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* |V=2|P|X| CC |M| PT | sequence number |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | timestamp |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | synchronization source (SSRC) identifier |
* +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
* | contributing source (CSRC) identifiers |
* | |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
* The first twelve octets are present in every RTP packet, while the
* list of CSRC identifiers is present only when inserted by a mixer.
*
* The version defined by RFC3550 specification is two.
*
* @author zhangjx
*/
public class RtpHeader implements IcepCoder<RtpHeader> {
/**
* 该值占4个字节 由7种数据组成按位存储
* version(2bits) + padding(1bit) + extend(1bit) + crscs(4bits) + marker(1bit) + payloadtype(7bits) + sn(16bits)
* version : 占2比特。 表示RTP 的版本号 0b10。
* padding : 占1比特。 置“1”表示用户数据最后加有填充位用户数据中最后一个字节是填充位计数它表示一共加了多少个填充位。
* 在两种情况下可能需要填充: 一是某些加密算法要求数据块大小固定二是在一个低层协议数据包中装载多个RTP 分组。
* extend : 占1比特。 置“1”表示RTP 报头后紧随一个扩展报头。
* crscs : 占4比特。 CSRC计数包括紧接在固定头后CSRC标识符个数。
* marker : 占1比特。 标记解释由设置定义,目的在于允许重要事件在包流中标记出来。设置可定义其他标示位,或通过改变位数量来指定没有标记位。
* payloadtype : 占7比特。 载荷类型: 记录后面资料使用哪种 Codec receiver 端找出相应的 decoder 解码出來。
* sn : 占16比特。 每发送一个RTP数据包该序号增加1。该序号在接收方可用来发现丢失的数据包和对到来的数据包进行排序。 初值为随机数每发送一个增加1。可供接收方检测分组丢失和恢复分组次序。
*
*/
private int headval = 0b10_0_0_0000_0_0000000_0000000000000000;
/**
* 占4个字节。 时间戳 表示RTP分组第一个字节的取样时刻。其初值为随机数每个采用周期加1。如果每次传送20ms的数据由于音频的采样频率为8000Hz即每20ms有160次采样则每传送20ms的数据时戳增加160。
*/
private int timestamp;
/**
* 同步源标识符SSRC 相当于每个数据流的唯一ID
* 占4字节。 用来标识一个同步源。此标识符是随机选择的但要保证同一RTP会话中的任意两个SSRC各不相同RTP必须检测并解决冲突。
*/
private int ssrc;
/**
* 提供源标识符CSRC
* 占0-60个字节。 它可有0~15项标识符每一项长度固定为32比特其项数由CC字段crscs来确定。如果提供源多于15个则只有15个被标识。
*/
private int[] csrc;
/**
* 占2字节
*/
private short exttype;
/**
* 扩展数据
* 占4*N字节 必须是4字节的倍数
*/
private byte[] extdata;
@Override
public RtpHeader decode(final ByteBuffer buffer) {
this.headval = buffer.getInt();
this.timestamp = buffer.getInt();
this.ssrc = buffer.getInt();
final int csrcs = getCrscs();
if (csrcs > 0) {
this.csrc = new int[csrcs];
for (int i = 0; i < csrcs; i++) {
this.csrc[i] = buffer.getInt();
}
}
if (isExtend()) {
this.exttype = buffer.getShort();
int extdatalen = (buffer.getShort() & 0xffff) * 4;
this.extdata = new byte[extdatalen];
buffer.get(extdata);
}
return this;
}
@Override
public ByteBuffer encode(final ByteBuffer buffer) {
buffer.putInt(this.headval);
buffer.putInt(this.timestamp);
buffer.putInt(this.ssrc);
final int csrcs = getCrscs();
if (csrcs > 0) {
for (int i = 0; i < csrcs; i++) {
buffer.putInt(this.csrc[i]);
}
}
if (isExtend()) {
buffer.putShort(this.exttype);
buffer.putShort((short) (this.extdata.length / 4));
buffer.put(this.extdata);
}
return buffer;
}
public static int getSsrc(final ByteBuffer buffer) {
return buffer.getInt(8);
}
public int getVersion() {
return (headval >> 30) & 0b11;
}
public boolean isPadding() {
return (headval & 0b00_1_0_0000_0_0000000_0000000000000000) > 0;
}
public void setPadding(boolean padding) {
if (padding) {
headval |= 0b00_1_0_0000_0_0000000_0000000000000000;
} else {
headval &= 0b11_0_1_1111_1_1111111_1111111111111111;
}
}
public boolean isExtend() {
return (headval & 0b00_0_1_0000_0_0000000_0000000000000000) > 0;
}
public short getExttype() {
return exttype;
}
public void setExttype(short exttype) {
this.exttype = exttype;
}
public int[] getCsrc() {
return csrc;
}
public void setCsrc(int[] csrc) {
this.csrc = csrc != null && csrc.length > 0 ? csrc : null;
if (this.csrc != null) {
this.headval = (headval & 0b11_1_1_0000_1_1111111_1111111111111111) | ((csrc.length << 24) & 0b00_0_0_1111_0_0000000_0000000000000000);
} else {
this.headval &= 0b11_1_1_0000_1_1111111_1111111111111111;
}
}
public byte[] getExtdata() {
return extdata;
}
public void setExtdata(byte[] exdata) {
boolean extend = exdata != null || exdata.length > 0;
if (extend) {
if ((exdata.length & 0b100) > 0) throw new RuntimeException("extdata length(" + exdata.length + ") is illegal");
headval |= 0b00_0_1_0000_0_0000000_0000000000000000;
} else {
headval &= 0b11_1_0_1111_1_1111111_1111111111111111;
}
this.extdata = (exdata != null && exdata.length > 0) ? exdata : null;
}
public int getCrscs() {
return (headval >> 24) & 0b1111;
}
public boolean isMarker() {
return (headval & 0b00_0_0_0000_1_0000000_0000000000000000) > 0;
}
public int getPayloadtype() {
return (headval >> 16) & 0b1111111;
}
public void setPayloadtype(int payloadtype) {
headval = (headval & 0b11_1_1_1111_1_0000000_1111111111111111) | ((payloadtype << 16) & 0b00_0_0_0000_0_1111111_0000000000000000);
}
public int getSeqnumber() {
return headval & 0xFFFF;
}
public void setSeqnumber(int seqnumber) {
headval = (headval >> 16 << 16) | (seqnumber & 0x0000FFFF);
}
}

View File

@@ -1,36 +0,0 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package com.wentch.redkale.net.icep.rtp;
import com.wentch.redkale.net.icep.*;
import java.nio.*;
/**
*
* @author zhangjx
*/
public class RtpPacket implements IcepCoder<RtpPacket> {
private RtpHeader header;
private byte[] payload;
@Override
public RtpPacket decode(final ByteBuffer buffer) {
if (header == null) this.header = new RtpHeader();
this.header.decode(buffer);
this.payload = new byte[buffer.remaining()];
buffer.get(payload);
return this;
}
@Override
public ByteBuffer encode(final ByteBuffer buffer) {
this.header.encode(buffer).put(payload);
return buffer;
}
}

View File

@@ -1,23 +0,0 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package com.wentch.redkale.net.icep.stun;
import java.nio.*;
/**
*
* @author zhangjx
*/
public abstract class StunAttribute {
public abstract StunAttribute decode(final ByteBuffer buffer, final byte[] transactionid);
public abstract ByteBuffer encode(final ByteBuffer buffer, final byte[] transactionid);
public abstract short getAttributeid();
public abstract String getName();
}

View File

@@ -1,127 +0,0 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package com.wentch.redkale.net.icep.stun;
import com.wentch.redkale.net.icep.*;
import com.wentch.redkale.util.*;
import java.nio.*;
import java.security.*;
/**
*
* @author zhangjx
*/
public class StunHeader implements IcepCoder<StunHeader> {
public static final int MAGIC_COOKIE = 0x2112A442;
//---------------------------- type -------------------------
private static final int TYPE_BIT_MASK = 0x0110;
public static final short TYPE_REQUEST = 0x0000;
public static final short TYPE_INDICATION = 0x0010;
public static final short TYPE_SUCCESS = 0x0100;
public static final short TYPE_ERROR = 0x0110;
//---------------------------- action -------------------------
public static final int ACTION_BIT_MASK = 0xCEEF;
public static final short ACTION_BINDING = 0x0001;
public static final short ACTION_ALLOCATE = 0x0003;
public static final short ACTION_REFRESH = 0x0004;
public static final short ACTION_SEND = 0x0006;
public static final short ACTION_DATA = 0x0007;
public static final short ACTION_CREATE_PERMISSION = 0x0008;
public static final short ACTION_CHANNELBIND = 0x0009;
//-----------------------------------------------------------
private short requestid; //无符号 2bytes 首位2bits必定是00 所以该值不会为负数
private char bodysize; //无符号 2bytes
private byte[] transactionid; //RFC5389 =MAGIC_COOKIE + byte[12] = byte[16];
public static byte[] generateTransactionid() {
byte[] transactions = new byte[16];
// Get a secure PRNG
SecureRandom random = new SecureRandom();
random.nextBytes(transactions);
transactions[0] = 0x21;
transactions[1] = 0x12;
transactions[2] = (byte) 0xA4;
transactions[3] = 0x42;
return transactions;
}
public StunHeader(short requestid, byte[] transactionid0) {
this.requestid = requestid;
this.transactionid = transactionid0 == null ? generateTransactionid() : transactionid0;
}
@Override
public StunHeader decode(final ByteBuffer buffer) {
this.requestid = buffer.getShort();
this.bodysize = buffer.getChar();
this.transactionid = new byte[16];
buffer.get(transactionid);
return this;
}
@Override
public ByteBuffer encode(final ByteBuffer buffer) {
buffer.putShort(this.requestid);
buffer.putChar(this.bodysize);
buffer.put(transactionid);
return buffer;
}
@Override
public String toString() {
return this.getClass().getSimpleName() + "[requestid = " + format(requestid) + ", bodysize = " + (int) (bodysize) + ", transactionid = " + Utility.binToHexString(transactionid) + "]";
}
private static String format(short value) {
String str = Integer.toHexString(value);
if (str.length() == 1) return "0x000" + str;
if (str.length() == 2) return "0x00" + str;
if (str.length() == 3) return "0x0" + str;
return "0x" + str;
}
public void setRequestid(int requestid) {
this.requestid = (short) requestid;
}
public void setRequestid(short requestid) {
this.requestid = requestid;
}
public void setBodysize(char bodysize) {
this.bodysize = bodysize;
}
public void setBodysize(int bodysize) {
this.bodysize = (char) bodysize;
}
public int getBodysize() {
return bodysize;
}
public byte[] getTransactionid() {
return transactionid;
}
}

View File

@@ -1,49 +0,0 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package com.wentch.redkale.net.icep.stun;
import java.nio.*;
import java.util.*;
/**
*
* @author zhangjx
*/
public class StunPacket {
private StunHeader header;
private final List<StunAttribute> attributes = new ArrayList<>();
public StunPacket(StunHeader header) {
this.header = header;
}
public ByteBuffer encode(final ByteBuffer buffer) {
int start = buffer.position();
header.encode(buffer);
final byte[] transactionid = header.getTransactionid();
for (StunAttribute attr : attributes) {
attr.encode(buffer, transactionid);
}
int end = buffer.position();
buffer.putShort(start + 2, (short) (end - start - 20));
return buffer;
}
public void addAttribute(StunAttribute attribute) {
this.attributes.add(attribute);
}
public StunHeader getHeader() {
return header;
}
public List<StunAttribute> getAttributes() {
return attributes;
}
}