Ocaml / Async socket issue - asynchronous

I am quite new to OCaml and I am working on a small TCP client utility, using Async/Core.
The connection is opened using
Tcp.with_connection (Tcp.Where_to_connect.of_host_and_port { host = "localhost"; port = myPort })
I need to be able to accept keyboard input, as well as read input from the socket. I use the Deferred.any for this purpose.
Calling Reader.read reader buf on the socket results in `Eof, which is OK, but when the method (containing the Deferred.any code) is called recursively, I get an exception:
“unhandled exception in Async scheduler”
(“unhandled exception”
((monitor.ml.Error
(“can not read from reader” (reason “in use”)
.....
Reader.is_closed on the reader returns false.
How can I “monitor” the socket recursively without this exception?
Michael

Related

Spring data redis stream receiver completes prematurely

I am using Spring data Redis to consume from a Redis stream ,using the reactive stream receiver to listen over a consumer group works ,but have observed that the Flux stream closes prematurely sometimes and doesn't listen to new messages any more and the flux terminates prematurely .
Code
StreamReceiverOptions<String, MapRecord<String, String, String>> options = StreamReceiverOptions.builder()
.build();
StreamReceiver.create(reactiveConnFactory, options)
.receiveAutoAck("CONSUMER_GRP", "CONSUMER_ID_1"), StreamOffset.create(
"CONSUMER_STREAM",
ReadOffset.lastConsumed()))
.doOnNext(msg -> LOG.info("Got [{}] message from stream", msg))
.flatMap(msg -> Mono.fromRunnable(() -> process("reactive", msg))
.subscribeOn(streamConsumerExecutor))
.onErrorResume(t -> Flux.empty())
.doOnCancel(() -> LOG.info("Consumer Stream was cancelled"))
.doOnComplete(() -> {
LOG.info("Consumer Stream Completed");
})
.doOnTerminate(() -> {
LOG.info("Consumer Stream terminated");
})
.subscribe();
After some time of reading messages from the stream get the log that the "consumer stream terminated"
version : 2.2.0.RELEASE
Is this a bug or am I missing anything ,Could any one help ?
UPDATE
Looks like redis commands are timing out as I get a RedisCommandTimeoutException, is there a way to retry the streaming process on such errors rather than cancelling it . Also figured out it happens in the XREADGROUP operation though when running through the nodejs redis-cli issuing the same command worked fine?

Asterisk AsterNET How to move from parking to queue?

Im using C# AsterNET to manage my Asterisk commands and events, and now I do have a new feature to work on.
This is simple (I think) but I'm stucked right now.
Scenario
I do have two queues, 8100 and 8300, and 2 extensions being 8101 and 8301. When I do have a call from PSTN it is driven to 8100 queue. When the 8101 extension become available I do add this extension to the 8100 queue, so the calling PSTN device will be redirected to this 8101 extension.
Everything is working fine till here.
Sometimes I do park the calling device and let 8301 knows it using my app, so 8301 user using the same app can send a command asking for that parked channel to be redirect to his SIP Phone. Also working fine.
Scope
Now I want to have some feature to let 8101 transfer this calling device to my other queue, the 8300. So I just tried to reuse my parked method and redirect method
internal void Park(string channel, int parkTimeout)
{
ParkAction pa = new ParkAction(channel, channel, parkTimeout.ToString());
ManagerResponse mr = manager.SendAction(pa);
}
internal void RedirectFromParking(string channel, string exten)
{
RedirectAction ra = new RedirectAction
{
Priority = 1,
Context = "default",
Channel = channel,
Exten = exten
};
ManagerResponse mr = manager.SendAction(ra);
}
Park("abc123456", 10000);
RedirectFromParking("abc123456", "8300")
Issue
I'm parking fine but when I try to redirect from parking to my queue the calling device is just disconnected and the connection is lost.
How can I transfer a parked call to my queue or transfer it directly to the queue (would be better) without needing to originate?
Just do hold instead of parking and make your own list of such calls.
To transfer to a queue I can do a blind transfer as documented on Asterisk website. Links below:
ManagerAction_BlindTransfer
ManagerEvent_BlindTransfer
To achieve this using AsterNET, I can use the same RedirectAction I was using but I do need to change the context. It can't be default for context, as default we are letting Asterisk manage it and somehow it can't handle as I expetected. So it need to be clearly specified as internar transfer. The event raised after this context transfer is the Manager_BlindTransfer.
Manager_Action_RedirectAction
So using my SIP Phone I manage to transfer a call while I was debugging that raised event method, so I could catch the context used in. Using the correct context
ManagerConnection manager = new ManagerConnection(address, port, user, password);
manager.BlindTransfer += Manager_BlindTransfer;
private void Manager_BlindTransfer(object sender, BlindTransferEvent e)
{
}
After this I created another method to transfer to directly to a queue using the correct context.
internal void TransferToQueue(string channel, string queue)
{
RedirectAction ma = new RedirectAction
{
Priority = priority,
Context = "from-internal-xfer",
Channel = channel,
Exten = queue
};
ManagerResponse mr = manager.SendAction(ma);
}
TransferToQueue("abc123456", "8300")
Summary
Was just a matter of the correct context to be used in.
from-internal-xfer

Simple Rust TCP server and client do not receive messages and never terminates

I am trying to spawn a server and connect to it on a different thread. I know Rust has blocking I/O, but I feel like I should be able to connect a server in a different thread. I do not have a lot of knowledge in threads. The end game is to connect to this server across a network. That is what I am simulating with the player_stream TCPStream. The player_stream will wait until there is something in its buffer. Once something has been written there, it will respond back to the server. As is, the program will not terminate.
use std::net::{TcpListener, TcpStream};
use std::io::{BufReader,BufWriter};
use std::io::Write;
use std::io::Read;
use std::thread;
fn main() {
thread::spawn(move || {
start_server();
});
let player_stream = TcpStream::connect("127.0.0.1:8000").expect("Couldn't connect");
let mut reader = BufReader::new(&player_stream);
let mut response = String::new();
reader.read_to_string(&mut response);
println!("Player received {}", response);
let mut writer = BufWriter::new(&player_stream);
writer.write_all("NAME".as_bytes());
}
fn start_server() {
let listener = TcpListener::bind("127.0.0.1:8000").unwrap();
fn handle_client(stream: TcpStream) {
println!("Client connected");
let mut writer = BufWriter::new(&stream);
writer.write_all("Red".as_bytes());
let mut reader = BufReader::new(&stream);
let mut response = String::new();
reader.read_to_string(&mut response);
println!("Server received {}", response);
}
// accept connections
for stream in listener.incoming() {
match stream {
Ok(stream) => {
handle_client(stream);
}
Err(e) => { panic!("{}",e) }
}
}
}
First off, don't ignore warnings. You have 4 errors of the type warning: unused result which must be used. Every single one of those could be cases where your code is failing and you wouldn't even know it. Use expect liberally!
Second, you have an open client read socket and you ask to "read all the data until the end into a string". What determines the end? In this case, it's when the socket is closed; so when is that?
Trick question!
The client's read socket closes when the server's write socket closes.
The server's write socket closes when the server's read socket closes.
The server's read socket closes when the the client's write socket closes.
So when does that happen? Because there's no code that does it specifically, it will close when the socket is dropped, so:
The client's write socket closes when the the client ends.
Thus the deadlock. The issue could be fixed by explicitly closing the write half of the socket:
stream.shutdown(std::net::Shutdown::Write).expect("could not shutdown");
Third, you are writing into a BufWriter. Review the documentation for it:
A BufWriter keeps an in-memory buffer of data and writes it to an underlying writer in large, infrequent batches.
The buffer will be written out when the writer is dropped.
The BufWriter is dropped at the end of the scope, after you've tried to read the response. That's another deadlock.
In the end, you need to establish a protocol for how to delimit messages sent back and forth. A simple but very limited solution is to have a line-oriented protocol: every message fits on one line ending with a newline character.
If you choose that, you can use read_to_line instead. I've also used BufWriter::flush to force the data to be sent down the wire; you could have also encapsulated writer in a block so it is dropped earlier or explicitly call drop(writer).
use std::net::{TcpListener, TcpStream};
use std::io::{BufReader, BufWriter, Write, BufRead};
use std::thread;
fn main() {
thread::spawn(start_server);
let player_stream = TcpStream::connect("127.0.0.1:8000").expect("Couldn't connect");
let mut reader = BufReader::new(&player_stream);
let mut response = String::new();
reader.read_line(&mut response).expect("Could not read");
println!("Player received >{}<", response.trim());
let mut writer = BufWriter::new(&player_stream);
writer.write_all("NAME\n".as_bytes()).expect("Could not write");
}
fn start_server() {
let listener = TcpListener::bind("127.0.0.1:8000").unwrap();
fn handle_client(stream: TcpStream) {
println!("Client connected");
let mut writer = BufWriter::new(&stream);
writer.write_all("Red\n".as_bytes()).expect("could not write");
writer.flush().expect("could not flush");
let mut reader = BufReader::new(&stream);
let mut response = String::new();
reader.read_line(&mut response).expect("could not read");
println!("Server received {}", response);
}
for stream in listener.incoming() {
let stream = stream.expect("Unable to accept");
handle_client(stream);
}
}
You'll note that the program doesn't always print out the server's response. That's because the main thread exiting exits the program.
You mentioned that your real case uses XML, which can have newlines embedded in it, making a line-oriented protocol unsuitable. Another common protocol is to send a length before sending the data itself. There are many possible implementations for this. At a previous job, we sent XML in this fashion. We started with an ASCII-encoded newline-terminated string of the length before the data itself. In that case, having the readability of the length as a string was a benefit. You could also choose to send a number of bytes that can be interpreted according to some endianness as a 2's compliment number.
See also:
Rust echo server and client using futures blocks itself forever

akka io tcp server

I am using the new Akka IO and followed this tutorial(which is a simple server-client application). My server actor system code looks like this:
// create the sever system
ActorSystem tcpServerSystem = ActorSystem.create("tcp-server-system");
// create the tcp actor
final ActorRef tcpServer = Tcp.get(tcpServerSystem).manager();
// create the server actor;
ActorRef serverActor = tcpServerSystem.actorOf(new Props(ServerActor.class).withRouter(new RoundRobinRouter(5)), "server");
// tell the tcp server to use an actor for listen connection on;
final List<Inet.SocketOption> options = new ArrayList<Inet.SocketOption>();
options.add(TcpSO.reuseAddress(true));
tcpServer.tell(TcpMessage.bind(serverActor, new InetSocketAddress("127.0.0.1", 12345), 10, options),
serverActor);
The ServerActor class it's just a plain actor that on it's onReceive does the followings:
logger.info("Received: " + o);
if (o instanceof Tcp.Connected){
connectionActor = getSender();
connectionActor.tell(TcpMessage.register(getSelf()), getSelf());
ByteStringBuilder byteStringBuilder = new ByteStringBuilder();
byteStringBuilder.putBytes("Hello Worlds".getBytes());
connectionActor.tell(TcpMessage.write(byteStringBuilder.result()), getSelf());
}
I am trying to test the server actor using netcat and have this "strange" behaviour: only the first client that connect tot the server is receiving the message send from the server. The nexts clients could connect to the server but does not receive the message. Also in debug mode the server actor doesn't get the Tcp.Connected message(except for the first connected client), so a registration message could not be sent to the client, althought the next clients could connect.
this is a known issue in the 2.2-M1 milestone, where the problem was that the TcpListener didn't register AcceptInterest on the selector unless it reached the configured BatchAcceptLimit, leading to it not being notified of new accepts if there where only a few connections pending.
It has been fixed and will be part of the next milestone release.

HTTP Connection Parameters

I am using the HTTP Connection in the following way:
HttpConnection _httpConnection = null;
try {
_httpConnection = (HttpConnection)Connector.open(_url);
} catch(Exception e) { }
byte [] postDataBytes = _postData.getBytes();
_httpConnection.setRequestMethod(HttpConnection.POST);
_httpConnection.setRequestProperty("User-Agent","Profile/MIDP-2.0 Configuration/CLDC-1.0");
_httpConnection.setRequestProperty("Content-Language", "en-US");
_httpConnection.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
_httpConnection.setRequestProperty("Connection", "close");
_httpConnection.setRequestProperty("Content-Length", Integer.toString(_postData.getBytes().length));
os = _httpConnection.openOutputStream();
os.write(postDataBytes);
os.flush();
This HTTP Connection requires parameters to successfully open. For example on a WIFI network, it requires the ";deviceside=true;interface=wifi" to be added to the URL.
The problem is for the EDGE connection. Each country requires different parameters to be added. For example in lebanon it requires ";deviceside=false" but in KSA if i add this parameter the connection will not open. In USA it needs different types of parametes. The question is how to establish an HTTP connection for all the countries with the same parameters. So that the application will successfully have an internet connection no matter where it is downloaded.
Welcome to the confusing world of network transports on BlackBerry! You will want to start with the article Connecting your BlackBerry - http and socket connections to the world.
Here is a simple example for "just give me a connection" (note, you will need to add appropriate error handling; also, myURL in the code below should have no connection descriptor info appended to it):
ConnectionFactory factory = new ConnectionFactory();
ConnectionDescriptor descriptor = factory.getConnection(myURL);
if (descriptor != null) {
_httpConnection = (HttpConnection) descriptor.getConnection();
...
}
Try using to use the method reffered in this link melick-rajee.blogspot.com and use it like
_url = "http://www.example.com";
_httpConnection = (HttpConnection)Connector.open(_url + getConnectionString());
You will have to sign the application to use this else the application will show exception.
To sign your application just go here Code Signing Keys
To use the connectionFactory, seems you need to set BisBOptions.
Try this:
connFact = new ConnectionFactory();
connFact.setTransportTypeOptions(TransportInfo.TRANSPORT_BIS_B,
new BisBOptions("mds-public"));

Resources