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

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).

Related

How do I read OpenVINO IR models from memory with the OpenVINO C API

I am having trouble reading OpenVINO IR networks (XML and bin) from memory using ie_core_read_network_from_memory() in the OpenVINO 2021.4 C API ie_c_api.h.
I suspect that I am creating the network weight blob wrong, but I cannot find any information on how to create weight blobs correctly for networks.
I have read the OpenVINO C API docs but cannot deduce from docs what I am doing wrong. The OpenVINO code repo contains some C code samples, but none of the samples seem to use ie_core_read_network_from_memory().
Below is a cut out of the code I am having trouble with.
// void* dmem->data - network memory buffer (float32)
// size_t dmem->size - size of network memory buffer (bytes)
ie_core_t* ov_core = NULL;
IEStatusCode status = ie_core_create("", &ov_core);
if (status != OK)
{
// error handling
}
const dimensions_t weights_tensor_dims =
{ 4, { 1, 1, 1, dmem->size/sizeof(float) } };
tensor_desc_t weights_tensor_desc = { OIHW, weights_tensor_dims, FP32 };
ie_blob_t* ov_model_weight_blob = NULL;
status = ie_blob_make_memory_from_preallocated(
&weights_tensor_desc, dmem->data, dmem->size, &ov_model_weight_blob);
if (status != OK)
{
// error handling
}
// char* model_xml_desc - the model's XML string
uint8_t* ov_model_xml_content = (uint8_t*)model_xml_desc;
ie_network_t* ov_network = NULL;
size_t xml_sz = strlen(ov_model_xml_content);
status = ie_core_read_network_from_memory(
ov_core, ov_model_xml_content, xml_sz, ov_model_weight_blob, &ov_network);
if (status != OK)
{
// Always get "GENERAL_ERROR (-1)"
}
The code works fine down to the ie_core_read_network_from_memory() call which results in "GENERAL_ERROR".
I have tried two models that were converted from Tensorflow. One is a simple [X] -> [Y] regression model (single input value, single output value). The other is also a regression model [X_1, X_2, ..., X_9] -> [Y] (nine input values, single output value). They work fine when reading them from file with ie_core_read_network(), but for my use case I must provide the network as a binary memory buffer and XML string.
I would appreciate any help, either by pointing out what I am getting wrong or directing me to some code samples that use ie_core_read_network_from_memory().
System information:
Windows 10
OpenVINO v2021.4.689
Microsoft Visual Studio 2019
UPDATE: An Intel employee reached out to me in another forum and pointed out that there is a unit test for ie_core_read_network_from_memory(). The unit test successfully reads a network from memory and made clear that I was in fact using a faulty tensor description to produce the weight blob, just as I suspected. Apparently the weight blob descriptor should be one dimensional, have memory layout ANY and datatype U8 even though the model weights are fp32.
From the unit test:
std::string bin_std = TestDataHelpers::generate_model_path("test_model", "test_model_fp32.bin");
const char* bin = bin_std.c_str();
//...
std::vector<uint8_t> weights_content(content_from_file(bin, true));
tensor_desc_t weights_desc { ANY, { 1, { weights_content.size() } }, U8 };
However, simply changing the tensor descriptor was not enough to get my code to work so it remains for me to properly translate the C++ code from the unit test to my C environment before the issue to can be considered solved.
Thanks
Refer to tensor_desc struct and standard layout format.
Apart from that, it is recommended to use the Benchmark_app tool to test the inference performance.

IBM MQ MQCONN from host to Docker container

