use of net.morimekta.util.io.BigEndianBinaryReader in project providence by morimekta.
the class NonblockingSocketServer method handleRead.
@SuppressWarnings("unchecked")
private void handleRead(SelectionKey key, Context context) throws IOException {
long startTime = System.nanoTime();
// part a: read into the readBuffer.
if (context.currentFrameSize == 0) {
// read frame size.
try {
if (context.channel.read(context.sizeBuffer) < 0) {
context.close();
key.cancel();
return;
}
if (context.sizeBuffer.position() < 4) {
return;
}
} catch (IOException e) {
// LOGGER.error(e.getMessage(), e);
context.close();
key.cancel();
return;
}
context.sizeBuffer.flip();
try (ByteBufferInputStream in = new ByteBufferInputStream(context.sizeBuffer);
BigEndianBinaryReader reader = new BigEndianBinaryReader(in)) {
context.currentFrameSize = reader.expectInt();
}
context.sizeBuffer.rewind();
if (context.currentFrameSize > maxFrameSizeInBytes) {
LOGGER.warn("Attempting message of " + context.currentFrameSize + " > " + maxFrameSizeInBytes);
context.close();
key.cancel();
return;
}
if (context.currentFrameSize < 1) {
LOGGER.warn("Attempting message of " + context.currentFrameSize);
context.close();
key.cancel();
return;
}
context.readBuffer.rewind();
context.readBuffer.limit(context.currentFrameSize);
}
try {
if (context.channel.read(context.readBuffer) < 0) {
LOGGER.warn("Closed connection while reading frame");
context.close();
key.cancel();
return;
}
} catch (IOException e) {
LOGGER.warn("Exception reading frame: {}", e.getMessage(), e);
context.close();
key.cancel();
return;
}
if (context.readBuffer.position() < context.readBuffer.limit()) {
// wait until next read, and see if remaining of frame has arrived.
return;
}
// part b: if the read buffer is complete, handle the content.
PServiceCall call;
try {
context.currentFrameSize = 0;
context.readBuffer.flip();
call = serializer.deserialize(new ByteBufferInputStream(context.readBuffer), processor.getDescriptor());
context.readBuffer.clear();
workerExecutor.submit(() -> {
PServiceCall reply;
try {
reply = processor.handleCall(call);
} catch (Exception e) {
reply = new PServiceCall<>(call.getMethod(), PServiceCallType.EXCEPTION, call.getSequence(), PApplicationException.builder().setMessage(e.getMessage()).setId(PApplicationExceptionType.INTERNAL_ERROR).initCause(e).build());
}
synchronized (context.writeQueue) {
context.writeQueue.offer(new WriteEntry(startTime, call, reply));
key.interestOps(key.interestOps() | SelectionKey.OP_WRITE);
selector.wakeup();
}
});
} catch (IOException e) {
double duration = ((double) System.nanoTime() - startTime) / NS_IN_MILLIS;
instrumentation.onTransportException(e, duration, null, null);
}
}
use of net.morimekta.util.io.BigEndianBinaryReader in project providence by morimekta.
the class BinaryFormatUtils method readMessage.
/**
* Read message from reader.
*
* @param input The input reader.
* @param descriptor The message descriptor.
* @param strict If the message should be read in strict mode.
* @param <Message> The message type.
* @param <Field> The field type.
* @return The read and parsed message.
* @throws IOException If read failed.
*/
public static <Message extends PMessage<Message, Field>, Field extends PField> Message readMessage(BigEndianBinaryReader input, PMessageDescriptor<Message, Field> descriptor, boolean strict) throws IOException {
PMessageBuilder<Message, Field> builder = descriptor.builder();
if (builder instanceof BinaryReader) {
((BinaryReader) builder).readBinary(input, strict);
} else {
FieldInfo fieldInfo = readFieldInfo(input);
while (fieldInfo != null) {
PField field = descriptor.findFieldById(fieldInfo.getId());
if (field != null) {
Object value = readFieldValue(input, fieldInfo, field.getDescriptor(), strict);
builder.set(field.getId(), value);
} else {
readFieldValue(input, fieldInfo, null, false);
}
fieldInfo = readFieldInfo(input);
}
if (strict) {
try {
builder.validate();
} catch (IllegalStateException e) {
throw new SerializerException(e, e.getMessage());
}
}
}
return builder.build();
}
use of net.morimekta.util.io.BigEndianBinaryReader in project providence by morimekta.
the class BinarySerializer method deserialize.
@Nonnull
@Override
@SuppressWarnings("unchecked")
public <Message extends PMessage<Message, Field>, Field extends PField> PServiceCall<Message, Field> deserialize(@Nonnull InputStream is, @Nonnull PService service) throws IOException {
BigEndianBinaryReader in = new BigEndianBinaryReader(is);
String methodName = null;
int sequence = 0;
PServiceCallType type = null;
try {
int methodNameLen = in.expectInt();
int typeKey;
// versioned
if (methodNameLen <= 0) {
int version = methodNameLen & VERSION_MASK;
if (version == VERSION_1) {
typeKey = methodNameLen & 0xFF;
methodNameLen = in.expectInt();
if (methodNameLen > MAX_METHOD_NAME_LEN) {
throw new SerializerException("Exceptionally long method name of %s bytes", methodNameLen).setExceptionType(PApplicationExceptionType.PROTOCOL_ERROR);
}
if (methodNameLen < 1) {
throw new SerializerException("Exceptionally short method name of %s bytes", methodNameLen).setExceptionType(PApplicationExceptionType.PROTOCOL_ERROR);
}
methodName = new String(in.expectBytes(methodNameLen), UTF_8);
} else {
throw new SerializerException("Bad protocol version: %08x", version >>> 16).setExceptionType(PApplicationExceptionType.INVALID_PROTOCOL);
}
} else {
if (strict && versioned) {
throw new SerializerException("Missing protocol version").setExceptionType(PApplicationExceptionType.INVALID_PROTOCOL);
}
if (methodNameLen > MAX_METHOD_NAME_LEN) {
if (methodNameLen >>> 24 == '<') {
throw new SerializerException("Received HTML in service call").setExceptionType(PApplicationExceptionType.PROTOCOL_ERROR);
}
if (methodNameLen >>> 24 == '{' || methodNameLen >>> 24 == '[') {
throw new SerializerException("Received JSON in service call").setExceptionType(PApplicationExceptionType.PROTOCOL_ERROR);
}
throw new SerializerException("Exceptionally long method name of %s bytes", methodNameLen).setExceptionType(PApplicationExceptionType.PROTOCOL_ERROR);
}
methodName = new String(in.expectBytes(methodNameLen), UTF_8);
typeKey = in.expectByte();
}
sequence = in.expectInt();
type = PServiceCallType.findById(typeKey);
PServiceMethod method = service.getMethod(methodName);
if (type == null) {
throw new SerializerException("Invalid call type " + typeKey).setExceptionType(PApplicationExceptionType.INVALID_MESSAGE_TYPE);
} else if (type == PServiceCallType.EXCEPTION) {
PApplicationException ex = readMessage(in, PApplicationException.kDescriptor, strict);
return (PServiceCall<Message, Field>) new PServiceCall<>(methodName, type, sequence, ex);
} else if (method == null) {
throw new SerializerException("No such method " + methodName + " on " + service.getQualifiedName()).setExceptionType(PApplicationExceptionType.UNKNOWN_METHOD);
}
@SuppressWarnings("unchecked") PMessageDescriptor<Message, Field> descriptor = isRequestCallType(type) ? method.getRequestType() : method.getResponseType();
Message message = readMessage(in, descriptor, strict);
return new PServiceCall<>(methodName, type, sequence, message);
} catch (SerializerException se) {
throw new SerializerException(se).setMethodName(methodName).setCallType(type).setSequenceNo(sequence);
} catch (IOException e) {
throw new SerializerException(e, e.getMessage()).setMethodName(methodName).setCallType(type).setSequenceNo(sequence);
}
}
use of net.morimekta.util.io.BigEndianBinaryReader in project providence by morimekta.
the class FramedBufferInputStream method readFrame.
private int readFrame() throws IOException {
frameSizeBuffer.rewind();
in.read(frameSizeBuffer);
if (frameSizeBuffer.position() == 0) {
return -1;
}
if (frameSizeBuffer.position() < Integer.BYTES) {
throw new IOException("Not enough bytes for frame size: " + frameSizeBuffer.position());
}
frameSizeBuffer.flip();
int frameSize;
try (ByteBufferInputStream in = new ByteBufferInputStream(frameSizeBuffer);
BigEndianBinaryReader reader = new BigEndianBinaryReader(in)) {
frameSize = reader.expectInt();
}
if (frameSize < 1) {
throw new IOException("Invalid frame size " + frameSize);
} else if (frameSize > buffer.capacity()) {
IOException ex = new IOException("Frame size too large " + frameSize + " > " + buffer.capacity());
try {
// Try to consume the frame so we can continue with the next.
while (frameSize > 0) {
buffer.rewind();
buffer.limit(Math.max(frameSize, buffer.capacity()));
int r = in.read(buffer);
if (r > 0) {
frameSize -= r;
} else {
break;
}
}
} catch (Exception e) {
ex.addSuppressed(e);
}
throw ex;
}
buffer.rewind();
buffer.limit(frameSize);
while (in.read(buffer) > 0) {
if (buffer.position() == frameSize) {
break;
}
LOGGER.debug("still not enough: " + buffer.position() + " of " + frameSize);
}
if (buffer.position() < frameSize) {
throw new IOException();
}
buffer.flip();
return frameSize;
}
Aggregations