How do I send async data via libwebsocket? - c

I am using warmcat's libwebsocket C library for a small websocket server. I have the examples up and working and can send data in response to receiving data from the websocket (such as echoing back the reversed bytes sent). However, I haven't been able to figure out how to send data asynchronously from the server without already being in the libwebsocket callback function. I need the wsi pointer to pass to libwebsocket_write() but don't see how to get the pointer except while in the callback.
I've read that libwebsocket is not thread safe, as my own experience seems to confirm.
In libwebsockets.c:line2483, I read that "The protocol callback functions are [...] called periodically to allow async transmission." This is exactly what I want but I haven't observed this happening in my own code and haven't found any way to "turn it on".
Suggestions on how to write asynchronously to the websocket I am serving?
Code for libwebsocket: http://git.warmcat.com/cgi-bin/cgit/libwebsockets/
Example of use: http://martinsikora.com/libwebsockets-simple-websocket-server

I haven't found a super clean way of doing that. What I would suggest is to register a callback on the event that server can write to the client and then check if there's asynchronous work to send there. the LWS_CALLBACK_SERVER_WRITEABLE event is just that, and if you call libwebsocket_callback_on_writable(context, wsi); from within your callback it'll be periodically called.
So, something like this:
static int callback_myprotocol(struct libwebsocket_context *context,
struct libwebsocket *wsi,
enum libwebsocket_callback_reasons reason,
void *user, void *in, size_t len)
{
SendState *ss = (SendState*)user;
switch (reason) {
case LWS_CALLBACK_ESTABLISHED:
printf("connection established\n");
// get the ball rolling
libwebsocket_callback_on_writable(context, wsi);
break;
case LWS_CALLBACK_SERVER_WRITEABLE: {
if (!work_to_be_done) {
// schedule ourselves to run next tick anyway
libwebsocket_callback_on_writable(context, wsi);
return 0;
}
// send our asynchronous message
libwebsocket_write(wsi, buf, size, flag);
// and schedule ourselves again
libwebsocket_callback_on_writable(context, wsi);
break;
}
default:
break;
}
return 0;
}
I adapted this from the test-fraggle.c example; the above is roughly what that example does to send messages in smaller chunks.

Related

Arduino Socket.io shows disconnected when delay() is used