Trying to connect from a C application running as an IBM MQ client on a host to an MQ server running as a docker container.
The client code taken from an IBM example is provided below.
The questions is which protocol is used when MQCONN is called as no IP/port is provided? I can only guess it is some kind of an IPC.
For this reason I'm running the docker container with --ipc="host" option, but it still fails with CompCode=2, Reason=2058
#include <cmqc.h>
⋮
static char Parm1[MQ_Q_MGR_NAME_LENGTH] ;
⋮
int main(int argc, char *argv[] )
{
/* */
/* Variables for MQ calls */
/* */
MQHCONN Hconn; /* Connection handle */
MQLONG CompCode; /* Completion code */
MQLONG Reason; /* Qualifying reason */
⋮
/* Copy the queue manager name, passed in the */
/* parm field, to Parm1 */
strncpy(Parm1,argv[1],MQ_Q_MGR_NAME_LENGTH);
⋮
/* */
/* Connect to the specified queue manager. */
/* Test the output of the connect call. If the */
/* call fails, print an error message showing the */
/* completion code and reason code, then leave the */
/* program. */
/* */
MQCONN(Parm1,
&Hconn,
&CompCode,
&Reason);
if ((CompCode != MQCC_OK) | (Reason != MQRC_NONE))
{
sprintf(pBuff, MESSAGE_4_E,
ERROR_IN_MQCONN, CompCode, Reason);
PrintLine(pBuff);
RetCode = CSQ4_ERROR;
goto AbnormalExit2;
}
⋮
}
If your program will be running on the same server as the queue manager then it is best to link it with 'mqm.lib' (bindings mode) rather than 'mqic.lib' (client mode).
In the MQ KnowLedge Center, there are examples on how to compile and link your C program. The examples are listed as: 'C client application' (client mode) and 'C server application' (bindings mode).
If in the future, your C program needs to connect to a remote queue manager then you need to link it for 'client mode'.
To configure your C program to handle proper MQ security, change the MQCONN API call to MQCONNX API call.
i.e.
MQCNO cno = {MQCNO_DEFAULT};
MQCD cd = {MQCD_CLIENT_CONN_DEFAULT};
MQCSP csp = {MQCSP_DEFAULT};
strncpy(cd.ConnectionName, hostname, MQ_CONN_NAME_LENGTH);
strncpy(cd.ChannelName, channelName, MQ_CHANNEL_NAME_LENGTH);
csp.AuthenticationType = MQCSP_AUTH_USER_ID_AND_PWD;
csp.CSPUserIdPtr = &myUserId;
csp.CSPUserIdOffset = 0;
csp.CSPUserIdLength = strlen(myUserId);
csp.CSPPasswordPtr = &myPassword;
csp.CSPPasswordOffset = 0;
csp.CSPPasswordLength = strlen(myPassword);
cno.cdPtr = &cd;
cno.Version = MQCNO_CURRENT_VERSION;
cno.SecurityParmsPtr = &csp;
cno.SecurityParmsOffset = 0;
MQCONNX(QMgrName, &cno, &Hcon, &CompCode, &Reason);
A few years ago, I wrote a blog posting called: MQ API Verbs that IBM Forgot!!. I created wraps for MQCONN and MQCONNX that will allow the program to pass UserId & Password for MQCONN and MQCONNX API calls. You may find it easier to simply use the wrappers.

Calling Chicken Scheme function from SDL2 audio callback function hangs

I am trying to embed Chicken Scheme into a C program, to generate sounds to be played with SDL2's audio system. I would have liked to use the sdl2 egg, but it does not seem to support Audio yet (despite the documentation mentioning the 'audio flag for the init! function).
At first, I was using SDL_QueueAudio from C, passing it a buffer that I had allocated in C and then filled in Scheme. This worked fine, passing a Sint16 * and size_t into Scheme, then using pointer-s16-set! from Scheme to fill it and returning a size_t to note how many cells were filled.
Then, when I realised that using the callback api for generating the audio was much better suited to this, I tried switching to it (having already used it before in C), only for the Scheme function to never be entered. Logging something in the callback function before the Scheme call worked, but logging directly within the Scheme function, or after the Scheme call, never happened.
I can only imagine that this is due to SDL2's audio callback running on a separate thread, and that messing with calling through to Scheme somehow. With this in mind, I tried calling CHICKEN_run(C_toplevel); from within the callback function, the first time that it was called, but that only resulted in a bus error.
So my question is: is there a way of calling embedded Chicken Scheme from SDL2's audio callback?
I am on macOs 10.13.6 High Sierra, with SDL2 and chicken both installed and up-to-date through Homebrew.
I compile with (as I said, this works fine when using the queue audio api):
csc code.c codescm.scm -embedded -o code -L -lSDL2
My simplified code is below:
#include <chicken.h>
#include "SDL2/SDL.h"
extern size_t fill_sound_buffer(Sint16 *buffer, size_t buffer_length);
void fill_sound_callback(void *user_data, Uint8 *stream, int stream_length)
{
// Logging here prints to the console
fill_sound_buffer((Sint16 *)stream, stream_length / 2);
// Logging here does not print to the console
}
void play(void)
{
SDL_AudioSpec audio_want;
SDL_zero(audio_want);
audio_want.freq = 44100;
audio_want.format = AUDIO_S16SYS;
audio_want.channels = 1;
audio_want.samples = 2048;
audio_want.callback = fill_sound_callback;
SDL_AudioSpec audio_have;
SDL_AudioDeviceID audio_device = SDL_OpenAudioDevice(NULL, 0, &audio_want, &audio_have, 0);
SDL_PauseAudioDevice(audio_device, 0);
SDL_Delay(5000);
// Logging here shows up after 5 seconds, but the program then continues to wait
SDL_CloseAudioDevice(audio_device);
}
int main(int argc, char *argv[])
{
SDL_Init(SDL_INIT_AUDIO);
CHICKEN_run(C_toplevel);
play();
SDL_Quit();
return 0;
}
(import (chicken format)
(chicken foreign)
(chicken memory)
(chicken platform))
(define-external (fill_sound_buffer ((c-pointer short) buffer) (size_t buffer_length)) size_t
; This never prints when using the callback api
(printf "In Scheme~%")
; Removed the code that calculates a sine wave and fills the buffer with it, which works
0)
(return-to-host)

