I'm trying to implement smpp solution using opensmpp. Messages are sent succefully but for delivery receipts, I get only for some submited message and the same delivery receipts came several times. Can someone help me please.
private void receiveSms() {
try {
if (session != null && session.isBound()) {
PDU pdu = session.receive(1500);
if (pdu instanceof DeliverSM) {
DeliverSM received = (DeliverSM) pdu;
if (received.getEsmClass() == 0) {
// new message
System.out.println("RECEIVE NEW MESSAGE " + received.debugString());
} else {
//delivry Repport
System.out.println("RECEIVE NEW DELIVERED REPORT: " + received.debugString());
}
}
}
...
I am not familliar with opensmpp, but note that the messageId in norm smpp34 is still NULL,
The messageId associated to SUBMIT_SM is in DELIVER_SM "receipted_message_id" field,
or in the short_message if the appendixB is used,
If the "receipted_message_id" field has always the same value, you should check about the SMSC configuration/code, the DELIVER_SM is generated there
Related
I have a RabbitMQ server (v.3.8.2) with a simple exchange fanout-queue binding running, with several producers and one consumer. The average delivery/ack rate is quite low, about 6 msg/s.
The queue is created at runtime by producers with the x-message-ttl parameter set at 900000 (15 minutes).
In very specific conditions (e.g. rare error situation), messages are rejected by the consumer. These messages then are shown in the unacked counter on the RabbitMQ admin web page indefinitely. They never expire or get discarded event after they timeout.
There are no specific per-message overrides in ttl parameters.
I do not need any dead letter processing as these particular messages do not require processing high reliabilty, and I can afford to lose some of them every now and then under those specific error conditions.
Exchange parameters:
name: poll
type: fanout
features: durable=true
bound queue: poll
routing key: poll
Queue parameters:
name: poll
features: x-message-ttl=900000 durable=true
For instance, this is what I am currently seeing in the RabbitMQ server queue admin page:
As you can see, there are 12 rejected/unack'ed messages in the queue, and they have been living there for more than a week now.
How can I have the nacked messages expire as per the ttl parameter?
Am I missing some pieces of configuration?
Here is an extract from the consumer source code:
// this code is executed during setup
...
consumer = new EventingBasicConsumer(channel);
consumer.Received += (sender, e) =>
{
// Retrieve retry count & death list if present
List<object> DeathList = ((e?.BasicProperties?.Headers != null) && e.BasicProperties.Headers.TryGetValue("x-death", out object obj)) ? obj as List<object> : null;
int count = ((DeathList != null) &&
(DeathList.Count > 0) &&
(DeathList[0] is Dictionary<string, object> values) &&
values.TryGetValue("count", out obj)
) ? Convert.ToInt32(obj) : 0;
// call actual event method
switch (OnRequestReceived(e.Body, count, DeathList))
{
default:
channel.BasicAck(e.DeliveryTag, false);
break;
case OnReceivedResult.Reject:
channel.BasicReject(e.DeliveryTag, false);
break;
case OnReceivedResult.Requeue:
channel.BasicReject(e.DeliveryTag, true);
break;
}
};
...
// this is the actual "OnReceived" method
static OnReceivedResult OnRequestReceived(byte[] payload, int count, List<object> DeathList)
{
OnReceivedResult retval = OnReceivedResult.Ack; // success by default
try
{
object request = MessagePackSerializer.Typeless.Deserialize(payload);
if (request is PollRequestContainer prc)
{
Log.Out(
Level.Info,
LogFamilies.PollManager,
log_method,
null,
"RequestPoll message received did={0} type=={1} items#={2}", prc.DeviceId, prc.Type, prc.Items == null ? 0 : prc.Items.Length
);
if (!RequestManager.RequestPoll(prc.DeviceId, prc.Type, prc.Items)) retval = OnReceivedResult.Reject;
}
else if (request is PollUpdateContainer puc)
{
Log.Out(Level.Info, LogFamilies.PollManager, log_method, null, "RequestUpdates message received dids#={0} type=={1}", puc.DeviceIds.Length, puc.Type);
if (!RequestManager.RequestUpdates(puc.DeviceIds, puc.Type)) retval = OnReceivedResult.Reject;
}
else Log.Out(Level.Error, LogFamilies.PollManager, log_method, null, "Message payload deserialization error length={0} count={1}", payload.Length, count);
}
catch (Exception e)
{
Log.Out(Level.Error, LogFamilies.PollManager, log_method, null, e, "Exception dequeueing message. Payload length={0} count={1}", payload.Length, count);
}
// message is rejected only if RequestUpdates() or RequestPoll() return false
// message is always acked if an exception occurs within the try-catch or if a deserialization type check error occurs
return retval;
}
This state occurs when the Consumer does not ack or reject both after receiving the message.
In the unacked state, the message does not expire.
After receiving the message, you must ack or reject it.
This issue isn't a problem that doesn't expire, problem is you don't ack or reject the message.
x-message-ttl=900000 means how long the message stays in the queue without being delivered to the consumer.
In your situation, your message is already delivered to the consumer and it needs to be acked/rejected.
I am discovering the Plc4x java implementation which seems to be of great interest in our field. But the youth of the project and the documentation makes us hesitate. I have been able to implement the basic hello world for reading out of our PLCs, but I was unable to write. I could not find how the addresses are handled and what the maskwrite, andMask and orMask fields mean.
Please can somebody explain to me the following example and detail how the addresses should be used?
#Test
void testWriteToPlc() {
// Establish a connection to the plc using the url provided as first argument
try( PlcConnection plcConnection = new PlcDriverManager().getConnection( "modbus:tcp://1.1.2.1" ) ){
// Create a new read request:
// - Give the single item requested the alias name "value"
var builder = plcConnection.writeRequestBuilder();
builder.addItem( "value-" + 1, "maskwrite:1[1]/2/3", 2 );
var writeRequest = builder.build();
LOGGER.info( "Synchronous request ..." );
var syncResponse = writeRequest.execute().get();
}catch(Exception e){
e.printStackTrace();
}
}
I have used PLC4x for writing using the modbus driver with success. Here is some sample code I am using:
public static void writePlc4x(ProtocolConnection connection, String registerName, byte[] writeRegister, int offset)
throws InterruptedException {
// modbus write works ok writing one record per request/item
int size = 1;
PlcWriteRequest.Builder writeBuilder = connection.writeRequestBuilder();
if (writeRegister.length == 2) {
writeBuilder.addItem(registerName, "register:" + offset + "[" + size + "]", writeRegister);
}
...
PlcWriteRequest request = writeBuilder.build();
request.execute().whenComplete((writeResponse, error) -> {
assertNotNull(writeResponse);
});
Thread.sleep((long) (sleepWait4Write * writeRegister.length * 1000));
}
In the case of modbus writing there is an issue regarding the return of the writer Future, but the write is done. In the modbus use case I don't need any mask stuff.
I am following "isRegistered" api from this sample code. I did not understand how we get phone number from security context.
The API that I want to use is:
#Path("/isRegistered")
#GET
#Produces("application/json")
#OAuthSecurity(enabled = true)
#ApiOperation(value = "Check if a phone number is registered",
notes = "Check if a phone number is registered",
httpMethod = "GET",
response = Boolean.class
)
#ApiResponses(value = {
#ApiResponse(code = 200, message = "OK",
response = String.class),
#ApiResponse(code = 401, message = "Not Authorized",
response = String.class),
#ApiResponse(code = 500, message = "Cannot check if phone number is registered",
response = String.class)
})
public Boolean isRegistered() {
//Getting client data from the security context
ClientData clientData = securityContext.getClientRegistrationData();
if (clientData == null) {
throw new InternalServerErrorException("This check allowed only from a mobile device.");
}
String number = clientData.getProtectedAttributes().get(SMSOTPSecurityCheck.PHONE_NUMBER);
return number != null && !number.trim().equals("");
}
How does the security context have the client phone number?
There is a client project as well in this sample. Please refer to the complete sample.
Within the client side logic here, the user is asked to provide the phone number , which is sent to the server in an adapter call:
MainViewController.codeDialog("Phone Number", message: "Please provide your phone number",isCode: true) { (phone, ok) -> Void in
if ok {
let resourseRequest = WLResourceRequest(URL: NSURL(string:"/adapters/smsOtp/phone/register/\(phone)")!, method:"POST")
.....
Now in the adapter code path #Path("/register/{phoneNumber}") notice the following code:
clientData.getProtectedAttributes().put(SMSOTPSecurityCheck.PHONE_NUMBER, phoneNumber);
securityContext.storeClientRegistrationData(clientData);
This is how the phone number made it to the security context.
Run the sample and use a tool such as Wireshark to analyze the data flow between client and server.
I want to implement an IQHandler, but I want to make sure that only authenticated users can send IQ Packets to it. I want to make sure that the JID I get from Packet.getFrom() is the authenticated user that sent it.
I need this so that no one can just create an IQ Packet and set the "from" attribute to a user id other than their own. Can someone help me with this?
Try this:
ClientSession session = sessionManager.getSession(sender);
if(session.getStatus() == Session.STATUS_AUTHENTICATED) {
//YOUR STUFF HERE
}
UPDATE:
Looking closer at the source. It appears that the IQRouter already does this for you. If you are not authenticated the server response with an error stating just that.
public void route(IQ packet) {
if (packet == null) {
throw new NullPointerException();
}
JID sender = packet.getFrom();
ClientSession session = sessionManager.getSession(sender);
try {
// Invoke the interceptors before we process the read packet
InterceptorManager.getInstance().invokeInterceptors(packet, session, true, false);
JID to = packet.getTo();
if (session != null && to != null && session.getStatus() == Session.STATUS_CONNECTED &&
!serverName.equals(to.toString())) {
// User is requesting this server to authenticate for another server. Return
// a bad-request error
IQ reply = IQ.createResultIQ(packet);
reply.setChildElement(packet.getChildElement().createCopy());
reply.setError(PacketError.Condition.bad_request);
session.process(reply);
Log.warn("User tried to authenticate with this server using an unknown receipient: " +
packet.toXML());
}
else if (session == null || session.getStatus() == Session.STATUS_AUTHENTICATED || (
isLocalServer(to) && (
"jabber:iq:auth".equals(packet.getChildElement().getNamespaceURI()) ||
"jabber:iq:register"
.equals(packet.getChildElement().getNamespaceURI()) ||
"urn:ietf:params:xml:ns:xmpp-bind"
.equals(packet.getChildElement().getNamespaceURI())))) {
handle(packet);
}
else {
IQ reply = IQ.createResultIQ(packet);
reply.setChildElement(packet.getChildElement().createCopy());
reply.setError(PacketError.Condition.not_authorized);
session.process(reply);
}
// Invoke the interceptors after we have processed the read packet
InterceptorManager.getInstance().invokeInterceptors(packet, session, true, true);
}
For one of the requirement we need to keep track of queue depth and successfully processed messages. The idea is to publish messages and get a list of successful and failed messages. To simulate the requirement I did the following
Publish the messages with Mandatory and Immediate flag sent channel.basicPublish 'exchange' ,'rKey',true,false, props,"Hello World".bytes
The consumer consumes even marked ( I have put numbers from 1..10 as marked value in header of each messages) and does not ACKS odd numbered messages.
I have implemented setReturnListnere in the publisher to capture undelivered messages.
While am able to get the number of unack messages via Rabbmitmqctl list_queues messages_unacknowledged, somehow my handleBasicReturn method does not gets called. Am in missing something.
Code snippets:
Producer:
channel.setReturnListener(new ReturnListener() {
public void handleBasicReturn(int replyCode, String replyText, String exchange,
String routingKey, AMQP.BasicProperties properties,
byte[] body)
throws IOException {
println "Debugging messages!!!!"
println "The details of returned messages are ${replyText} from ${exchange} with routingKey as ${routingKey} with properties"
}
});
println " queuename is ${dec.queue} and consumerCount is ${dec.consumerCount} messageCount is ${dec.messageCount}"
(1..10).each {
println "Sending file ${i}....."
def headers = new HashMap<String,Object>()
headers.put "operatiion","scp"
headers.put "dest","joker.dk.mach.com"
headers.put "id", i
println headers
BasicProperties props = new BasicProperties(null, null, headers, null, null, null, null, null,null, null, null, null,null, null)
channel.basicPublish 'exchange' ,'rKey',true,false, props,"Hello Worls".bytes
i++
}
channel.close()
Consumer:
while (true) {
def delivery = consumer.nextDelivery()
def headers = delivery?.properties?.headers
def id = headers.get("id")
println "Received message:"
println " ${id.toString()}"
if( id % 2 == 0){
channel.basicAck delivery.envelope.deliveryTag, false
}
}
Read this explanation about how the immediate and mandatory flags impact message delivery in RabbitMQ.
In your case, since you have a consumer receiving messages, messages won't be returned even if the consumer never acks them.
D.