I am new to Arduino and facing an issue. I am implementing socket in Arduino for ESP8266 . It works as expected when I am not using delay() or not using someFunction(). As soon as i use delay or do some processing than i am getting connection disconnected one server socket.
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>
#include <ArduinoJson.h>
#include <WebSocketsClient.h>
#include <SocketIOclient.h>
#include <Hash.h>
ESP8266WiFiMulti WiFiMulti;
SocketIOclient socketIO;
#define USE_SERIAL Serial1
void socketIOEvent(socketIOmessageType_t type, uint8_t * payload, size_t length) {
switch(type) {
case sIOtype_DISCONNECT:
USE_SERIAL.printf("[IOc] Disconnected!\n");
break;
case sIOtype_CONNECT:
USE_SERIAL.printf("[IOc] Connected to url: %s\n", payload);
break;
case sIOtype_EVENT:
USE_SERIAL.printf("[IOc] get event: %s\n", payload);
break;
case sIOtype_ACK:
USE_SERIAL.printf("[IOc] get ack: %u\n", length);
hexdump(payload, length);
break;
case sIOtype_ERROR:
USE_SERIAL.printf("[IOc] get error: %u\n", length);
hexdump(payload, length);
break;
case sIOtype_BINARY_EVENT:
USE_SERIAL.printf("[IOc] get binary: %u\n", length);
hexdump(payload, length);
break;
case sIOtype_BINARY_ACK:
USE_SERIAL.printf("[IOc] get binary ack: %u\n", length);
hexdump(payload, length);
break;
}
}
void setup() {
// USE_SERIAL.begin(921600);
USE_SERIAL.begin(115200);
//Serial.setDebugOutput(true);
USE_SERIAL.setDebugOutput(true);
USE_SERIAL.println();
USE_SERIAL.println();
USE_SERIAL.println();
for(uint8_t t = 4; t > 0; t--) {
USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t);
USE_SERIAL.flush();
delay(1000);
}
// disable AP
if(WiFi.getMode() & WIFI_AP) {
WiFi.softAPdisconnect(true);
}
WiFiMulti.addAP("SSID", "passpasspass");
//WiFi.disconnect();
while(WiFiMulti.run() != WL_CONNECTED) {
delay(100);
}
String ip = WiFi.localIP().toString();
USE_SERIAL.printf("[SETUP] WiFi Connected %s\n", ip.c_str());
// server address, port and URL
socketIO.begin("10.11.100.100", 8880);
// event handler
socketIO.onEvent(socketIOEvent);
}
unsigned long messageTimestamp = 0;
void loop() {
socketIO.loop();
uint64_t now = millis();
if(now - messageTimestamp > 2000) {
messageTimestamp = now;
// creat JSON message for Socket.IO (event)
DynamicJsonDocument doc(1024);
JsonArray array = doc.to<JsonArray>();
// add evnet name
// Hint: socket.on('event_name', ....
array.add("event_name");
// add payload (parameters) for the event
JsonObject param1 = array.createNestedObject();
param1["now"] = now;
// JSON to String (serializion)
String output;
serializeJson(doc, output);
// Send event
socketIO.sendEVENT(output);
// Print JSON for debugging
USE_SERIAL.println(output);
}
//NEED TO DO SOME PROCESSIONG
delay(2000);
someFuntion();
}
void someFunction(){
//some processing that consume the time
}
You are getting timeout on server side.
When you are making delay(10000) esp8266 is just hanging on some loop (as a delay implementation) - any other code is not executed due this time. So when the server is not getting any data it disconnects client.
The solution (easy way) is to make a new connection every time you want to send data. In pseudocode it will look like this:
void loop(){
connectToServer();
sendData();
Disconnect();
delay(1000);
SomeFunction();
}
Then it should work.
The more complicated method is to familiarize yourself with the concept of Events and callbacks and get rid of delay() function. Or try to use esp_rtos_sdk witch is asynchronous tasks concepts RTOS framework.
Have fun!
Edited:
After refreshed the code I'm able to tell more about it, so I'm editing the previous post.
The quickest way to make it work(partly) is to remove the delay(2000) statement - because this If() statement is handling sending messages in 2 seconds interval. As I see you may wan't to put this void someFunction() to this if() statement too. This will make "some processing" in 2 seconds interval.
socketIO.loop() is handling maintaining connection with server and sending event's to server so it has to be call as quick as plausible. In case with delay you are getting socket timeout and disconnection.
void loop() function must be shortest as plausible to maintain the connection. Probably it is 500ms or so - regarding to you experiments. So any delay's is not plausible. If you need more processing try to familiarize with event processing. The easiest way is to declare flags as Boolean and timers counting time intervals. When timer is lunched it's sets the flag as true and you may process function.
Websockets on ESP(or other embedded microprocessors) are hard for beginners because they are time dependent. You need to have short processing loop or some of asynchronous methods used.
I hope, that I help.

How to use napi_threadsafe_function for NodeJS Native Addon

