Am 19.01.2016 um 01:18 schrieb Bruno Filipe Basilio <[email protected]>:
Hi,
Thank you for all your work in snmp4j and related.
We are using snmp4j to handle NTCIP-PMPP protocol which is based in SNMP over
TCP.
More details about NTCIP-PMPP specification, see:
http://www.ntcip.org/library/documents/pdf/pmpp01.pdf
The problem is that using upstream DefaultTcpTransportMapping some data is
discarded when the message received has a fragmented header, resulting in
incoherent message.
Some changes were made to work around the problem, but as you can see bellow,
it isn't the prettiest since we hadn't many experience coding in snmp4j.
You can see an example of the data exchange and the test code we have used to
replicate the problem using only snmp4j example code.
All feedback is appreciated, but maybe you can suggest a better solution and
add it in upstream snmp4j.
Here follows an example of the data exchanged and the fragmented response.
*Sent data*
7E 05 13 C1 30 31 02 01 00 04 06 50 75 62 6C 69 63 A0 24 02 04 28 BA 92 8B 02
01 00 02 01 00 30 16 30 14 06 10 2B 06 01 04 01 89 36 04 02 03 05 08 01 03 05
01 05 00 AE 11 7E
*Received data fragments*
1)
7E 05 13
2)
C1 30 70 02 01 00 04 06 50 75 62 6C 69 63 A2 63 02 04 28 BA 92 8B 02 01 00 02
01 00 30 55 30 53 06 10 2B 06 01 04 01 89 36 04 02 03 05 08 01 03 05 01 04 3F
44 52 49 56 45 5B 6E 6C 5D 57 49 54 48 5B 6E 6C 5D 43 41 52 45 5B 6E 70 5D 54
48 41 4E 4B 20 59 4F 55 5B
3)
6E 6C 5D 46 4F 52 20 44 52 49 56 49 4E 47 5B 6E 6C 5D 4E 57 20 50 41 52 4B 57
41 59 47 34 7E
The test code is as follows:
String host="127.0.0.1";
int port=7000;
boolean isPmpp= true;
String oid="1.3.6.1.4.1.1206.4.2.3.6.5.0";
String communityName="Public";
TcpTransportMapping transportMapping= new DefaultTcpTransportMapping();
transportMapping.setMessageLengthDecoder(new
PmppMessageLengthDecoder());
MessageDispatcher messageDispatcher = new PmppMessageDispatcher();
messageDispatcher.addMessageProcessingModel(new MPv1());
Snmp snmp= new Snmp(messageDispatcher, transportMapping);
Address targetAddress = GenericAddress.parse("tcp:" + host + "/" +
port);
// setting up target
CommunityTarget target = new CommunityTarget();
target.setCommunity(new OctetString(communityName));
target.setAddress(targetAddress);
target.setRetries(2);
target.setTimeout(1500);
target.setVersion(SnmpConstants.version1);
// creating PDU
PDU pdu = new PDU();
pdu.add(new VariableBinding(new OID(oid)));
pdu.setType(PDU.GET);
snmp.listen();
// send the PDU
ResponseEvent response = snmp.send(pdu, target);
// extract the response PDU (could be null if timed out)
PDU responsePDU = response.getResponse();
if(responsePDU==null) {
System.out.println("response null");
System.exit(-1);
}
Vector vbs = responsePDU.getVariableBindings();
Variable ret=null;
if (vbs.size() > 0) {
VariableBinding vb = (VariableBinding) vbs.get(0);
ret = vb.getVariable();
}
snmp.close();
System.out.println("s=" + ret);
*Changes suggested to work around the problem*
pt.brisa.pmv.ntcip_adapter.manager.PmppTcpTransportMapping.ServerThread.readMessage(SelectionKey,
SocketChannel, TcpAddress)
--- a/org/snmp4j/transport/DefaultTcpTransportMapping.java 2015-12-30
02:54:34.000000000 +0000
+++ b/org/snmp4j/transport/DefaultTcpTransportMapping.java 2016-01-18
23:30:53.604959600 +0000
@@ -953,12 +992,25 @@ public class DefaultTcpTransportMapping
// slow but in some cases needed:
entry = sockets.get(incomingAddress);
}
+
+ ByteBuffer readBuffer =null;
if (entry != null) {
// note that socket has been used
entry.used();
- ByteBuffer readBuffer = entry.getReadBuffer();
+ readBuffer = entry.getReadBuffer();
if (readBuffer != null) {
readChannel.read(readBuffer);
+
+ if(logger.isDebugEnabled()) {
+ logger.debug("readBuffer != null, readBuffer.position() !=
messageLengthDecoder.getMinHeaderLength():"
+ +
(readBuffer.position()!=messageLengthDecoder.getMinHeaderLength())
+ + ", readBuffer.position(): "+ readBuffer.position()
+ + ", readBuffer.limit(): "+ readBuffer.limit()
+ +", readBuffer.array():" + new
OctetString(readBuffer.array(), 0, readBuffer.limit()).toHexString());
+ }
+
+ // don't handle fragment less then header length
+ if (readBuffer.position() !=
messageLengthDecoder.getMinHeaderLength()) {
if (readBuffer.hasRemaining()) {
entry.addRegistration(selector, SelectionKey.OP_READ);
}
@@ -968,8 +1020,17 @@ public class DefaultTcpTransportMapping
}
return;
}
+ if(logger.isDebugEnabled()) {
+ logger.debug("readBuffer.position() !=
messageLengthDecoder.getMinHeaderLength(), readBuffer.position(): "+
readBuffer.position());
+ }
+ }
}
- ByteBuffer byteBuffer = ByteBuffer.wrap(buf);
+
+ ByteBuffer byteBuffer =null;
+ long bytesRead = 0;
+ if (readBuffer == null) {
+ // prepare a read fist fragment
+ byteBuffer = ByteBuffer.wrap(buf);
byteBuffer.limit(messageLengthDecoder.getMinHeaderLength());
if (!readChannel.isOpen()) {
sk.cancel();
@@ -979,12 +1040,14 @@ public class DefaultTcpTransportMapping
}
return;
}
- long bytesRead = 0;
try {
bytesRead = readChannel.read(byteBuffer);
if (logger.isDebugEnabled()) {
logger.debug("Reading header " + bytesRead + " bytes from " +
incomingAddress);
+ logger.debug("entry != null, byteBuffer read, byteBuffer.position():
"+ byteBuffer.position()
+ + ", readBuffer.limit(): "+ byteBuffer.limit()
+ +", readBuffer.array():" + new
OctetString(byteBuffer.array(), 0, byteBuffer.limit()).toHexString());
}
}
catch (ClosedChannelException ccex) {
@@ -995,6 +1058,29 @@ public class DefaultTcpTransportMapping
}
return;
}
+ }
+ else {
+ // get buffer info from previous read saved in entry
+ byteBuffer=readBuffer;
+ bytesRead=readBuffer.position();
+ ByteBuffer b = ByteBuffer.wrap(buf);
+ b.put(readBuffer.array(), 0, (int) bytesRead);
+ }
+
+ if (bytesRead> 0 && bytesRead<messageLengthDecoder.getMinHeaderLength())
{
+ // handle read fragment less than header length and save it in entry
+ byte[] message = new byte[byteBuffer.capacity()];
+ int bufpos = byteBuffer.position();
+ int buflim = byteBuffer.limit();
+ byteBuffer.flip();
+ byteBuffer.get(message, 0, bufpos);
+ ByteBuffer newBuffer = ByteBuffer.wrap(message);
+ newBuffer.position(bufpos);
+ newBuffer.limit(buflim);
+ if (entry != null) {
+ entry.setReadBuffer(newBuffer);
+ }
+ }
if (bytesRead == messageLengthDecoder.getMinHeaderLength()) {
MessageLength messageLength =
messageLengthDecoder.getMessageLength(ByteBuffer.wrap(buf));
@@ -1019,6 +1105,12 @@ public class DefaultTcpTransportMapping
byteBuffer.limit(messageLength.getMessageLength());
bytesRead += readChannel.read(byteBuffer);
if (bytesRead == messageLength.getMessageLength()) {
+ if(entry!=null){
+ if(logger.isDebugEnabled()) {
+ logger.debug("bytesRead == messageLength.getMessageLength(),
bytesRead: "+ bytesRead);
+ }
+ entry.setReadBuffer(null); // <== set read buffer of entry
to null
+ }
dispatchMessage(incomingAddress, byteBuffer, bytesRead, entry);
}
else {
Best regards,
Bruno
Bruno Filipe Basílio
Departamento de Investigação, Desenvolvimento e Inovação
Tel: (+351) 214233436
http://www.brisainovacao.pt
--------------------------------------------------------------------------------
Declaração:
A informação contida nesta mensagem, e os ficheiros anexos, é privilegiada e
confidencial, destinando-se exclusivamente ao(s) destinatário(s).Se não é o
destinatário (ou o responsável pela sua entrega ao destinatário) e recebeu a
mesma por engano, fica notificado que é estritamente proibido reproduzir,
guardar ou distribuir toda ou qualquer parte desta mensagem e ficheiros anexos.
Por favor reencaminhe a mensagem para o responsável pelo seu envio ou
contacte-nos por telefone e elimine a mensagem e ficheiros anexos do seu
computador, sem os reproduzir.
Disclaimer:
The information contained in this message, and any files attached, is
privileged and confidential, and intended exclusively for the included
addresses. If you are not the intended recipient (or the person responsible for
delivering to the intended recipient) and received this message by mistake, be
aware that copy, storage, distribution or any other use of all or part of this
message and the files attached is strictly prohibited. Please notify the sender
by reply e-mail or contact us by telephone and delete this message and the
files attached, without retaining a copy.
--------------------------------------------------------------------------------
_______________________________________________
SNMP4J mailing list
[email protected]
https://oosnmp.net/mailman/listinfo/snmp4j