I am trying to recieve SNMP v3 traps from a device, using Adventnet.
When getting a trap I see the following AdventNet exception thrown:
Exception while constructing message after receiving PDU. Dropping this PDU received from xxx.xxx.xxx.xxx. com.adventnet.snmp.snmp2.SnmpException: Parse Header: Incorrect Scoped data
If I monitor the traps using NG-Soft browser the traps are recieved correctly.
Here is my code:
private void initV3Parameters(NEData neData) throws InterruptedException
{
logger.debug("in.");
try
{
logger.debug(".in");
SnmpAPI m_api = new SnmpAPI();
m_api.setDebug( true );
SnmpSession m_session = new SnmpSession(m_api);
m_session.addSnmpClient(this);
UDPProtocolOptions m_udpOpt = new UDPProtocolOptions();
m_udpOpt.setRemoteHost(neData.m_szIpAddress);
m_session.setProtocolOptions(m_udpOpt);
try
{
m_session.open();
String message="Succes to bind port: "+session.getLocalPort();
logger.info(message);
System.out.println(message);
}
catch (Exception ex)
{
String message = "Failed to open session - Port in use or permission denied. \n Message- "+ ex.getMessage() + "\n Will exit from Trap process. ";
logger.error(message, ex);
System.err.println(message);
throw new RuntimeException(message);
}
SnmpEngineEntry engineentry = new SnmpEngineEntry(neData.m_szIpAddress, m_udpOpt.getRemotePort());
SnmpEngineTable enginetable = m_api.getSnmpEngine();
enginetable.addEntry(engineentry);
try
{
engineentry.discoverSnmpEngineID(m_session,10000,3);
}
catch (Exception e)
{
logger.error("Failed to discover snmp EngineID. " + e.getMessage());
printToLog("failed",neData);
return;
}
USMUserEntry entry = new USMUserEntry(neData.usmUser.getBytes(), engineentry.getEngineID());
entry.setAuthProtocol(Integer.parseInt(neData.authProtocol));
entry.setAuthPassword(neData.authPassword.getBytes());
entry.setPrivProtocol(Integer.parseInt(neData.privProtocol));
entry.setPrivPassword(neData.privPassword.getBytes());
byte[] authKey = USMUtils.password_to_key(entry.getAuthProtocol(),
neData.authPassword.getBytes(),
neData.authPassword.getBytes().length,
engineentry.getEngineID());
entry.setAuthKey(authKey);
byte[] privKey = USMUtils.password_to_key(entry.getAuthProtocol(),
neData.privPassword.getBytes(),
neData.privPassword.getBytes().length,
engineentry.getEngineID());
entry.setPrivKey(privKey);
entry.setEngineEntry(engineentry);
entry.setSecurityLevel(Snmp3Message.AUTH_PRIV);
SecurityProvider provider = m_api.getSecurityProvider();
USMUserTable userTable = (USMUserTable) provider.getTable(3);
userTable.addEntry(entry);
entry.timeSynchronize(m_session, m_udpOpt);
printToLog("success",neData);
}
catch (Exception exp)
{
logger.error(exp.getMessage()+" for ip = "+neData.m_szIpAddress,exp);
discoveredDeque.put(neData);
printToLog("failed",neData);
}
}
I've also tried Using High-Level API
USMUtils.init_v3_parameters(
neData.usmUser,
null,
Integer.valueOf(neData.authProtocol),
neData.authPassword,
neData.privPassword,
udpOptions,
session,
false,
Integer.valueOf(neData.privProtocol));
In this case I see the trap using public void debugPrint (String debugOutput)
and no exception is throwing.
But there is nothing in the callback
Any advice will be welcome!!!
It turns out that there was a problem with the time synchronization of the device that sends the traps and my code worked perfectly fine.
probably NG-Soft doesn't care from time sync...
I attach my code here in case any of you will need it in the future...
private SnmpSession session;
/**
* Create a listener for trap version 1-2
*/
public void trapsListener ()
{
logger.debug(".in");
SnmpAPI api = new SnmpAPI();
// api.setDebug( true );
session = new SnmpSession(api);
session.addSnmpClient(this);
UDPProtocolOptions udpOpt = new UDPProtocolOptions();
udpOpt.setLocalPort(TRAP_PORT);
session.setProtocolOptions(udpOpt);
try
{
session.open();
String message="Succes to bind port: "+session.getLocalPort();
logger.info(message);
System.out.println(message);
}
catch (Exception ex)
{
String message = "Failed to open session - Port in use or permission denied. \n Message- "+ ex.getMessage() + "\n Will exit from Trap process. ";
logger.error(message, ex);
System.err.println(message);
throw new RuntimeException(message);
}
}
/**
* For each new device
* 1) discover the snmp engineID
* 2) create SnmpEngineEntry and add it to SnmpEngineTable
* 3) create USMUserEntry and add it to USMUserTable
* 4) performs time synchronization
**/
private void initV3Parameters(Device data) throws InterruptedException
{
logger.debug("in.");
try
{
UDPProtocolOptions udpOptions = new UDPProtocolOptions();
udpOptions.setLocalPort(TRAP_PORT);
udpOptions.setRemoteHost(data.getIpAddress());
USMUtils.init_v3_parameters(
data.getUsmUser(),
null,// null means that the SNMPv3 discovery will be activated
Integer.valueOf(data.getAuthProtocol()),
data.getAuthPassword(),
data.getPrivPassword(),
udpOptions,
session,
false,
Integer.valueOf(data.getPrivProtocol()));
printToLog("secsses",data);
}
catch (SnmpException exp) {
logger.error(exp.getMessage()+" for ip = "+data.getIpAddress(),exp);
printToLog("failed",data);
}
}
Related
I have a controller. Obtain data from client and in my service I get messages from API, but using WEBSocket connection. I never worked with WEBSockets before, so I found code example and implemented it. It works fine but the problem is, I have no idea how can I return obtained messages to my controller and to send response to the client.
public void sendRequest(String trader, List<String> cryptoGroup) {
// String json = ...prepare JSON...
try {
// open websocket
final WebsocketClientEndpoint clientEndPoint = new WebsocketClientEndpoint(new URI(link));
// add listener
clientEndPoint.addMessageHandler(System.out::println);
// send message to websocket
clientEndPoint.sendMessage(json);
// wait 5 seconds for messages from websocket
Thread.sleep(5000);
} catch (InterruptedException ex) {
throw new RuntimeException("InterruptedException exception: " + ex.getMessage());
} catch (URISyntaxException ex) {
throw new RuntimeException("URISyntaxException exception: " + ex.getMessage());
}
}
public void addMessageHandler(MessageHandler msgHandler) {
this.messageHandler = msgHandler;
}
public static interface MessageHandler {
public void handleMessage(String message);
}
Maybe there is a some kind of a pattern for such cases, some kind of observer-listener or something... I'll be appreciate for the ideas
In my current code i had a servlet from which if i create post to the servlet it will open a new websocket client , that mean 10 client connection each running for same purpose but with different api and secret , so i need to close particular session
I am using Jetty :: Websocket :: Client v9.4.48.v20220622
Please suggest , as i can get the session details but unable to use because it's not working with String data type . only in Session session it is working and i am unable to store session details anywhere else , as only in String data type i can save .
Whereas a is my API and b is my Secret Key ;
PS : Websocket connection is working fine to send expected data
class connector {
String a;
String b;
public void start() {
WebSocketClient client = new WebSocketClient();
MyWebSocket socket = new MyWebSocket();
try {
client.start();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
URI destUri = null;
try {
destUri = new URI("wss://socket.delta.exchange");
} catch (URISyntaxException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
ClientUpgradeRequest request = new ClientUpgradeRequest();
System.out.println("Connecting to: " + destUri);
try {
client.connect(socket, destUri, request);
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
try {
socket.awaitClose(3600, TimeUnit.SECONDS);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
client.stop();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
#WebSocket
public class MyWebSocket {
private final CountDownLatch closeLatch = new CountDownLatch(1);
#OnWebSocketConnect
public void onConnect(Session session) throws IOException {
session.getRemoteAddress();
System.out.println("Connection opened");
PingPong newObj = new PingPong();
newObj.session = session;
Authorization authMe = new Authorization();
Identifier getSt = new Identifier();
newObj.enableHeartBeat();
System.out.println(session);
session.getRemote().sendString(authMe.data(a, b));
}
#OnWebSocketMessage
public void onMessage(String message) {
MessageHandler objmsg = new MessageHandler();
objmsg.check();
System.out.println(
"Current Thread ID: "
+ Thread.currentThread().getId());
System.out.println("Message from Server: -- " + message);
}
#OnWebSocketClose
public void onClose(int statusCode, String reason) {
System.out.println("WebSocket Closed. Code:" + statusCode);
}
public boolean awaitClose(int duration, TimeUnit unit)
throws InterruptedException {
return this.closeLatch.await(duration, unit);
}
}
}
I want to do session.close() for a particular session details which i got from
session.getRemoteAddress().toString();
Session session ;
String sessionDetailSaved ;
i want to search for sessionDetailSaved and compare with all the on running sessions and close it
Or else any other way i can close particular session with different method may be interrupting session thread but sure it will not completely close connection .
Maven Dependency i am using
<dependency>
<groupId>org.eclipse.jetty.websocket</groupId>
<artifactId>websocket-client</artifactId>
<version>9.4.48.v20220622</version>
</dependency>
Calling Session.close() will initiate a close handshake where the remote endpoint should reply with a response close frame, and once the close response has been received the WebSocket connection will be closed. You can send custom close status code and reason with Session.close(int statusCode, String reason).
You also have the option to call Session.disconnect() which will do a hard close of the underlying connection without sending this close frame.
In regards to your code, it looks like you are never completing the closeLatch in the OnWebSocketClose method, so your awaitClose method will always timeout.
Also, if possible you should try to re-use the same WebSocketClient instance for multiple connections because it is a heavy weight object. It is expensive to create a new one for each request.
I'm trying to add the option to get a TRAP V3 (I can get TRAP V1 and V2).
here is the Session init
public void CreateSession()
{
logger.debug(".in");
System.out.println("Waiting to receive traps .......");
api = new SnmpAPI();
api.setDebug( true );
session = new SnmpSession(api);
session.addSnmpClient(this);
udpOpt = new UDPProtocolOptions();
udpOpt.setLocalPort(TRAP_PORT);
session.setProtocolOptions(udpOpt);
try
{
session.open();
String message="Succes to bind port: "+session.getLocalPort();
logger.info(message);
System.out.println(message);
}
catch (Exception ex)
{
String message = "Failed to open session - Port in use or permission denied. \n Message- "+ ex.getMessage() + "\n Will exit from Trap process. ";
logger.error(message, ex);
System.err.println(message);
throw new RuntimeException(message);
}
}
Every time I set up a device in V3 I perform the discovery and its registration to the tables using the method USMUtils.init_v3_parameters.
private void initV3Parameters(NEData neData) throws InterruptedException
{
logger.debug("in.");
try
{
UDPProtocolOptions udpOptions = new UDPProtocolOptions();
udpOptions.setLocalPort(TRAP_PORT);
udpOptions.setRemoteHost(neData.m_szIpAddress);
USMUtils.init_v3_parameters(
neData.usmUser,
null,
Integer.valueOf(neData.authProtocol),
neData.authPassword,
neData.privPassword,
udpOptions,
session,
false,
Integer.valueOf(neData.privProtocol));
printToLog("success",neData);
}
catch (SnmpException exp) {
logger.error(exp.getMessage()+" for ip = "+neData.m_szIpAddress,exp);
discoveredDeque.put(neData);
printToLog("failed",neData);
}
}
When TRAP V1 or V2 arrives it comes to this function and it works perfect.But I want to add the V3 as well
/**
* Receives incoming PDUs and adds them to the traps queue. Notifies the
* internal thread on the arrival of each PDU.
*/
public boolean callback (SnmpSession session, SnmpPDU pdu, int requestID)
{
logger.info("in session= "+session+" ,pdu= "+pdu+" ,requestID = "+requestID);
if (pdu == null)
{
logger.info("Received null PDU");
}
else
{
// Add the PDU to the end of the traps queue.
// Notify the internal thread.
try
{
synchronized (this)
{
Object t = m_Traps.addElement(pdu);
if (t != null)
{
// The new trap replaced an old one.
logger.info("Queue full: replaced old PDU");
}
notify();
}
}
catch (Exception ex)
{
logger.error(ex.getMessage(),ex);
}
}
// All PDUs are handled, so true should always be returned.
return true;
}
I have debugPrint implementation from SnmpClient and it seems that AdventNet gets the TRAP but does not do anything with it...
The SNMP agent is implemented using NetSNMP.
What is missing to make AdventNet handle the V3 TRAP?
Is this the right callback function to use?
public boolean callback (SnmpSession session, SnmpPDU pdu, int requestID)
I try to implement Server-Sent-Event in my Webapp with Java Serlvet on server.
Is it possible to check in Servlet that connection is closed by client? The loop while(true) in Servlet is infinite even if client browser is closed.
Client code
function startLogSSE(lastEventId, level) {
var eventSource = new EventSource("log-sse?last-event-id=" + lastEventId + "&level=" + level);
eventSource.onmessage = function (event) {
document.getElementById('log').innerHTML = event.data + "\n" + document.getElementById('log').innerHTML;
};
}
Server code
public class LogSSEServlet extends HttpServlet {
private static final Logger logger = LoggerFactory.getLogger(LogSSEServlet.class);
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/event-stream");
response.setCharacterEncoding("UTF-8");
PrintWriter writer = response.getWriter();
// get logger purgerDB appender
PurgerDBAppender appender = LogUtils.getPurgerDBAppender();
if (appender == null) {
writer.write("data: [ERROR] Appender 'purgerDB' isn't found for logger 'com.bp3'\n\n");
writer.close();
return;
}
int eventId = 0;
// get last-event-id
String lastEventId = request.getHeader("last-event-id");
if (lastEventId == null) {
// try to get lastEventId from parameter
lastEventId = request.getParameter("last-event-id");
}
if (lastEventId != null) {
try {
eventId = Integer.parseInt(lastEventId);
} catch (NumberFormatException e) {
logger.error("Failed to parse last-event-id: " + lastEventId);
}
}
String minLevel = request.getParameter("level");
if (minLevel == null) {
minLevel = "TRACE";
}
// get logs from purgerDB logger appender
LogServices logServices = new LogServices();
try {
logServices.open();
} catch (SQLException e) {
throw new ServletException(e);
}
try {
while (true) {
List<LogMessage> messages = logServices.getLastMessages(Level.toLevel(minLevel), eventId, 0);
if (messages.size() > 0) {
writer.write("id: " + messages.get(0).getEventId() + "\n");
writer.write("data: " + LogUtils.formatLog(messages) + "\n");
writer.flush();
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
break;
}
}
} catch (SQLException e) {
throw new ServletException(e);
} finally {
logServices.closeQuietly();
}
}
}
Is it possible to check in Servlet that connection is closed by client?
Eventually an exception will be thrown: either an IOException: connection reset if you are streaming directly to the socket, or an OutOfMemoryError if the container is streaming to memory, which it does when you aren't using a fixed-length or chunked transfer mode.
The loop while(true) in Servlet is infinite even if client browser is closed.
No it isn't.
One way to check, wihin the Servlet, that connection is closed, is using the writer.checkError() method. I tested this fix on Chrome and it works. Your code would be:
boolean error=false;
while (!error) {
//...
writer.write("data: " + /*...*/ "\n");
//writer.flush();
error = writer.checkError(); //internally calls writer.flush()
}
Details:
The PrintWriter's API says:
Methods in this class never throw I/O exceptions, although some of its
constructors may. The client may inquire as to whether any errors have
occurred by invoking checkError().
and the checkError() says:
Flushes the stream if it's not closed and checks its error state
why i got this error
20:43:40,798 ERROR Tx:809 - java.net.SocketException: Broken pipe
java.net.SocketException: Broken pipe
at java.net.SocketOutputStream.socketWrite0(Native Method)
at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:92)
at java.net.SocketOutputStream.write(SocketOutputStream.java:136)
at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:65)
at java.io.BufferedOutputStream.write(BufferedOutputStream.java:109)
at com.logica.smpp.TCPIPConnection.send(TCPIPConnection.java:353)
at com.logica.smpp.Transmitter.send(Transmitter.java:79)
at com.logica.smpp.Session.send(Session.java:993)
at com.logica.smpp.Session.send(Session.java:1048)
at com.logica.smpp.Session.enquireLink(Session.java:789)
at com.logica.smpp.Tx.kirimEnquireLink(Tx.java:795)
at com.logica.smpp.Tx.access$0(Tx.java:777)
at com.logica.smpp.Tx$1.run(Tx.java:120)
at java.util.TimerThread.mainLoop(Timer.java:512)
at java.util.TimerThread.run(Timer.java:462)
..I'm Using Open smpp logica library to create smsc client..for a few hours it's work but then the error come out..when i'm trying to send enquiry link,,the session I create is syncronize and the type of connection is Transceiver here's a piece of code i used to bind and to enqury link
private void bind()
{
debug.enter(this, "SMPPTest.bind()");
try {
if (bound) {
System.out.println("Already bound, unbind first.");
return;
}
BindRequest request = null;
BindResponse response = null;
String syncMode = (asynchronous ? "a" : "s");
// type of the session
syncMode = getParam("Asynchronous/Synchronnous Session? (a/s)",
syncMode);
if (syncMode.compareToIgnoreCase("a")==0) {
asynchronous = true;
} else if (syncMode.compareToIgnoreCase("s")==0) {
asynchronous = false;
} else {
System.out.println("Invalid mode async/sync, expected a or s, got "
+ syncMode +". Operation canceled.");
return;
}
// input values
bindOption = getParam("Transmitter/Receiver/Transciever (t/r/tr)",
bindOption);
if (bindOption.compareToIgnoreCase("t")==0) {
request = new BindTransmitter();
} else if (bindOption.compareToIgnoreCase("r")==0) {
request = new BindReceiver();
} else if (bindOption.compareToIgnoreCase("tr")==0) {
request = new BindTransciever();
} else {
System.out.println("Invalid bind mode, expected t, r or tr, got " +
bindOption + ". Operation canceled.");
return;
}
ipAddress = getParam("IP address of SMSC", ipAddress);
port = getParam("Port number", port);
TCPIPConnection connection = new TCPIPConnection(ipAddress, port);
connection.setReceiveTimeout(20*1000);
session = new Session(connection);
systemId = getParam("Your system ID", systemId);
password = getParam("Your password", password);
// set values
request.setSystemId(systemId);
request.setPassword(password);
request.setSystemType(systemType);
request.setInterfaceVersion((byte)0x34);
request.setAddressRange(addressRange);
// send the request
System.out.println("Bind request " + request.debugString());
if (asynchronous) {
pduListener = new SMPPTestPDUEventListener(session);
response = session.bind(request,pduListener);
} else {
response = session.bind(request);
}
System.out.println("Bind response " + response.debugString());
if (response.getCommandStatus() == Data.ESME_ROK) {
System.out.println("CommandID "+response.getCommandId());
bound = true;
}
} catch (Exception e) {
event.write(e,"");
debug.write("Bind operation failed. " + e);
System.out.println("Bind operation failed. " + e);
} finally {
debug.exit(this);
}
}
the code for enquiry link is
private void kirimEnquireLink()
{
try
{
log.info("Send enquireLink!");
EnquireLink request = new EnquireLink();
EnquireLinkResp response = new EnquireLinkResp();
// synchronized (session) {
// session.enquireLink(request);
// }
if(asynchronous)
{
session.enquireLink(request);
}else
{
response = session.enquireLink(request);
System.out.println("Enquire Link Response "+request.debugString());
}
}
catch (Exception e)
{
bound = false;
// unbind();
log.error(e, e);
}
}
i called enquiry link every 10 second,, any idea why
The problem you are facing is that there is never insurance that connection will be always available, nor the session. Many different external reasons can bring the link between ESME and SMSC down. My suggestion, try-catch the enquire_link operations and the submit operations, evaluate the Exception and take action.
I've successfully implemented recursive method calls to deal with this issue as follows
/**
* Connect to ESME and submit a message, if binding process fails, reattempt
* to reconnect and submit.
*/
public void connect() {
try {
//Create connection
BindRequest request = null;
request = new BindTransciever();
connection = new TCPIPConnection("localhost", 17632);
connection.setReceiveTimeout(20 * 1000);
session = new Session(connection);
//Prepare request
request.setSystemId("pavel");
request.setPassword("wpsd");
request.setSystemType("CMT");
request.setInterfaceVersion((byte) 0x34);
request.setAddressRange(new AddressRange());
pduListener = new SMPPTestPDUEventListener(session);
//Session binding process, if it fails, we are thrown to the catch section
//with a BrokenPipe (IOException)
session.bind(request, pduListener);
//Prepare message
SubmitSM msg = new SubmitSM();
// set values
msg.setDestAddr("04234143939");
msg.setShortMessage("hello");
msg.assignSequenceNumber(true);
//Send to our custom made submitMessage method that reattempts if failure
submitMessage(msg);
} catch (Exception ex){
//Analyze what type of exception was
if (ex instanceof IOException || ex instanceof SocketException){
//IOException relate to the brokenpipe issue you are facing
//you need to close existing sessions and connections
//restablish session
if (this.connection!=null){
this.connection.close();
}
//This is a recursive call, I encourage you to elaborate
//a little bit this method implementing a counter so you
//don't end up in an infinite loop
this.connect();
} else {
//LOG whatever other exception thrown
}
}
}
/**
* Submit message to SMSC, if it fails because of a connection issue, reattempt
* #param message
*/
private void submitMessage(SubmitSM message){
try{
session.submit(message);
} catch (Exception ex){
//Analyze what type of exception was
if (ex instanceof IOException || ex instanceof SocketException){
//IOException relate to the brokenpipe issue you are facing
//you need to close existing sessions and connections
//restablish session and try to submit again
if (this.connection!=null){
this.connection.close();
}
//Call a rebind method
this.bind();
//This is a recursive call, I encourage you to elaborate
//a little bit this method implementing a counter so you
//don't end up in an infinite loop
this.submitMessage(message);
} else {
//LOG whatever other exception thrown
}
}
}
Do the same with the enquire_link, try-catch, during IOException rebind, and reattempt. Do not forget to add a couter and a maximum ammount of attempts in order to avoid infinite loops during recursive calls.
You do not need to enquire_link every 10 seconds. Most providers will let you know how often it needs to be done, the standard is 10 minutes.