I've been looking through the NAPI documentation to try and understand how it deals with multithreading. According to the documentation napi_create_threadsafe_function() and napi_call_threadsafe_function() are used to create and call js functions from multiple threads. The issue is that the documentation is not that straight forward, and there are no examples and I can't find any anywhere else.
If anyone has any experience using napi_create_threadsafe_function() and napi_call_threadsafe_function() or know where to find examples of them being used. Please if you could help out with a a basic example so I can just understand how to use them correctly.
I'm writting a C addon not C++ and need to use these functions. I am not using the wrapper node-addon-api, but napi directly
As a summery tag we may say, the N-API ThreadSafeFunctions acts as a safe tunnel between the asynchronous C/C++ code executing on a worker thread and the JavaScript layer for information exchange.
Before going technical let us consider a scenario that we have a very long running process heavy task to be completed. We all know putting this task on node.js main thread is not a good choice, it will chock the event loop and block all other task in the queue. So a good choice could be to consider this task in a separate thread (let us call this thread as a worker thread). JavaScript asynchronous callback and Promise are doing exactly this approach.
Let us say we have deployed the task on a worker thread and we are ready with a portion of result and we would like it to be send to JavaScript layer. Then the process involve are, converting the result into napi_value and then call the Callback JavaScript function from C/C++. Unfortunately neither of the operation can be performed from a worker thread; these operations should be exclusively done from the main thread. The JavaScript Promise and Callback, wait till the task completion and then switch over to main thread along with the task result in a normal C/C++ storage facility such as structure etc. Then do the napi_value conversion and call the JavaScript callback function from the main thread.
Since our task is extremely long running probably we don't want to wait till the end of the task before exchanging the result with JavaScript layer.
Let us consider a scenario where we are searching objects in a very large video where we prefer to get the detected objects send to JavaScript layer as on when it is found.
In such a scenario we will have to start sending task result while the task is still in progress. This is the scenario where Asynchronous Thread-safe Function Calls come for our help. It acts as a safe tunnel between the worker thread and the JavaScript layer for information exchange. Let us consider the following function snippet
napi_value CAsyncStreamSearch(napi_env env, napi_callback_info info)
{
// The native addon function exposed to JavaScript
// This will be the funciton a node.js application calling.
}
void ExecuteWork(napi_env env, void* data)
{
// We will use this function to get the task done.
// This code will be executed on a worker thread.
}
void OnWorkComplete(napi_env env, napi_status status, void* data)
{
// after the `ExecuteWork` function exits, this
// callback function will be called on the main thread
}
void ThreadSafeCFunction4CallingJS(napi_env env, napi_value js_cb,
void* context, void* data)
{
// This funcion acts as a safe tunnel between the asynchronous C/C++ code
// executing the worker thread and the JavaScript layer for information exchange.
}
In this first three functions are nearly same as JavaScript Promise and Callback that we are familiar with. The fourth one is specifically for the Asynchronous Thread-safe Function Calls. In this, our long running task is being executed by ExecuteWork() function on a worker thread. Let us say it has instructed us not to call JavaScript (and also any napi_value conversion of result) from ExecuteWork() but permitted to do so from ThreadSafeCFunction4CallingJS as long as we are calling ThreadSafeCFunction4CallingJS with an napi equivalent of C/C++ function pointer. Then we could pack the JavaScript calls inside this ThreadSafeCFunction4CallingJS() function. Then when ExecuteWork() function could pass the result to ThreadSafeCFunction4CallingJS() while it is being invoked in a plain C/C++ storage units such as structure etc. The ThreadSafeCFunction4CallingJS() convert this result to napi_value and call JavaScript function.
Under the cover the ThreadSafeCFunction4CallingJS() function is being queue to the event loop, and eventually it get executed by main thread.
The following code snippet packed inside CAsyncStreamSearch() is responsible for creating a C/C++ function pointer equivalent of N-API by usng napi_create_threadsafe_function() and it is being done from the native addon's main thread itself. Similarly the request for creation of worker thread by using napi_create_async_work() function then placing the work int the event queue by using napi_queue_async_work() so that a worker thread will pickup this item in the future.
napi_value CAsyncStreamSearch(napi_env env, napi_callback_info info)
{
-- -- -- --
-- -- -- --
// Create a thread-safe N-API callback function correspond to the C/C++ callback function
napi_create_threadsafe_function(env,
js_cb, NULL, work_name, 0, 1, NULL, NULL, NULL,
ThreadSafeCFunction4CallingJS, // the C/C++ callback function
// out: the asynchronous thread-safe JavaScript function
&(async_stream_data_ex->tsfn_StreamSearch));
// Create an async work item, that can be deployed in the node.js event queue
napi_create_async_work( env, NULL,
work_name,
ExecuteWork,
OnWorkComplete,
async_stream_data_ex,
// OUT: THE handle to the async work item
&(async_stream_data_ex->work_StreamSearch);)
// Queue the work item for execution.
napi_queue_async_work(env, async_stream_data_ex->work_StreamSearch);
return NULL;
}
Then during the asynchronous execution of task (ExecuteWork() function) invokes ThreadSafeCFunction4CallingJS() by calling napi_call_threadsafe_function() function as shown bellow.
static void ExecuteWork(napi_env env, void *data)
{
// tsfn is napi equivalent of point to ThreadSafeCFunction4CallingJS
// function that we created at CAsyncStreamSearch function
napi_acquire_threadsafe_function( tsfn )
Loop
{
// this will eventually invoke ThreadSafeCFunction4CallingJS()
// we may call any number of time (in fact it can be called from any thread)
napi_call_threadsafe_function( tsfn, WorkResult, );
}
napi_release_threadsafe_function( tsfn,);
}
The example you pointed out is one of the best source of information and it is directly form node.js team itself. When I was learning this concept I too was referring the same example, during my study the example has been recreated by extracting original idea from it, hope you may find this much simplified. and it is available at
https://github.com/msatyan/MyNodeC/blob/master/src/mync1/ThreadSafeAsyncStream.cpp
https://github.com/msatyan/MyNodeC/blob/master/test/ThreadSafeAsyncStream.js
If anyone else gets stuck with this issue. I finally managed to hunt down an example here.
Once I understand it better and have gotten a working sample, I will update here. Hopefully someone needing this in the future will have an easier time than me.
See Satyan's answer
The solution from this site worked for me here
struct ThreadCtx {
ThreadCtx(Napi::Env env) {};
std::thread nativeThread;
Napi::ThreadSafeFunction tsfn;
};
void Target::Connect(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
threadCtx = new ThreadCtx(env);
// Create a ThreadSafeFunction
threadCtx->tsfn = Napi::ThreadSafeFunction::New(env, info[0].As<Napi::Function>(), "Resource Name", 0 /* Unlimited queue */, 1 /* Only 1 thread */, threadCtx,
[&]( Napi::Env, void *finalizeData, ThreadCtx *context ) {
printf("Thread cleanup\n");
threadCtx->nativeThread.join();
},
(void*)nullptr
);
// Create a native thread
threadCtx->nativeThread = std::thread([&] {
auto callback = [](Napi::Env env, Napi::Function cb, char* buffer) {
cb.Call({Napi::String::New(env, buffer)});
};
char reply[1024];
memset(reply, 0, sizeof(reply));
while(true)
{
size_t reply_length = boost::asio::read(s, boost::asio::buffer(reply, sizeof(reply)));
if(reply_length <= 0) {
printf("Bad read from boost asio\n");
break;
}
// Callback (blocking) to JS
napi_status status = threadCtx->tsfn.BlockingCall(reply, callback);
if (status != napi_ok)
{
// Handle error
break;
}
}
// Release the thread-safe function
threadCtx->tsfn.Release();
});
}
addon.cc - (tested and 100% working)
#include <napi.h>
Napi::Value SAFE_THREAD(const Napi::CallbackInfo& info) {
std::thread([](Napi::ThreadSafeFunction tsfn){
struct output_data{
int arg1;
std::string arg2;
};
auto data = new output_data();
///---------------
///fill output data
data->arg1=1;
data->arg2="string data";
std::this_thread::sleep_for(std::chrono::milliseconds(2000));
///---------------
///output thread result to nodejs
napi_status status = tsfn.BlockingCall(data,[](Napi::Env env, Napi::Function jsCallback,output_data* data){
jsCallback.Call({Napi::Number::New(env, data->arg1), String::New(env, data->arg2)});
delete data;
});
if(status != napi_ok) { std::cout << "error!" << "\n"; }
tsfn.Release();
},Napi::ThreadSafeFunction::New(info.Env(), info[0].As<Function>(), "TSFN", 0, 1,[](Napi::Env env, void *finalizeData){},(void *)nullptr)).detach();
return info.Env().Null();
}
index.js
const ADDON = require('./THREAD/build/Release/addon');
function time_sec(){return (new Date()).getTime()/1000;}
var t = time_sec();
ADDON.SAFE_THREAD((arg1,arg2)=>{
console.log(time_sec()-t, 'arg1 = '+arg1)
console.log(time_sec()-t, 'arg2 = '+arg2)
});
console.log(time_sec()-t, 'fin')
output:
0.00099992752075 fin
2.00499987602233 arg1 = 1
2.00600004196167 arg2 = string data
see also how to emit data from thread