Send net-snmp INFORM calling send_v2trap() in C

This tutorial explains how to send a SNMP TRAP calling send_v2trap() in C.
How do I send a SNMP INFORM instead?
The manpage says I can send INFORMs, but it doesn't say how.
Figured out by myself :-)
send_v2trap(3) says:
send_v2trap() uses the supplied list of variable bindings to form an SNMPv2 trap,
which is sent to SNMPv2-capable sinks on the configured list.
An equivalent INFORM is sent to the configuredq list of inform sinks.
but doesn't say what is this configured list;
Instead, snmpd.conf(5) explains that I should edit /etc/snmp/snmpd.conf and add lines telling which hosts will receive the INFORMs. For example, the following makes send_v2trap() send INFORM to host1 and host2:
informsink host1 public 162
informsink host2 public 162
Actually, you can register the sinks inside C by using the net-snmp, agent_trap.h function:
void snmpd_parse_config_informsink(const char *, char *);
where I suppose that the first argument is not used and the second argument you can write as the following example in C++:
//sink declarations
String serverAddress = "127.0.0.1";
int serverPort = 162;
String community = "public";
//mount sink string
string cptrS = serverAddress + ":" + to_string(serverPort) + " \t\n" + community;
//transform string to char*
char * cptr = &cptrS[0];
//register the sink
snmpd_parse_config_informsink(NULL,cptr);
now, you can call send_v2trap() and send by inform the variables set using snmp_varlist_add_variable().
Reference: http://www.net-snmp.org/dev/agent/agent__trap_8c-source.html

How do I create a "netlink" between kernel and userspace?

I want to use netlink to communicate between an application and kernel space. My Linux kernel version is 2.6.28, and the following is my wrong code:
nf_sock=netlink_kernel_create(NL_PROTO,0,nl_user_skb,THIS_MODULE);
The abbreviated error message is:
error: too few arguments to function 'netlink_kernel_create'
In the file <linux/netlink.h>, the function netlink_kernel_create() is defined as
extern struct sock *netlink_kernel_create(struct net *net,int unit,unsigned int groups,void (*input)(struct sk_buff *skb),struct mutex *cb_mutex,struct module *module)
I don't understand what to use for the first argument, net. Can someone explain what I should use here?
A struct net contains information about the network namespace, a set of network resources available to processes. Note that there could be multiple network namespaces (i.e. multiple instances of the networking stack), but most drivers use the init_net namespace.
Your call should probably look something like the following
nf_sock = netlink_kernel_create(&init_net,
NETLINK_USERSOCK,
0,
nl_rcv_func,
NULL,
THIS_MODULE);
where nl_rcv_func is a function taking struct sk_buff *skb as the only argument and processes the received netlink message.
You seem to have been following a guide such as this one, which (being from 2005) might well have been outpaced by the development of the kernel. It seems the internal API to create a netlink from the kernel side has changed.
Either check the Documentation/ folder in your local kernel tree for some (hopefully fresher) documentation, or read the code itself. You could also trawl the Linux Kernel mailing list archives for any mention of the changes that seem to have happened.
Here is the actual implemntation as of 2.6.29, if you'd rather puzzle it out backwards (and haven't already checked this in your own tree, of course).
Yes, struct net is indeed for net namespace, but it is not proper to always use init_net, you should register your own pernet_operations, like this:
static struct pernet_operations fib_net_ops = {
.init = fib_net_init,
.exit = fib_net_exit,
};
static int __net_init fib_net_init(struct net *net)
{
int error;
#ifdef CONFIG_IP_ROUTE_CLASSID
net->ipv4.fib_num_tclassid_users = 0;
#endif
error = ip_fib_net_init(net);
if (error < 0)
goto out;
error = nl_fib_lookup_init(net);
if (error < 0)
goto out_nlfl;
error = fib_proc_init(net);
if (error < 0)
goto out_proc;
out:
return error;
out_proc:
nl_fib_lookup_exit(net);
out_nlfl:
ip_fib_net_exit(net);
goto out;
}
static int __net_init nl_fib_lookup_init(struct net *net)
{
struct sock *sk;
struct netlink_kernel_cfg cfg = {
.input = nl_fib_input,
};
sk = netlink_kernel_create(net, NETLINK_FIB_LOOKUP, &cfg);
if (sk == NULL)
return -EAFNOSUPPORT;
net->ipv4.fibnl = sk;
return 0;
}
and finally:
register_pernet_subsys(&fib_net_ops);
I would suggest ioctl for kernel/user communication. The ioctl interface is standard and the chance of been updated between kernels is small.

Resources