NanoPB Callback functions - c

I am working on a project which includes the use of NanoPB.
Currently I have the situation where in my protofile I have multiple callback fields.
I now must encode and decode these callback fields using my own written callback functions.
My question is:
I have a message defined in the protofile which contains callback fields and non callback fields. If I create an callback encode function, should I make this for a specific field or for the entire message?
My protofile looks like this:
syntax = "proto2";
message stringCallback{
required string name = 1;
required string surname = 2;
required int32 age = 3;
}
An example of encoding a string:
bool encode_string(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{
char *str = "Hello world!";
if (!pb_encode_tag_for_field(stream, field))
return false;
return pb_encode_string(stream, (uint8_t*)str, strlen(str));
}

If I create an callback encode function, should I make this for a specific field or for the entire message?
Whatever is most suitable for your purpose.
The example callback you show is not particularly useful. If you only wanted to take a string from char*, you could just set (nanopb).type = FT_POINTER on the field.
If your callback actions are the same for multiple fields, by all means, reuse the same function. If there is a difference, make separate functions.

Related

C Curl 400 Bad Request keyword "on"

I wrote a C Program that calls a webservice with cURL. I started my test by hardcoding the address of the webservice with parameters like this :
http://....php?type=adresse&texte=XYZ
It worked fine so I've tried to concatenate a variable for field texte has shown below but it failed and returned me 400 Bad Request.
We checked the content of the request and there is a keyword "on" in front of the webservice address and I don't know where that come from.
on http://....php?type=adresse&texte=xyz&indDebut=0&indFin=1&epsg=900913&format=json"
char* mystrcat( char* dest, char* src )
{
while (*dest) dest++;
while (*dest++ = *src++);
return --dest;
}
recherche = "G0A3B0";
pcbak_adresse(recherche);
const char * pcbak_adresse(const char *details)
{
...
char * lien;
const char * fin_lien;
lien = "http://....php?type=adresse&texte=";
fin_lien = "&indDebut=0&indFin=1&epsg=900913&format=json";
/*Concatenation function*/
mystrcat(details, fin_lien);
mystrcat(lien, details);
/* Set CURL parameters */
curl_easy_setopt(curlHandler, CURLOPT_URL, lien);
curl_easy_setopt(curlHandler, CURLOPT_CUSTOMREQUEST, "GET");
curl_easy_setopt(curlHandler, CURLOPT_WRITEFUNCTION, callback_func);
curl_easy_setopt(curlHandler, CURLOPT_WRITEDATA, &str);
res = curl_easy_perform(curlHandler);
/* Check for errors */
if (res != CURLE_OK)
return curl_easy_strerror(res);
...
}
Thanks for your help!
No matter what mystrcat() is,
mystrcat(lien, details);
is wrong.
If it creates a new string composed by the two inputs, it's not being captured anywhere.
If it tries to write to lien it's undefined behavior. Because you cannot modify string literals which is what lien is.
The same reasoning probably applies to details, but you didn't post details declaration and/or definition.
Do not use anything like strcat() except if you want to do it only once.
To concatenate strings use something like a structure where you store the length of the current string, the size of the target array, and of course the target array. You can then resize the target when you need to, you don't need to find the end of the target string every time (which is what strcat() will do), you also have the advantage of controlling how you append to the string with a lot of detail.
To achieve what you want, you can do this
char lien[256];
int length;
length = snprintf(
lien,
sizeof(lien),
"http://....php?type=adresse&texte=%s&indDebut=0&indFin=1&epsg=900913&format=json",
details
);
if ((length >= sizeof(lien)) || (length == -1))
return error_occurred_here();
Also, returning a static string (which probably is what curl_easy_strerror() returns), and a tentatively dynamic one from the same function is bad design, because,
You can't tell whether it's an error or the JSON returned from the link.
You will need some method to determine whether it's a static string or the one generated in the function in order to free() it.

How to read URLs containing question marks in C using microhttpd.h

I am trying to parse the URL in C using microhttpd library.
daemon = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_SSL, PORT, NULL, NULL, &answer_to_connection, NULL, MHD_OPTION_HTTPS_MEM_KEY, key_pem, MHD_OPTION_HTTPS_MEM_CERT, cert_pem, MHD_OPTION_END);
When I run the function MHD_start_daemon a call back function answer_to_connection is called.
static int answer_to_connection(void *cls, struct MHD_Connection *connection, const char *url, const char *method, const char *version, const char *upload_data, size_t *upload_data_size, void **con_cls)
{
printf("URL:%s\n", url);
}
One of the parameters of answer_to_connection is const char *url. The url variable contains the string after https://localhost:port example: for http://128.19.24.123:8888/cars/ferrari the url value will be /cars/ferrari
But in case of http://128.19.24.123:8888/cars?value=ferrari the url is printing only cars.
I want to print cars?value=ferrari. How can I do that?
There is a tutorial on microhttpd library at https://www.gnu.org/software/libmicrohttpd/tutorial.html
But I can't find any solution to this problem there.
CAVEAT EMPTOR: I have not used this library, this answer is based on a quick perusal of the API.
It looks like you can't access the whole original URL, because microhttpd parses it for you. Instead you access the individual query string values using MHD_lookup_connection_value, like this:
value = MHD_lookup_connection_value(connection, MHD_GET_ARGUMENT_KIND, "value");
That would return a pointer to the value of the query string argument, or null if not found.
You can also use MHD_get_connection_values to iterate over the query string components. In that case you would call it like this:
num = MHD_get_connection_values(connection, MHD_GET_ARGUMENT_KIND, iterator, cls);
iterator would be a callback function to receive the GET query arguments, one by one.
See also: the Handling requests section in the manual.