Alternative to blocking code

Attempting to use mbed OS scheduler for a small project.
As mbed os is Asynchronous I need to avoid blocking code.
However the library for my wireless receiver uses a blocking line of:
while (!(wireless.isRxData()));
Is there an alternative way to do this that won't block all the code until a message is received?
static void listen(void) {
wireless.quickRxSetup(channel, addr1);
sprintf(ackData,"Ack data \r\n");
wireless.acknowledgeData(ackData, strlen(ackData), 1);
while (!(wireless.isRxData()));
len = wireless.getRxData(msg);
}
static void motor(void) {
pc.printf("Motor\n");
m.speed(1);
n.speed(1);
led1 = 1;
wait(0.5);
m.speed(0);
n.speed(0);
}
static void sendData() {
wireless.quickTxSetup(channel, addr1);
strcpy(accelData, "Robot");
wireless.transmitData(accelData ,strlen(accelData));
}
void app_start(int, char**) {
minar::Scheduler::postCallback(listen).period(minar::milliseconds(500)).tolerance(minar::milliseconds(1000));
minar::Scheduler::postCallback(motor).period(minar::milliseconds(500));
minar::Scheduler::postCallback(sendData).period(minar::milliseconds(500)).delay(minar::milliseconds(3000));
}
You should remove the while (!(wireless.isRxData())); loop in your listen function. Replace it with:
if (wireless.isRxData()) {
len = wireless.getRxData(msg);
// Process data
}
Then, you can process your data in that if statement, or you can call postCallback on another function that will do your processing.
Instead of looping until data is available, you'll want to poll for data. If RX data is not available, exit the function and set a timer to go off after a short interval. When the timer goes off, check for data again. Repeat until data is available. I'm not familiar with your OS so I can't offer any specific code. This may be as simple as adding a short "sleep" call inside the while loop, or may involve creating another callback from the scheduler.

