Systemd dbus sd_bus_call_method() with array - dbus

I am trying to modify some code using systemd dbus.
The method call looks like this:
res = sd_bus_call_method(bus,
SERVICE_NAME,
OBJECT_PATH,
INTERFACE,
"AddData",
&error, &m,
"ss",
data->key,
data->valyue);
Now I'm trying to change that to:
res = sd_bus_call_method(bus,
SERVICE_NAME,
OBJECT_PATH,
INTERFACE,
"AddData",
&error, &m,
"(a(ss))",
/* WHAT DO I PASS HERE? */);
I can't find examples or documentation and the code is not super clear to me.

From documentation sd_bus_call_method
sd_bus_call_method() is a convenience function for initializing a bus message object and calling the corresponding D-Bus method. It combines the sd_bus_message_new_method_call(3), sd_bus_message_append(3) and sd_bus_call(3) functions into a single function call.
Details about parameters can be found on sd_bus_message_append().
res = sd_bus_call_method(bus,
SERVICE_NAME,
OBJECT_PATH,
INTERFACE,
"AddData",
&error, &m,
"(a(ss))",
1, /* size of array */
"hello",
"world");

Related

GLIB D-BUS Bluetooth - How to get the file descriptor?

I am using BLUEZ and GLIB/D-BUS to connect 2 Raspberry Pi (also a laptop and a Raspberry Pi).
So far I could make fair progress.
EDIT: on good advises from #ukBaz I am using a python client from my laptop, and my C code server on the Raspberry Pi.
On the "server", I can register the device with a custom service UUID and a Serial RFCOMM profile UUID, and wait for connection. Connecting with the python client works and I can see that there is a handler available (see after code below for debug output)
I'm using this code (within a dbus loop, code simplified for readability):
static void new_connection(GDBusMethodInvocation *inv)
{
g_log(LOG_SERVER, G_LOG_LEVEL_MESSAGE, "New connection.");
GDBusMessage *msg = g_dbus_method_invocation_get_message(inv);
// This prints the output below this code snippet
gchar *content = g_dbus_message_print(msg, 2);
g_log(LOG_SERVER, G_LOG_LEVEL_INFO, "Message is:\n%s", content);
g_free(content);
GVariant *params = g_dbus_method_invocation_get_parameters(inv);
const char *object;
GVariant *properties;
gint32 *handle;
g_variant_get(params, "(oha{sv})", &object, &handle, &properties);
// Problem here, 'handle' is NULL
g_log(LOG_SERVER, G_LOG_LEVEL_INFO, "Object is [%s]\nHandle is [%ls]", object, handle);
GVariantIter iter;
g_variant_iter_init(&iter, properties);
display_properties(&iter);
}
Here is the output:
New connection.
Message is:
Type: method-call
Flags: none
Version: 0
Serial: 32
Headers:
path -> objectpath '/org/bluez/jscturret'
interface -> 'org.bluez.Profile1'
member -> 'NewConnection'
destination -> ':1.18'
sender -> ':1.11'
signature -> signature 'oha{sv}'
num-unix-fds -> uint32 1
Body: (objectpath '/org/bluez/hci0/dev_00_AA_AA_AA_AA_AA', handle 0, #a{sv} {})
UNIX File Descriptors:
fd 7: dev=0:8,mode=0140777,ino=41101,uid=0,gid=0,rdev=0:0,size=0,atime=0,mtime=0,ctime=0
Object is [/org/bluez/hci0/dev_00_AA_AA_AA_AA_AA]
Handle is [(null)]
It shows that there is a file descriptor fd 7 but when I read the GVariant parameter I get NULL.
How can I access the file descriptor? My understanding is I need that to be able to read/write from/to the client.
I used https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/doc/device-api.txt and https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/doc/adapter-api.txt for reference and a few other posts here on SO.
Also got a lot of info in https://www.linumiz.com/.
Current full code is available here: btservice
Oh! I am pretty sure you are supposed to send a pointer to an integer (not a pointer to a pointer to it).
You can do
gint32 handle; // instead of gint32 *handle;
and it should work.
This API has a very poor design (relying on variadic, with format specifiers... the reason why people dislike C).

The correct way to communicate with Glib/Gtk from another thread [duplicate]

I need to attach file descriptors to the GLIB mainloop. My issue is that the list of file descriptors is not fixed during execution.
According to GLIB documentation, I can:
create a GIOChannel for each FD using g_io_channel_unix_new and attach it to the context with g_io_add_watch
Use a Gsource created with g_io_create_watch and set a callback g_source_set_callback
My question is : is it possible to modify dynamically a source or a context. And how can I do it ? I find the GSourceFuncs ability, but that doesn't fit my issue.
Thanks for your help.
g_io_add_watch returns an event source ID which you can later use to dynamically remove the watch again, using g_source_remove. Use one event source per FD and instead of modifying existing watches, remove the old ones and create appropriate new ones.
I digged more into GLIB and now:
I create a source with callbacks functions (prepare, check, dispatch, finalize)
In the prepare callback, FD are deleted using g_source_remove_unix_fd() and then added to the current source using g_source_add_unix_fd().
I returned FALSE to set the timeout (1s for my example)
My issue is that without the FD, the prepare callback is called each 1s as expected. When FD is added, the prepare callback is called without timeout. the poll exit directly.
I have a look into GLIB source code, but don't understand the reason why ?
Help please
Regards
amenophiks' answer is the best.
If you want your code to work with an older glib you can use:
g_source_add_poll()
g_source_remove_poll()
Have you read the Main Event Loop documentation? The description section has a pretty good explanation of how things work.
Have you looked at the Custom GSource tutorial? This allows you to extend a GSource object to include your own state. You also can write your own prepare, dispatch, query, and check functions.
Whenever I really want to see how something should be done with GLib, GTK, etc the first place I look is the test code that lives in their git repository. Be sure to checkout the proper tag for the version of that you are targeting.
For example I currently target 2.48.2
Here are two pretty good examples
https://gitlab.gnome.org/GNOME/glib/blob/2.48.2/tests/mainloop-test.c
https://gitlab.gnome.org/GNOME/glib/blob/2.48.2/glib/tests/mainloop.c
The other nice feature is it's a git repository so you can search it very easily.
Seems, I found a diminutive hook. Try this:
struct source {
GSource gsrc;
GPollFD *gpfd;
};
struct data {
/* A something data. */
};
static gboolean gsrc_dispatch(GSource *gsrc, GSourceFunc cb, gpointer data);
static struct data * data_alloc(void);
static GSourceFuncs gsf = {
.prepare = NULL,
.check = NULL,
.dispatch = gsrc_dispatch,
.finalize = NULL
};
int main(void)
{
struct source *src;
int fd;
struct data *data = data_alloc();
/* Something other. */
/* For example, we are want to capture video from a camera. */
fd = open("/dev/video0", O_RDWR);
if (fd < 0) {
perror("open()");
return -1;
}
src = (struct source *) g_source_new(&gsf, sizeof(struct source));
src->gpfd = g_source_add_unix_fd((GSource *) src, fd, G_IO_IN);
g_source_set_callback((GSource *) src, NULL, data, NULL);
g_source_attach((GSource *) src, NULL);
/* Something other and free. */
return 0;
}
static gboolean
gsrc_dispatch(GSource *gsrc, GSourceFunc cb, gpointer data)
{
struct source *src = (struct source *) gsrc;
struct data *d = data;
if (src->gpfd != NULL) {
if (src->gpfd->revents & G_IO_IN) {
/* Capture a frame. */
}
}
g_main_context_iteration(NULL, TRUE);
return G_SOURCE_CONTINUE;
}
static struct data *
data_alloc(void)
{
/* Allocate a data. */
}
Yes, you can use the double gpfd pointer.

Flutter (Dart) ffi - Aplication freezes during processing external library methohd

I am using C library iperf3 to measure network. When I start network testing my aplication freezes and wait for results. I tried async and threads but any progress. Any advise? I'd like to run my test and asynchronously call another methods (at best, call this library again, but other methods). Is it possible?
My network.dart
final DynamicLibrary iperfLib = Platform.isAndroid
? DynamicLibrary.open("libiperf.so")
: DynamicLibrary.process();
typedef RunTestFunc = ffi.Pointer<ffi.Uint8> Function(
ffi.Pointer<ffi.Uint8> context);
typedef RunTest = ffi.Pointer<ffi.Uint8> Function(
ffi.Pointer<ffi.Uint8> context);
RunTest _run_test = iperfLib
.lookup<ffi.NativeFunction<RunTestFunc>>('run_test')
.asFunction<RunTest>();
ffi.Pointer<ffi.Uint8> runTest(ffi.Pointer<ffi.Uint8> context) {
return _run_test(context);
}
and iperf.c
Iperf* run_test(Iperf* test) {
__android_log_print( ANDROID_LOG_INFO, "DONE ", "server_hostname %s", test->server_hostname );
int cc = iperf_run_client( test ) ;
__android_log_print( ANDROID_LOG_INFO, "DONE ", " %d",cc );
iperf_free_test( test );
return test
}
Async Callbacks
The problem is that C routines called from dart are blocking and therefore congest the single existing dart isolate, consequently freezing the UI.
To work around this problem you have to open a port on the dart isolate through which your C routines can asynchronously send messages to the dart isolate. To signal to the dart compiler that this is a non-blocking operation, simply delay the completion of the function until a message on the designated port has been received.
Future<int> asyncData() async {
var receiveData;
bool receivedCallback = false;
var receivePort = ReceivePort()..listen((data) {
print('Received data from c');
receiveData = data;
receivedCallback = true;
});
var nativeSendPort = receivePort.sendPort.nativePort;
nativeTriggerFunction(nativeSendPort);
while(!receivedCallback) {
await Future.delayed(Duration(milliseconds: 100));
}
receivePort.close();
return receiveData;
}
In C, you need to create a trigger function which should ideally be as lightweight as possible, passing the port number to your C code and calling the actual function you want to execute on a different thread.
The trigger function will finish almost instantly, allowing your dart thread to do other work and as soon as the newly created thread is done, it sends its result through the native port back to the dart isolate which can pick up where it left off.
void native_trigger_function(Dart_Port port) {
pthread_t t;
Dart_Port *args = (Dart_Port *) malloc(sizeof(Dart_Port));
*args = port;
pthread_create(&t, NULL, _native_function, args);
}
void *_native_function(void *args) {
Dart_Port port = *(Dart_Port *) args;
int rc = 0;
// do some heavy work
// send return code to dart
Dart_CObject obj;
obj.type = Dart_CObject_kInt32;
obj.value.as_int32 = rc;
Dart_PostCObject_DL(port, &obj);
free(args);
pthread_exit(NULL);
}
Note: This logic relies on the native dart api to work which can be found here. Before use, the interface needs to be attached to the current dart isolate which can be achieved by calling Dart_InitializeApiDL(dart_api_data) from C where dart_api_data is a void pointer which can be obtained from your dart code using the dart:ffi package through NativeApi.initializeApiData.
Update: Thanks #fdollack for fixing the example snippets!
Thank you #Lucas Aschenbach!
This minimum example was so hard to find.
2 small additions.
First, the allocated pointer should be casted to (Dart_Port*),
and the port argument from dart has to be assigned/copied to where the pointer is at!
void native_trigger_function(Dart_Port port) {
pthread_t t;
Dart_Port *args= (Dart_Port*)malloc(sizeof(Dart_Port));
*args = port; // assign port
pthread_create(&t, NULL, _native_function, args);
}
The second thing is inside the _native_function the response to Dart has to be
Dart_PostCObject_DL(port, &obj);
instead of
Dart_PostCObject_DL(args_c.send_port, &obj);

Calling a C library method from swift using pointers

Given the following ODBC C API information and associated type definitions, how does one call the SQLSetEnvAttr function from swift?
From swift, my code successfully invokes the prerequisite SQLAllocHandle function which provides the handle to the environment (henv) utilized in the subsequent SQLSetEnvAttr function call.
I have tried a variety of approaches including UnsafeMutablePointer, attempting to follow instructions referenced on the following sites, but I couldn't figure out how to get the compiler to allow me to convert from a Void * to a SQLPOINTER (even though it is defined to be the same thing). Additionally, I was stymied on how to make the UnsafeMutablePointer point to the value of the CUnsignedLong variable (SQL_OV_ODBC3 typedef) I used (set to 3)
http://www.sitepoint.com/using-legacy-c-apis-swift/
http://chris.eidhof.nl/posts/swift-c-interop.html
ODBC API
typedef signed short int SQLSMALLINT;
typedef SQLSMALLINT SQLRETURN;
typedef void * SQLPOINTER;
#define SQL_ATTR_ODBC_VERSION 200
#define SQL_OV_ODBC3 3UL
retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION,
(SQLPOINTER) SQL_OV_ODBC3, 0);
The working swift code that gets me the handle to the environment is:
var sqlHenvPtr : UnsafeMutablePointer<SQLHENV> = UnsafeMutablePointer<SQLHENV>.alloc(1)
var retcode : CShort = SQLAllocHandle(Int16(SQL_HANDLE_ENV), nil, sqlHenvPtr)
Looking for help with how to define and pass the third parameter:
let SQL_ATTR_ODBC_VERSION : Int32 = 200
retcode = SQLSetEnvAttr(sqlHenvPtr.memory, SQL_ATTR_ODBC_VERSION, ???, 0)
Any assistance would be much appreciated.
Updated per Chris's feedback
let value = UnsafeMutablePointer<Void>(bitPattern: 3)
SQLSetEnvAttr(0, 0, value, 0)
The expected value by SQLSetEnvAttr() is 0x3 (in your case it was 0x10025a478). I verified that my own prototype C function which accepts SQLPOINTER receives 0x3 in case of preparing 3rd parameter in proposed way. Hope it helps now.

