use of zmq.util.ValueReference in project jeromq by zeromq.
the class StreamEngine method handshake.
// Detects the protocol used by the peer.
private boolean handshake() {
assert (handshaking);
assert (greetingRecv.position() < greetingSize);
final Mechanisms mechanism = options.mechanism;
assert (mechanism != null);
// Position of the version field in the greeting.
final int revisionPos = SIGNATURE_SIZE;
// Make sure batch sizes match large buffer sizes
final int inBatchSize = Math.max(options.rcvbuf, Config.IN_BATCH_SIZE.getValue());
final int outBatchSize = Math.max(options.sndbuf, Config.OUT_BATCH_SIZE.getValue());
// Receive the greeting.
while (greetingRecv.position() < greetingSize) {
final int n = read(greetingRecv);
if (n == 0) {
error(ErrorReason.CONNECTION);
return false;
}
if (n == -1) {
if (!errno.is(ZError.EAGAIN)) {
error(ErrorReason.CONNECTION);
}
return false;
}
// peer is using unversioned protocol.
if ((greetingRecv.get(0) & 0xff) != 0xff) {
// then the other peer is using ZMTP 1.0.
break;
}
if (greetingRecv.position() < SIGNATURE_SIZE) {
continue;
}
// (i.e. the peer is using the unversioned protocol).
if ((greetingRecv.get(9) & 0x01) != 0x01) {
break;
}
// If the least significant bit is 1, the peer is using ZMTP 2.0 or later
// and has sent us the ZMTP signature.
int outpos = greetingSend.position();
// Send the major version number.
if (greetingSend.limit() == SIGNATURE_SIZE) {
if (outsize == 0) {
ioObject.setPollOut(handle);
}
greetingSend.limit(SIGNATURE_SIZE + 1);
// Major version number
greetingSend.put(revisionPos, Protocol.V3.revision);
outsize += 1;
}
if (greetingRecv.position() > SIGNATURE_SIZE) {
if (greetingSend.limit() == SIGNATURE_SIZE + 1) {
if (outsize == 0) {
ioObject.setPollOut(handle);
}
// We read a further byte, which indicates the ZMTP version.
byte protocol = greetingRecv.get(revisionPos);
if (protocol == Protocol.V1.revision || protocol == Protocol.V2.revision) {
// If this is V1 or V2, we have a ZMTP 2.0 peer.
greetingSend.limit(V2_GREETING_SIZE);
greetingSend.position(SIGNATURE_SIZE + 1);
// Socket type
greetingSend.put((byte) options.type);
outsize += 1;
} else {
// If this is 3 or greater, we have a ZMTP 3.0 peer.
greetingSend.limit(V3_GREETING_SIZE);
greetingSend.position(SIGNATURE_SIZE + 1);
// Minor version number
greetingSend.put((byte) 0);
outsize += 1;
greetingSend.mark();
greetingSend.put(new byte[20]);
assert (mechanism == Mechanisms.NULL || mechanism == Mechanisms.PLAIN || mechanism == Mechanisms.CURVE || mechanism == Mechanisms.GSSAPI);
greetingSend.reset();
greetingSend.put(mechanism.name().getBytes(ZMQ.CHARSET));
greetingSend.reset();
greetingSend.position(greetingSend.position() + 20);
outsize += 20;
greetingSend.put(new byte[32]);
outsize += 32;
greetingSize = V3_GREETING_SIZE;
}
}
}
greetingSend.position(outpos);
}
// messages.
if ((greetingRecv.get(0) & 0xff) != 0xff || (greetingRecv.get(9) & 0x01) == 0) {
// If the least significant bit is 0, then the other peer is using ZMTP 1.0.
if (session.zapEnabled()) {
// reject ZMTP 1.0 connections if ZAP is enabled
error(ErrorReason.PROTOCOL);
return false;
}
zmtpVersion = Protocol.V0;
encoder = new V1Encoder(errno, outBatchSize);
decoder = new V1Decoder(errno, inBatchSize, options.maxMsgSize, options.allocator);
// We have already sent the message header.
// Since there is no way to tell the encoder to
// skip the message header, we simply throw that
// header data away.
final int headerSize = options.identitySize + 1 >= 255 ? 10 : 2;
ByteBuffer tmp = ByteBuffer.allocate(headerSize);
// Prepare the identity message and load it into encoder.
// Then consume bytes we have already sent to the peer.
Msg txMsg = new Msg(options.identitySize);
txMsg.put(options.identity, 0, options.identitySize);
encoder.loadMsg(txMsg);
ValueReference<ByteBuffer> bufferp = new ValueReference<>(tmp);
int bufferSize = encoder.encode(bufferp, headerSize);
assert (bufferSize == headerSize);
// Make sure the decoder sees the data we have already received.
decodeDataAfterHandshake(0);
// message into the incoming message stream.
if (options.type == ZMQ.ZMQ_PUB || options.type == ZMQ.ZMQ_XPUB) {
subscriptionRequired = true;
}
// We are sending our identity now and the next message
// will come from the socket.
nextMsg = pullMsgFromSession;
// We are expecting identity message.
processMsg = processIdentity;
} else if (greetingRecv.get(revisionPos) == Protocol.V1.revision) {
// ZMTP/1.0 framing.
zmtpVersion = Protocol.V1;
if (session.zapEnabled()) {
// reject ZMTP 1.0 connections if ZAP is enabled
error(ErrorReason.PROTOCOL);
return false;
}
encoder = new V1Encoder(errno, outBatchSize);
decoder = new V1Decoder(errno, inBatchSize, options.maxMsgSize, options.allocator);
decodeDataAfterHandshake(V2_GREETING_SIZE);
} else if (greetingRecv.get(revisionPos) == Protocol.V2.revision) {
// ZMTP/2.0 framing.
zmtpVersion = Protocol.V2;
if (session.zapEnabled()) {
// reject ZMTP 2.0 connections if ZAP is enabled
error(ErrorReason.PROTOCOL);
return false;
}
encoder = new V2Encoder(errno, outBatchSize);
decoder = new V2Decoder(errno, inBatchSize, options.maxMsgSize, options.allocator);
decodeDataAfterHandshake(V2_GREETING_SIZE);
} else {
zmtpVersion = Protocol.V3;
encoder = new V2Encoder(errno, outBatchSize);
decoder = new V2Decoder(errno, inBatchSize, options.maxMsgSize, options.allocator);
greetingRecv.position(V2_GREETING_SIZE);
if (mechanism.isMechanism(greetingRecv)) {
this.mechanism = mechanism.create(session, peerAddress, options);
} else {
error(ErrorReason.PROTOCOL);
return false;
}
nextMsg = nextHandshakeCommand;
processMsg = processHandshakeCommand;
}
// Start polling for output if necessary.
if (outsize == 0) {
ioObject.setPollOut(handle);
}
// Handshaking was successful.
// Switch into the normal message flow.
handshaking = false;
if (hasHandshakeTimer) {
ioObject.cancelTimer(HANDSHAKE_TIMER_ID);
hasHandshakeTimer = false;
}
socket.eventHandshaken(endpoint, zmtpVersion.ordinal());
return true;
}
use of zmq.util.ValueReference in project jeromq by zeromq.
the class StreamEngine method inEvent.
@Override
public void inEvent() {
assert (!ioError);
// If still handshaking, receive and process the greeting message.
if (handshaking) {
if (!handshake()) {
return;
}
}
assert (decoder != null);
// If there has been an I/O error, stop polling.
if (inputStopped) {
ioObject.removeHandle(handle);
handle = null;
ioError = true;
return;
}
// If there's no data to process in the buffer...
if (insize == 0) {
// Retrieve the buffer and read as much data as possible.
// Note that buffer can be arbitrarily large. However, we assume
// the underlying TCP layer has fixed buffer size and thus the
// number of bytes read will be always limited.
inpos = decoder.getBuffer();
int rc = read(inpos);
if (rc == 0) {
error(ErrorReason.CONNECTION);
}
if (rc == -1) {
if (!errno.is(ZError.EAGAIN)) {
error(ErrorReason.CONNECTION);
}
return;
}
// Adjust input size
inpos.flip();
insize = rc;
}
boolean rc = false;
ValueReference<Integer> processed = new ValueReference<>(0);
while (insize > 0) {
// Push the data to the decoder.
Step.Result result = decoder.decode(inpos, insize, processed);
assert (processed.get() <= insize);
insize -= processed.get();
if (result == Step.Result.MORE_DATA) {
rc = true;
break;
}
if (result == Step.Result.ERROR) {
rc = false;
break;
}
Msg msg = decoder.msg();
rc = processMsg.apply(msg);
if (!rc) {
break;
}
}
// or the session has rejected the message.
if (!rc) {
if (!errno.is(ZError.EAGAIN)) {
error(ErrorReason.PROTOCOL);
return;
}
inputStopped = true;
ioObject.resetPollIn(handle);
}
// Flush all messages the decoder may have produced.
session.flush();
}
use of zmq.util.ValueReference in project jeromq by zeromq.
the class V1EncoderTest method testReaderLong.
@Test
public void testReaderLong() {
Msg msg = readLongMessage1();
ValueReference<ByteBuffer> ref = new ValueReference<>();
int outsize = encoder.encode(ref, 0);
assertThat(outsize, is(0));
ByteBuffer out = ref.get();
assertThat(out, nullValue());
encoder.loadMsg(msg);
outsize = encoder.encode(ref, 64);
assertThat(outsize, is(64));
out = ref.get();
int position = out.position();
int limit = out.limit();
assertThat(limit, is(64));
assertThat(position, is(64));
ref.set(null);
outsize = encoder.encode(ref, 64);
assertThat(outsize, is(138));
out = ref.get();
position = out.position();
limit = out.limit();
assertThat(position, is(62));
assertThat(limit, is(200));
}
use of zmq.util.ValueReference in project jeromq by zeromq.
the class V2EncoderTest method testReaderLong.
@Test
public void testReaderLong() {
Msg msg = readLongMessage1();
ValueReference<ByteBuffer> ref = new ValueReference<>();
int outsize = encoder.encode(ref, 0);
assertThat(outsize, is(0));
ByteBuffer out = ref.get();
assertThat(out, nullValue());
encoder.loadMsg(msg);
outsize = encoder.encode(ref, 64);
assertThat(outsize, is(64));
out = ref.get();
int position = out.position();
int limit = out.limit();
assertThat(limit, is(64));
assertThat(position, is(64));
ref.set(null);
outsize = encoder.encode(ref, 64);
assertThat(outsize, is(138));
out = ref.get();
position = out.position();
limit = out.limit();
assertThat(position, is(62));
assertThat(limit, is(200));
}
use of zmq.util.ValueReference in project jeromq by zeromq.
the class AbstractDecoderTest method testReaderMultipleMsg.
@Test
public void testReaderMultipleMsg() {
ByteBuffer in = decoder.getBuffer();
int insize = readShortMessage(in);
assertThat(insize, is(7));
readShortMessage(in);
in.flip();
ValueReference<Integer> processed = new ValueReference<>(0);
decoder.decode(in, 14, processed);
assertThat(processed.get(), is(7));
assertThat(in.position(), is(7));
assertThat(decoder.msg(), notNullValue());
Step.Result result = decoder.decode(in, 6, processed);
assertThat(processed.get(), is(6));
assertThat(in.position(), is(13));
assertThat(result, is(Step.Result.MORE_DATA));
result = decoder.decode(in, 10, processed);
assertThat(processed.get(), is(1));
assertThat(in.position(), is(14));
assertThat(result, is(Step.Result.DECODED));
assertThat(decoder.msg(), notNullValue());
}
Aggregations