All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.eclipse.jetty.websocket.common.extensions.mux.MuxGenerator Maven / Gradle / Ivy
//
// ========================================================================
// Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.websocket.common.extensions.mux;
import java.io.IOException;
import java.nio.ByteBuffer;
import org.eclipse.jetty.io.ArrayByteBufferPool;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.websocket.api.WriteCallback;
import org.eclipse.jetty.websocket.api.extensions.Frame;
import org.eclipse.jetty.websocket.api.extensions.OutgoingFrames;
import org.eclipse.jetty.websocket.common.WebSocketFrame;
import org.eclipse.jetty.websocket.common.extensions.mux.op.MuxAddChannelRequest;
import org.eclipse.jetty.websocket.common.extensions.mux.op.MuxAddChannelResponse;
import org.eclipse.jetty.websocket.common.extensions.mux.op.MuxDropChannel;
import org.eclipse.jetty.websocket.common.extensions.mux.op.MuxFlowControl;
import org.eclipse.jetty.websocket.common.extensions.mux.op.MuxNewChannelSlot;
/**
* Generate Mux frames destined for the physical connection.
*/
public class MuxGenerator
{
private static final int CONTROL_BUFFER_SIZE = 2 * 1024;
/** 4 bytes for channel ID + 1 for fin/rsv/opcode */
private static final int DATA_FRAME_OVERHEAD = 5;
private ByteBufferPool bufferPool;
private OutgoingFrames outgoing;
public MuxGenerator()
{
this(new ArrayByteBufferPool());
}
public MuxGenerator(ByteBufferPool bufferPool)
{
this.bufferPool = bufferPool;
}
public void generate(long channelId, Frame frame, WriteCallback callback)
{
ByteBuffer muxPayload = bufferPool.acquire(frame.getPayloadLength() + DATA_FRAME_OVERHEAD,false);
BufferUtil.flipToFill(muxPayload);
// start building mux payload
writeChannelId(muxPayload,channelId);
byte b = (byte)(frame.isFin()?0x80:0x00); // fin
b |= (byte)(frame.isRsv1()?0x40:0x00); // rsv1
b |= (byte)(frame.isRsv2()?0x20:0x00); // rsv2
b |= (byte)(frame.isRsv3()?0x10:0x00); // rsv3
b |= (byte)(frame.getType().getOpCode() & 0x0F); // opcode
muxPayload.put(b);
BufferUtil.put(frame.getPayload(),muxPayload);
// build muxed frame
WebSocketFrame muxFrame = WebSocketFrame.binary();
BufferUtil.flipToFlush(muxPayload,0);
muxFrame.setPayload(muxPayload);
// NOTE: the physical connection will handle masking rules for this frame.
// release original buffer (no longer needed)
bufferPool.release(frame.getPayload());
// send muxed frame down to the physical connection.
outgoing.outgoingFrame(muxFrame,callback);
}
public void generate(WriteCallback callback,MuxControlBlock... blocks) throws IOException
{
if ((blocks == null) || (blocks.length <= 0))
{
return; // nothing to do
}
ByteBuffer payload = bufferPool.acquire(CONTROL_BUFFER_SIZE,false);
BufferUtil.flipToFill(payload);
writeChannelId(payload,0); // control channel
for (MuxControlBlock block : blocks)
{
switch (block.getOpCode())
{
case MuxOp.ADD_CHANNEL_REQUEST:
{
MuxAddChannelRequest op = (MuxAddChannelRequest)block;
byte b = (byte)((op.getOpCode() & 0x07) << 5); // opcode
b |= (byte)((op.getRsv() & 0x07) << 2); // rsv
b |= (op.getEncoding() & 0x03); // enc
payload.put(b); // opcode + rsv + enc
writeChannelId(payload,op.getChannelId());
write139Buffer(payload,op.getHandshake());
break;
}
case MuxOp.ADD_CHANNEL_RESPONSE:
{
MuxAddChannelResponse op = (MuxAddChannelResponse)block;
byte b = (byte)((op.getOpCode() & 0x07) << 5); // opcode
b |= (op.isFailed()?0x10:0x00); // failure bit
b |= (byte)((op.getRsv() & 0x03) << 2); // rsv
b |= (op.getEncoding() & 0x03); // enc
payload.put(b); // opcode + f + rsv + enc
writeChannelId(payload,op.getChannelId());
if (op.getHandshake() != null)
{
write139Buffer(payload,op.getHandshake());
}
else
{
// no handshake details
write139Size(payload,0);
}
break;
}
case MuxOp.DROP_CHANNEL:
{
MuxDropChannel op = (MuxDropChannel)block;
byte b = (byte)((op.getOpCode() & 0x07) << 5); // opcode
b |= (byte)(op.getRsv() & 0x1F); // rsv
payload.put(b); // opcode + rsv
writeChannelId(payload,op.getChannelId());
write139Buffer(payload,op.asReasonBuffer());
break;
}
case MuxOp.FLOW_CONTROL:
{
MuxFlowControl op = (MuxFlowControl)block;
byte b = (byte)((op.getOpCode() & 0x07) << 5); // opcode
b |= (byte)(op.getRsv() & 0x1F); // rsv
payload.put(b); // opcode + rsv
writeChannelId(payload,op.getChannelId());
write139Size(payload,op.getSendQuotaSize());
break;
}
case MuxOp.NEW_CHANNEL_SLOT:
{
MuxNewChannelSlot op = (MuxNewChannelSlot)block;
byte b = (byte)((op.getOpCode() & 0x07) << 5); // opcode
b |= (byte)(op.getRsv() & 0x0F) << 1; // rsv
b |= (byte)(op.isFallback()?0x01:0x00); // fallback bit
payload.put(b); // opcode + rsv + fallback bit
write139Size(payload,op.getNumberOfSlots());
write139Size(payload,op.getInitialSendQuota());
break;
}
}
}
BufferUtil.flipToFlush(payload,0);
WebSocketFrame frame = WebSocketFrame.binary();
frame.setPayload(payload);
outgoing.outgoingFrame(frame,callback);
}
public OutgoingFrames getOutgoing()
{
return outgoing;
}
public void setOutgoing(OutgoingFrames outgoing)
{
this.outgoing = outgoing;
}
/**
* Write a 1/3/9 encoded size, then a byte buffer of that size.
*
* @param payload
* @param buffer
*/
public void write139Buffer(ByteBuffer payload, ByteBuffer buffer)
{
write139Size(payload,buffer.remaining());
writeBuffer(payload,buffer);
}
/**
* Write a 1/3/9 encoded size.
*
* @param payload
* @param size
*/
public void write139Size(ByteBuffer payload, long size)
{
if (size > 0xFF_FF)
{
// 9 byte encoded
payload.put((byte)0x7F);
payload.putLong(size);
return;
}
if (size >= 0x7E)
{
// 3 byte encoded
payload.put((byte)0x7E);
payload.put((byte)(size >> 8));
payload.put((byte)(size & 0xFF));
return;
}
// 1 byte (7 bit) encoded
payload.put((byte)(size & 0x7F));
}
public void writeBuffer(ByteBuffer payload, ByteBuffer buffer)
{
BufferUtil.put(buffer,payload);
}
/**
* Write multiplexing channel id, using logical channel id encoding (of 1,2,3, or 4 octets)
*
* @param payload
* @param channelId
*/
public void writeChannelId(ByteBuffer payload, long channelId)
{
if (channelId > 0x1F_FF_FF_FF)
{
throw new MuxException("Illegal Channel ID: too big");
}
if (channelId > 0x1F_FF_FF)
{
// 29 bit channel id (4 bytes)
payload.put((byte)(0xE0 | ((channelId >> 24) & 0x1F)));
payload.put((byte)((channelId >> 16) & 0xFF));
payload.put((byte)((channelId >> 8) & 0xFF));
payload.put((byte)(channelId & 0xFF));
return;
}
if (channelId > 0x3F_FF)
{
// 21 bit channel id (3 bytes)
payload.put((byte)(0xC0 | ((channelId >> 16) & 0x1F)));
payload.put((byte)((channelId >> 8) & 0xFF));
payload.put((byte)(channelId & 0xFF));
return;
}
if (channelId > 0x7F)
{
// 14 bit channel id (2 bytes)
payload.put((byte)(0x80 | ((channelId >> 8) & 0x3F)));
payload.put((byte)(channelId & 0xFF));
return;
}
// 7 bit channel id
payload.put((byte)(channelId & 0x7F));
}
}