Nanopb without callbacks

I'm using Nanopb to try and send protobuf messages from a VxWorks based National Instruments Compact RIO (9025). My cross compilation works great, and I can even send a complete message with data types that don't require extra encoding. What's getting me is the callbacks. My code is cross compiled and called from LabVIEW and the callback based structure of Nanopb seems to break (error out, crash, target reboots, whatever) on the target machine. If I run it without any callbacks it works great.
Here is the code in question:
bool encode_string(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{
char *str = "Woo hoo!";
if (!pb_encode_tag_for_field(stream, field))
return false;
return pb_encode_string(stream, (uint8_t*)str, strlen(str));
}
extern "C" uint16_t getPacket(uint8_t* packet)
{
uint8_t buffer[256];
uint16_t packetSize;
ExampleMsg msg = {};
pb_ostream_t stream = pb_ostream_from_buffer(buffer, sizeof(buffer));
msg.name.funcs.encode = &encode_string;
msg.value = 17;
msg.number = 18;
pb_encode(&stream, ExampleMsg_fields, &msg);
packetSize = stream.bytes_written;
memcpy(packet, buffer, 256);
return packetSize;
}
And here's the proto file:
syntax = "proto2"
message ExampleMsg {
required int32 value = 1;
required int32 number = 2;
required string name = 3;
}
I have tried making the callback an extern "C" as well and it didn't change anything. I've also tried adding a nanopb options file with a max length and either didn't understand it correctly or it didn't work either.
If I remove the string from the proto message and remove the callback, it works great. It seems like the callback structure is not going to work in this LabVIEW -> C library environment. Is there another way I can encode the message without the callback structure? Or somehow embed the callback into the getPacket() function?
Updated code:
extern "C" uint16_t getPacket(uint8_t* packet)
{
uint8_t buffer[256];
for (unsigned int i = 0; i < 256; ++i)
buffer[i] = 0;
uint16_t packetSize;
ExampleMsg msg = {};
pb_ostream_t stream = pb_ostream_from_buffer(buffer, sizeof(buffer));
msg.name.funcs.encode = &encode_string;
msg.value = 17;
msg.number = 18;
char name[] = "Woo hoo!";
strncpy(msg.name, name, strlen(name));
pb_encode(&stream, ExampleMsg_fields, &msg);
packetSize = stream.bytes_written;
memcpy(packet, buffer, sizeof(buffer));
return packetSize;
}
Updated proto file:
syntax = "proto2"
import "nanopb.proto";
message ExampleMsg {
required int32 value = 1;
required int32 number = 2;
required string name = 3 [(nanopb).max_size = 40];
}
You can avoid callbacks by giving a maximum size for the string field using the option (nanopb).max_size = 123 in the .proto file. Then nanopb can generate a simple char array in the structure (relevant part of documentation).
Regarding why callbacks don't work: just a guess, but try adding extern "C" also to the callback function. I assume you are using C++ there, so perhaps on that platform the C and C++ calling conventions differ and that causes the crash.
Does the VxWorks serial console give any more information about the crash? I don't remember if it does that for functions called from LabView, so running some test code directly from the VxWorks shell may be worth a try also.
Perhaps the first hurdle is how the code handles strings.
LabVIEW's native string representation is not null-terminated like C, but you can configure LabVIEW to use a different representation or update your code to handle LabVIEW's native format.
LabVIEW stores a string in a special format in which the first four bytes of the array of characters form a 32-bit signed integer that stores how many characters appear in the string. Thus, a string with n characters requires n + 4 bytes to store in memory.
LabVIEW Help: Using Arrays and Strings in the Call Library Function Node
http://zone.ni.com/reference/en-XX/help/371361L-01/lvexcodeconcepts/array_and_string_options/

strcpy() does not write new string

In my code, I want to update the contents of global array data via a function. When I call the function, however, the contents of data do not change, despite the function calling strcpy() to effect that change -- afterward, data still contains "prg". How can I use strcpy() or something similar to write a new value to data?
char data[255] = "prg";
void process_tuple(Tuple *t)
{
//Get key
int key = t->key;
//Get integer value, if present
int value = t->value->int32;
//Get string value, if present
char string_value[32];
strcpy(string_value, t->value->cstring);
strcpy(data, "prg1212");
//Decide what to do
switch(key) {
case key_0:
break;
};
}
static WeatherAppDataPoint s_data_points[] =
{
{
.city = data,
.description = "surfboard :)",
.icon = WEATHER_APP_ICON_GENERIC_WEATHER,
.current = 110,
.high = 120,
.low = 100,
},
};
You are mistaking, the program as written will change data to prg1212 if the function is executed. You are either not calling it (bad event hookup, etc), the code as written isn't accurate (partial code that hides the real problem) or evaluating the wrong pointer during debugging (or at the wrong time).
I have figured out the problem with help from #Blidny and #MikeofSST
It turns out that my code above contained in a file app_data.c wasn't running code outside if the functions created in app_data.h. I moved my code up into the void where my temperature values were formatted and written, and strcpy() worked like a charm.

How to get metadata from Libextractor into a struct

I want to use Libextractor to get keywords/metadata for files.
The basic example for it is -
struct EXTRACTOR_PluginList *plugins
= EXTRACTOR_plugin_add_defaults (EXTRACTOR_OPTION_DEFAULT_POLICY);
EXTRACTOR_extract (plugins, argv[1],
NULL, 0,
&EXTRACTOR_meta_data_print, stdout);
EXTRACTOR_plugin_remove_all (plugins);
However, this calls the function EXTRACTOR_meta_data_print which "prints" it to "stdout"
I'm looking at a way to get this information to another function - i.e. pass or store this in memory for further working. The documentation was not clear to me. Any help or experience regarding this?
I've tried to install libextractor and failed to get it working (it always returns a NULL plugin pointer upon call to EXTRACTOR_plugin_add_defaults()), so what I will write next is NOT TESTED:
from : http://www.gnu.org/software/libextractor/manual/libextractor.html#Extracting
Function Pointer: int
(*EXTRACTOR_MetaDataProcessor)(void *cls,
const char *plugin_name,
enum EXTRACTOR_MetaType type,
enum EXTRACTOR_MetaFormat format,
const char *data_mime_type,
const char *data,
size_t data_len)
and
Type of a function that libextractor calls for each meta data item found.
cls
closure (user-defined)
plugin_name
name of the plugin that produced this value;
special values can be used (i.e. '<zlib>' for
zlib being used in the main libextractor library
and yielding meta data);
type
libextractor-type describing the meta data;
format basic
format information about data
data_mime_type
mime-type of data (not of the original file);
can be NULL (if mime-type is not known);
data
actual meta-data found
data_len
number of bytes in data
Return 0 to continue extracting, 1 to abort.
So you would just have to write your own function called whatever you want, and have this declaration be like:
int whateveryouwant(void *cls,
const char *plugin_name,
enum EXTRACTOR_MetaType type,
enum EXTRACTOR_MetaFormat format,
const char *data_mime_type,
const char *data,
size_t data_len)
{
// Do your stuff here
if(stop)
return 1; // Stops
else
return 0; // Continues
}
and call it via:
EXTRACTOR_extract (plugins, argv[1],
NULL, 0,
&whateveryouwant,
NULL/* here be dragons */);
Like described in http://www.gnu.org/software/libextractor/manual/libextractor.html#Generalities "3.3 Introduction to the libextractor library"
[here be dragons]: That is a parameter left for the user's use (even if it's redundant to say so). As defined in the doc: "For each meta data item found, GNU libextractor will call the ‘proc’ function, passing ‘proc_cls’ as the first argument to ‘proc’."
Where "the proc function" being the function you added (whateveryouwant() here) and proc_cls being an arbitrary pointer (can be anything) for you to pass data to the function. Like a pointer to stdout in the example, in order to print to stdout. That being said, I suspect that the function writes to a FILE* and not inevitably to stdout; so if you open a file for writing, and pass its "file decriptor" as last EXTRACTOR_extract()'s parameter you would probably end with a file filled with the information you can currently read on your screen. That wouldn't be a proper way to access the information, but if you're looking into a quick and dirty way to test some behavior or some feature; that could do it, until you write a proper function.
Good luck with your code!

Resources