calling IO Operations from thread in ruby c extension will cause ruby to hang

I have a problem with using threads in a C Extension to run ruby code async.
I have the following C code:
struct DATA {
VALUE callback;
pthread_t watchThread;
void *ptr;
};
void *executer(void *ptr) {
struct DATA *data = (struct DATA *) ptr;
char oldVal[20] = "1";
char newVal[20] = "1";
pthread_cleanup_push(&threadGarbageCollector, data);
while(1) {
if(triggerReceived) {
rb_funcall(data->callback, rb_intern("call"), 0);
}
}
pthread_cleanup_pop(1);
return NULL;
}
VALUE spawn_thread(VALUE self) {
VALUE block;
struct DATA *data;
Data_Get_Struct(self, struct DATA, data);
block = rb_block_proc();
data->callback = block;
pthread_create(&data->watchThread, NULL, &executer, data);
return self;
}
I am using this because I want to provide ruby-code as a callback, which will be executed, once the Thread receives a signal.
In general this is working fine, if the callback is something like this ruby-code:
1 + 1
But, if the callbacks ruby-code looks like this:
puts "test"
than the main ruby process will stop responding, once the callback is getting executed.
The thread is still running and able to react to signals and puts the "test" everytime, the thread receives a message.
Can somebody maybe tell me, how to fix this?
Thanks a lot
From the Ruby C API docs:
As of Ruby 1.9, Ruby supports native 1:1 threading with one kernel
thread per Ruby Thread object. Currently, there is a GVL (Global VM
Lock) which prevents simultaneous execution of Ruby code which may be
released by the rb_thread_call_without_gvl and
rb_thread_call_without_gvl2 functions. These functions are
tricky-to-use and documented in thread.c; do not use them before
reading comments in thread.c.
TLDR; the Ruby VM is not currently (at the time of writing) thread safe. Check out this nice write-up on Ruby Threading for a better overall understanding of how to work within these confines.
You can use Ruby's native_thread_create(rb_thread_t *th) which will use pthread_create behind the scenes. There are some drawbacks that you can read about in the documentation above the method definition. You can then run your callback with Ruby's rb_thread_call_with_gvl method. Also, I haven't done it here, but it might be a good idea to create a wrapper method so you can use rb_protect to handle exceptions your callback may raise (otherwise they will be swallowed by the VM).
VALUE execute_callback(VALUE callback)
{
return rb_funcall(callback, rb_intern("call"), 0);
}
// execute your callback when the thread receives signal
rb_thread_call_with_gvl(execute_callback, data->callback);

InternetReadFileEx gives 10035 and 1008 errors