Adding headers onto rabbitmq c client

I use librabbitmq C library to deal with AMQP-complaint brokers (RabbitMQ in my case) and i try to add headers onto the c client, for rabbitmq.
I modified amqp_sendstring.c
amqp_basic_properties_t props;
props._flags = AMQP_BASIC_CONTENT_TYPE_FLAG | AMQP_BASIC_DELIVERY_MODE_FLAG | AMQP_BASIC_HEADERS_FLAG;
props.content_type = amqp_cstring_bytes("text/plain");
props.delivery_mode = 2; /* persistent delivery mode */
amqp_table_t *table=&props.headers;
props.headers.num_entries=2;
props.headers.entries=calloc(props.headers.num_entries, sizeof(amqp_table_entry_t));
strcpy(&(table->entries[0]).key,"id1");
((table->entries[0]).value).kind=AMQP_FIELD_KIND_I32;
((table->entries[0]).value).value.i32=1234;
strcpy(&(table->entries[1]).key,"id2");
(table->entries[1]).value.kind=AMQP_FIELD_KIND_I32;
(table->entries[1]).value.value.i32=5678;
die_on_error(amqp_basic_publish(conn,
1,
amqp_cstring_bytes(exchange),
amqp_cstring_bytes(routingkey),
0,
0,
&props,
and in amqp_listen.c:
132 printf("Num headers received %d \n", envelope.message.properties.headers.num_entries);
However the listener doesn't seem to receive any headers. Any body have any suggestions? Other sample code?
The .key member of amqp_table_entry_t is an amqp_bytes_t not a char*, so you should use amqp_cstring_bytes() to set it instead of strcpy().

Resources