I have such websocket implementation and it worked before but now it doesn't because I upgraded library version.
int Handle(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) {
switch( reason ) {
case LWS_CALLBACK_CLOSED: {
lwsl_notice("Client Disconnected\n");
break;
}
case LWS_CALLBACK_ESTABLISHED: {
lwsl_notice("Client Connected\n");
break;
}
case LWS_CALLBACK_RECEIVE: {
lwsl_notice("Message: %s\n", in);
break;
}
default:
break;
}
return 0;
}
static struct lws_protocols protocols[] =
{
{
"server",
Handle,
sizeof(struct Session),
LWS_MESSAGE_CHUNK_SIZE,
},
{ NULL, NULL, 0, 0 }
};
int Start() {
struct lws_context_creation_info info;
memset( &info, 0, sizeof(info) );
info.port = 3018;
info.protocols = protocols;
info.gid = -1;
info.uid = -1;
struct lws_context *context = lws_create_context( &info );
while( 1 ) {
lws_service( context, 1000000 );
}
lws_context_destroy( context );
}
The problem is that data coming with some noise at the end.
If I send from one end {} I receive on another end {}/S4T1u3F2O1AA82K7Kg=. So *in contains this noise after actual message string.
How I can properly receive the data?
I tried different examples but they looks overcomplicated.
I was managed to copy right amount of data to the string.
My solution:
char data[len];
memcpy(data, in, len);
data[len] = '\0';
Below is my source code, I am trying to store sensor information on linked list.
Sensor information is received by type of JSON. And, I confirmed that it is well parsed.
However, when i am trying to store received value, then "Segmentation fault
" error is occurred.
I think it is because of usage of double pointer of struct.
How can i solve this?
//sensor
if (!strcmp(key, "sensor") && (num_sen > 0))
{
#if DEBUG
fprintf(stderr, "\n********************SENSORINFO********************\n");
#endif
SENSOR_CONFIG **p_sen = NULL;
p_sen = mcfg->sensor_cfg;
SENSOR_CONFIG ** firstnode = NULL;//첫번째 노드
SENSOR_CONFIG ** lastnode = NULL;//마지막 노드
if (num_sen > 0)
{
for (int i = 1; i < num_sen; i++)
{
json_t * arr_data, *obj2, *arr2;
const char * key2;
int k;
json_array_foreach(obj, i, arr) {
//각 센서 array 시작
json_object_foreach(arr, key2, obj2) {
p_sen = (SENSOR_CONFIG **)malloc(sizeof(SENSOR_CONFIG));//먼저 생성하고 보자
arr_data = json_object_get(arr, key2);
if (_eq("id"))
{
fprintf(stderr, "can read id\n");
(*p_sen)->id = (int)json_integer_value(arr_data);
fprintf(stderr, "id:");
fprintf(stderr, "%d\n", (*p_sen)->id);
}
...
}
(*p_sen)->next = NULL;
if (firstnode == NULL) {//처음으로 실행되면
firstnode = p_sen;
lastnode = p_sen;
}
else {//처음이 아니면 뒤에 계속 추가. lastnode가 계속 바뀐다
(*lastnode)->next = p_sen;//원래 lastnode가 가리키는 곳이 새로 생성된 노드의 값을 가리키게 한 후,
lastnode = p_sen;//방금 생성한 노드가 맨 끝자리에 추가했으므로 방금 생성한 노드가 lastnode가 된다.
}
}//sensor array
}
}
else
{
mcfg->sensor_cfg = NULL;
}
}
I'm developing an application written in C to communicate with an API web server using libcurl. I parsed successfully some JSON responses but I failed to parse this one (the simplest one).
- Code
void auth_parser(char* serverResponse,struct ParsedAuthResponse *responseP)
{
char* json_text;
json_t *root;
json_error_t error;
const char* error_text=NULL;
const char* message_text=NULL;
json_text=malloc(strlen(serverResponse)+strlen("[]")+1);
if (!json_text)
{
printf( "not enough memory\n");
return ;
}
strcpy(json_text,"[");
json_text=strcat(json_text,serverResponse);
json_text=strcat(json_text,"]");
root = json_loads(json_text, 0, &error);
SCM_FREE(json_text);
if(!json_is_array(root))
{
printf( "error: on line %d: %s\n", error.line, error.text);
return;
}
json_t *error_obj,*message_obj;
data = json_array_get(root, 0);
if(!json_is_object(data))
{
printf("error1 \n");
json_decref(root);
}
else
{
printf("OK1 \n");
}
error_obj= json_object_get(data, "error");
if(error_obj)
{
if(!json_is_string(error_obj))
{
printf( "error2 \n");
json_decref(root);
}
else
{
error_text=json_string_value(error_obj);
printf("error_text=%s",error_text);
}
message_obj=json_object_get(data, "message");
if(!json_is_string(message_obj))
{
printf( "error3 \n");
json_decref(root);
}
else
{
message_text=json_string_value(message_obj);
printf("message_text=%s",message_text);
printf("OK3 \n");
}
}
return;
}
This is the JSON object to parse :
{"error":4,"message":"Authentication Failed - You do not have
permissions to access the service"}
It fails at error2
You are checking if the value of the error key is a string and it is failing because it is an integer.
Try replacing :
if(!json_is_string(error_obj))
with
if(!json_is_integer(error_obj))
I have the following code:
typedef struct my_data {
char* name;
}my_data;
my_data data[]={
{ .name = "Peter" },
{ .name = "James" },
{ .name = "John" },
{ .name = "Mike" }
};
void loaddata()
{
FILE * in;
if((in = fopen("data.txt","rt")) != NULL) {
printf("start loading\n");
int i = 0;
while(!feof(in))
{
fscanf(in,"%s", &data[i].name);
printf("%s\n",data[i].name);
i++;
};
}
else
printf("loading not required\n");
fclose(in);
}
And it gives me a "killed" error.
How can I load data from file data.txt into existing structure and in case file doesn't exist to use default values which were defined ?
No need "&" in:
fscanf(in,"%s", &data[i].name);
and no need to close filestream if it's not opened.
void loaddata()
{
FILE * in;
if((in = fopen("data.txt","rt")) != NULL) {
printf("start loading\n");
int i = 0;
while(!feof(in))
{
fscanf(in,"%s", data[i].name);
printf("%s\n",data[i].name);
i++;
};
fclose(in); /* need closing */
}
else
printf("loading not required\n");
/* no need closing */
}
UPD: create structure with allocated memory, not pointer. Pointer accesses part of program, not memory, so you cannot save data there.
typedef struct my_data {
char name[10];
}my_data;
I have managed to parse ok. But now I am having trouble getting the values
that I need. I can get the element and the attributes. But cannot get the values.
I would like to get the value of frame in this xml it is 20.
/* track the current level in the xml tree */
static int depth = 0;
/* first when start element is encountered */
void start_element(void *data, const char *element, const char **attribute)
{
int i;
for(i = 0; i < depth; i++)
{
printf(" ");
}
printf("%s", element);
for(i = 0; attribute[i]; i += 2)
{
printf(" %s= '%s'", attribute[i], attribute[i + 1]);
}
printf("\n");
depth++;
}
/* decrement the current level of the tree */
void end_element(void *data, const char *el)
{
depth--;
}
int parse_xml(char *buff, size_t buff_size)
{
FILE *fp;
fp = fopen("start_indication.xml", "r");
if(fp == NULL)
{
printf("Failed to open file\n");
return 1;
}
XML_Parser parser = XML_ParserCreate(NULL);
int done;
XML_SetElementHandler(parser, start_element, end_element);
memset(buff, 0, buff_size);
printf("strlen(buff) before parsing: %d\n", strlen(buff));
size_t file_size = 0;
file_size = fread(buff, sizeof(char), buff_size, fp);
/* parse the xml */
if(XML_Parse(parser, buff, strlen(buff), XML_TRUE) == XML_STATUS_ERROR)
{
printf("Error: %s\n", XML_ErrorString(XML_GetErrorCode(parser)));
}
fclose(fp);
XML_ParserFree(parser);
return 0;
}
<data>
<header length="4">
<item name="time" type="time">16</item>
<item name="ref" type="string">3843747</item>
<item name="port" type="int16">0</item>
<item name="frame" type="int16">20</item>
</header>
</data>
Output from parsing
Element: data
Element: header length= '4'
Element: item name= 'time' type= 'time'
Element: item name= 'ref' type= 'string'
Element: item name= 'port' type= 'int16'
Element: item name= 'frame' type= 'int16'
It is quite difficult with expat. expat is better when you are only interested with the structure, not the content of the elements. Why not using libxml instead? What are your reasons for using an even-based parser like expat, rather than a tree-based one?
Anyway, the way to do it is to set a character data handler. Here is an example, based on your code:
#include <expat.h>
#include <stdio.h>
#include <string.h>
#define BUFFER_SIZE 100000
/* track the current level in the xml tree */
static int depth = 0;
static char *last_content;
/* first when start element is encountered */
void
start_element(void *data, const char *element, const char **attribute)
{
int i;
for (i = 0; i < depth; i++) {
printf(" ");
}
printf("%s", element);
for (i = 0; attribute[i]; i += 2) {
printf(" %s= '%s'", attribute[i], attribute[i + 1]);
}
printf("\n");
depth++;
}
/* decrement the current level of the tree */
void
end_element(void *data, const char *el)
{
int i;
for (i = 0; i < depth; i++) {
printf(" ");
}
printf("Content of element %s was \"%s\"\n", el, last_content);
depth--;
}
void
handle_data(void *data, const char *content, int length)
{
char *tmp = malloc(length);
strncpy(tmp, content, length);
tmp[length] = '\0';
data = (void *) tmp;
last_content = tmp; /* TODO: concatenate the text nodes? */
}
int
parse_xml(char *buff, size_t buff_size)
{
FILE *fp;
fp = fopen("start_indication.xml", "r");
if (fp == NULL) {
printf("Failed to open file\n");
return 1;
}
XML_Parser parser = XML_ParserCreate(NULL);
XML_SetElementHandler(parser, start_element, end_element);
XML_SetCharacterDataHandler(parser, handle_data);
memset(buff, 0, buff_size);
printf("strlen(buff) before parsing: %d\n", strlen(buff));
size_t file_size = 0;
file_size = fread(buff, sizeof(char), buff_size, fp);
/* parse the xml */
if (XML_Parse(parser, buff, strlen(buff), XML_TRUE) == XML_STATUS_ERROR) {
printf("Error: %s\n", XML_ErrorString(XML_GetErrorCode(parser)));
}
fclose(fp);
XML_ParserFree(parser);
return 0;
}
int
main(int argc, char **argv)
{
int result;
char buffer[BUFFER_SIZE];
result = parse_xml(buffer, BUFFER_SIZE);
printf("Result is %i\n", result);
return 0;
}
The 'value' 20 is the character data "20" in the element whose tagname is "item" and whose name attribute is "frame".
To receive character data events, register a callback with the XML_SetCharacterDataHandler function.
This callback will receive the character data. The parser may split character data - typically to handle reaching the end of a buffer, or for entities (so for foo&bar your handler will get three calls - "foo", "&" and "bar"), so you have to paste the string parts together again if you need the whole of the data.
You know when you have all the character data inside a node when you receive the next element start or close callback.
When you have all the character data, you can process it.
A stand-alone example simplified from your code:
#include <expat.h>
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
static const char* xml =
"<data>\n"\
" <header length=\"4\">\n"\
" <item name=\"time\" type=\"time\">16</item>\n"\
" <item name=\"ref\" type=\"string\">3843747</item>\n"\
" <item name=\"port\" type=\"int16\">0</item>\n"\
" <item name=\"frame\" type=\"int16\">20</item>\n"\
" </header>\n"\
"</data>\n";
void reset_char_data_buffer ();
void process_char_data_buffer ();
static bool grab_next_value;
void start_element(void *data, const char *element, const char **attribute) {
process_char_data_buffer();
reset_char_data_buffer();
if ( strcmp("item", element) == 0 ) {
size_t matched = 0;
for (size_t i = 0; attribute[i]; i += 2) {
if ( ( strcmp("name", attribute[i]) == 0 ) && ( strcmp("frame", attribute[i+1]) == 0 ) )
++matched;
if ( ( strcmp("type", attribute[i]) == 0 ) && ( strcmp("int16", attribute[i+1]) == 0 ) )
++matched;
}
if (matched == 2) {
printf("this is the element you are looking for\n");
grab_next_value = true;
}
}
}
void end_element(void *data, const char *el) {
process_char_data_buffer();
reset_char_data_buffer();
}
static char char_data_buffer[1024];
static size_t offs;
static bool overflow;
void reset_char_data_buffer (void) {
offs = 0;
overflow = false;
grab_next_value = false;
}
// pastes parts of the node together
void char_data (void *userData, const XML_Char *s, int len) {
if (!overflow) {
if (len + offs >= sizeof(char_data_buffer) ) {
overflow = true;
} else {
memcpy(char_data_buffer + offs, s, len);
offs += len;
}
}
}
// if the element is the one we're after, convert the character data to
// an integer value
void process_char_data_buffer (void) {
if (offs > 0) {
char_data_buffer[ offs ] = '\0';
printf("character data: %s\n", char_data_buffer);
if ( grab_next_value ) {
int value = atoi( char_data_buffer );
printf("the value is %d\n", value);
}
}
}
int main (void ) {
XML_Parser parser = XML_ParserCreate(NULL);
XML_SetElementHandler(parser, start_element, end_element);
XML_SetCharacterDataHandler(parser, char_data);
reset_char_data_buffer();
if (XML_Parse(parser, xml, strlen(xml), XML_TRUE) == XML_STATUS_ERROR)
printf("Error: %s\n", XML_ErrorString(XML_GetErrorCode(parser)));
XML_ParserFree(parser);
return 0;
}