I am trying to write an Asyncronous Wininet application. I read the data in my callback function in case of INTERNET_STATUS_REQUEST_COMPLETE and I handle the ERROR_IO_PENDING errors as well. But after some data read from internet, InternetReadFileEx function gives me 10035=WSAEWOULDBLOCK (A non-blocking socket operation could not be completed immediately) error. After that error I call InternetReadFileEx again and this time it gives me 1008=ERROR_NO_TOKEN (An attempt was made to reference a token that does not exist.) error. I think my design is not correct, and I receive these error because of that.
Here is a snippet of my code:
case INTERNET_STATUS_REQUEST_COMPLETE:
{
BOOL bAllDone= FALSE;
DWORD lastError;
do
{
//Create INTERNET_BUFFERS
char m_pbReadBuffer[4096];
INTERNET_BUFFERS BuffersIn;
ZeroMemory(&BuffersIn, sizeof(INTERNET_BUFFERS));
BuffersIn.dwStructSize = sizeof(INTERNET_BUFFERS);
BuffersIn.lpvBuffer = m_pbReadBuffer;
BuffersIn.dwBufferLength = 4096;
InternetReadFileEx(ReqContext->File, &BuffersIn, IRF_ASYNC, 1);
//HERE I GOT THOSE 10035 and 1008 ERRORS
lastError = GetLastError();
if(lastError == 997) // handling ERROR_IO_PENDING
break;//break the while loop
//append it to my ISTREAM
(ReqContext->savedStream)->Write(BuffersIn.lpvBuffer, BuffersIn.dwBufferLength, NULL);
if (BuffersIn.dwBufferLength == 0)
bAllDone = TRUE;
}while(bAllDone == FALSE);
//delete[] m_pbReadBuffer;
if(bAllDone == TRUE && lastError== 0)
{
//these are for passing the ISTREAM to the function which calls "InternetOpenUrl"
LARGE_INTEGER loc;
loc.HighPart = 0;
loc.LowPart = 0;
ReqContext->savedStream->Seek(loc, STREAM_SEEK_SET, NULL);
ReqContext->savedCallback->OnUrlDownloaded(S_OK, ReqContext->savedStream); //Tell silverlight ISTREAM is ready
ReqContext->savedStream->Release();
ReqContext->savedCallback->Release();
InternetCloseHandle(ReqContext->File);
InternetSetStatusCallback(ReqContext->Connection, NULL);
InternetCloseHandle(ReqContext->Connection);
delete[] ReqContext;
}
}
break;
Can anyone give me a hand to correct that?
Thanks everyone helping...
GetLastError() is only meaningful if InternetReadFileEx() (or any other API, for that matter) actually fails with an error. Otherwise, you will be processing an error from an earlier API call, giving your code a false illusion that an error happened when it really may not have. You MUST pay attention to API return values, but you are currently ignoring the return value of InternetReadFileEx().
Worse than that, though, you are using InternetReadFileEx() in async mode but you are using a receiving buffer that is local to the INTERNET_STATUS_REQUEST_COMPLETE callback handler. If InternetReadFileEx() fails with an ERROR_IO_PENDING error, the read is performed in the background and INTERNET_STATUS_REQUEST_COMPLETE will be triggered when the read is complete. However, when that error occurs, you are breaking your loop (even though the read is still in progress) and that buffer will go out of scope before the read is finished. While the reading is still in progress, the receiving buffer is still on the stack and InternetReadFileEx() is still writing to it, but it may get re-used for other things at the same time because your code moved on to do other things and did not wait for the read to finish.
You need to re-think your approach. Either:
remove the IRF_ASYNC flag, since that is how the rest of your callback code is expecting InternetReadFileEx() to behave.
re-write the code to operate in async mode correctly. Dynamically allocate the receive buffer (or at least store it somewhere else that remains in scope during the async reading), don't call IStream::Write() unless you actually have data to write (only when InternetReadFileEx() returned TRUE right away, or you get an INTERNET_STATUS_REQUEST_COMPLETE event with a success code from an earlier InternetReadFileEx()/ERROR_IO_PENDING call), etc.
There are plenty of online examples and tutorials that show how to use InternetReadFileEx() in async mode. Search around.

Resources