Print out response of Dbus Method Call in C - c

The problem I am having is specifically printing out the response of a dbus method call in C using the low level API. I am new to C's libdbus, but have done some work in python-dbus.
I know how to write dbus methods and method calls in python as well as the CLI
I can find code on the internet to invoke dbus methods, but they don't return or print out the response
I have been looking at the libdbus doxygen api, but cannot determine how to pull out the response.
The way I have my code set up, a python dbus daemon runs with methods I want to call. Some of them return a string. I want a C program to connect to the session bus, call the method, print out the reply and exit.
This is what I have currently:
#include <stdio.h>
#include <dbus/dbus.h>
static void send_dbus_message (DBusConnection *connection, const char *msg)
{
DBusMessage *message;
//initialize the message
message = dbus_message_new_signal ("/org/example/foo/bar",
"org.example.foo.bar",
msg);
//send the message
dbus_connection_send (connection, message, NULL);
//deallocate the message
dbus_message_unref (message);
}
int main (int argc, char **argv)
{
DBusConnection *connection;
DBusError error;
//init error message
dbus_error_init (&error);
connection = dbus_bus_get (DBUS_BUS_SESSION, &error);
if (!connection)
{
printf ("Connection to D-BUS daemon failed: %s", error.message);
//deallocate error message
dbus_error_free (&error);
return 1;
}
send_dbus_message (connection, "HelloWorld");
return 0;
}
Can be synchronous or asynchronous.

You can use the method mentioned in http://www.matthew.ath.cx/misc/dbus to get a method reply message.
Once you have a dbus message you can use following method to extract the data.
To parse a dbus message, you need a argument iterator. Initalize it to read contents of the incoming message.
DBusMessageIter MsgIter;
dbus_message_iter_init(msg, &MsgIter);//msg is pointer to dbus message received
You have to validate the signature of the incoming message before reading it. Or you can also go for argument by argument verification. For example, if the argument type is string
if (DBUS_TYPE_STRING == dbus_message_iter_get_arg_type(&MsgIter)){
char* str = NULL;
dbus_message_iter_get_basic(&MsgIter, &str);//this function is used to read basic dbus types like int, string etc.
}
For complex types, like structures, arrays, variants and dict entries, you have to create corresponding child iterators to parse contents of each complex element. Say, for a dbus signature ofs(i{ii}i)u, the extraction is done as below
//Parsing a signature s(i{ii}i)u
DBusMessageIter rootIter;
dbus_message_iter_init(msg, &rootIter);
if (DBUS_TYPE_STRING == dbus_message_iter_get_arg_type(&rootIter))
{
char* str = NULL;
dbus_message_iter_get_basic(&rootIter, &str);//this function is used to read basic dbus types like int, string etc.
dbus_message_iter_next(&rootIter);//Go to next argument of root iter
//Block to enter and read structure
if (DBUS_TYPE_STRUCT == dbus_message_iter_get_arg_type(&rootIter))
{
DBusMessageIter structIter;
dbus_message_iter_recurse(&rootIter, &structIter);//Initialize iterator for struct
//Argument 1 is int32
if (DBUS_TYPE_INT32 == dbus_message_iter_get_arg_type(&structIter))
{
int a;
dbus_message_iter_get_basic(&structIter, &a);//Read integer
dbus_message_iter_next(&structIter);//Go to next argument of structiter
if (DDBUS_TYPE_DICT_ENTRY == dbus_message_iter_get_arg_type(&structIter))
{
DBusMessageIter dictIter;
dbus_message_iter_recurse(&structIter, &dictIter);//Initialize iterator for dictentry
if (DBUS_TYPE_INT32 == dbus_message_iter_get_arg_type(&dictIter))
{
dbus_message_iter_get_basic(&dictIter, &a);//Read integer
dbus_message_iter_next(&dictIter);//Go to next argument of dictentry
if (DBUS_TYPE_INT32 == dbus_message_iter_get_arg_type(&dictIter))
{
dbus_message_iter_get_basic(&dictIter, &a);//Read integer
}
}
}
dbus_message_iter_next(&structIter);//Go to next argument of structiter
if (DBUS_TYPE_INT32 == dbus_message_iter_get_arg_type(&structIter))
{
dbus_message_iter_get_basic(&structIter, &a);//Read integer
}
}
}
dbus_message_iter_next(&rootIter);//Go to next argument of root iterator
if (DBUS_TYPE_UINT32 == dbus_message_iter_get_arg_type(&rootIter))
{
uint32_t b;
dbus_message_iter_get_basic(&rootIter, &b);//Read integer
}
}
In above code, I used argument by argument signature check. Instead you can do a one time verfication using dbus_message_iter_get_signature. Refer to libdbus api for more info.
#
From your reply I understand that you have problems with connection setup ,
here is a full example, where a method call is invoked on a server and the result is printed
if the first argument is a string.
#
#include <stdio.h>
#include <stdlib.h>
#include <dbus/dbus.h>
#include <assert.h>
DBusConnection* conn = NULL;
//Helper function to setup connection
void vsetupconnection();
//Send method call, Returns NULL on failure, else pointer to reply
DBusMessage* sendMethodCall(const char* objectpath, \
const char* busname, \
const char* interfacename, \
const char* methodname);
#define TEST_BUS_NAME "org.freedesktop.DBus"
#define TEST_OBJ_PATH "/org/freedesktop/DBus"
#define TEST_INTERFACE_NAME "org.freedesktop.DBus.Introspectable"
#define TEST_METHOD_NAME "Introspect"
int main (int argc, char **argv)
{
vsetupconnection();
DBusMessage* reply = sendMethodCall(TEST_OBJ_PATH, TEST_BUS_NAME, TEST_INTERFACE_NAME, TEST_METHOD_NAME);
if(reply != NULL) {
DBusMessageIter MsgIter;
dbus_message_iter_init(reply, &MsgIter);//msg is pointer to dbus message received
if (DBUS_TYPE_STRING == dbus_message_iter_get_arg_type(&MsgIter)){
char* str = NULL;
dbus_message_iter_get_basic(&MsgIter, &str);
printf("Received string: \n %s \n",str);
}
dbus_message_unref(reply);//unref reply
}
dbus_connection_close(conn);
return 0;
}
void vsetupconnection()
{
DBusError err;
// initialise the errors
dbus_error_init(&err);
// connect to session bus
conn = dbus_bus_get(DBUS_BUS_SESSION, &err);
if (dbus_error_is_set(&err)) {
printf("Connection Error (%s)\n", err.message);
dbus_error_free(&err);
}
if (NULL == conn) {
exit(1);
}
else {
printf("Connected to session bus\n");
}
}
DBusMessage* sendMethodCall(const char* objectpath, const char* busname, const char* interfacename, const char* methodname)
{
assert(objectpath != NULL); assert(busname != NULL); assert(interfacename != NULL);
assert(methodname != NULL); assert(conn != NULL);
DBusMessage* methodcall = dbus_message_new_method_call(busname,objectpath, interfacename, methodname);
if (methodcall == NULL) {
printf("Cannot allocate DBus message!\n");
}
//Now do a sync call
DBusPendingCall* pending;
DBusMessage* reply;
if (!dbus_connection_send_with_reply(conn, methodcall, &pending, -1))//Send and expect reply using pending call object
{
printf("failed to send message!\n");
}
dbus_connection_flush(conn);
dbus_message_unref(methodcall);
methodcall = NULL;
dbus_pending_call_block(pending);//Now block on the pending call
reply = dbus_pending_call_steal_reply(pending);//Get the reply message from the queue
dbus_pending_call_unref(pending);//Free pending call handle
assert(reply != NULL);
if(dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
printf("Error : %s",dbus_message_get_error_name(reply));
dbus_message_unref(reply);
reply = NULL;
}
return reply;
}

Related

DBus: Connection was disconnected before a reply was received

I want to send notifications to my window manager on linux through the org.freedesktop.Notifications service. In d-feet this works, but in C, I get the error "Connection was disconnected before a reply was received"
#include <stdio.h>
#include <dbus/dbus.h>
int main() {
DBusError error;
DBusConnection *conn;
dbus_uint32_t serial = 0;
char *app_name = "My App";
dbus_uint32_t replaces_id = 0;
char *app_icon = "";
char *summary = "Notification from My App";
char *body = "This is a test notification from My App.";
char **actions = NULL;
dbus_int32_t timeout = -1;
dbus_uint32_t notification_id = 0;
dbus_error_init(&error);
conn = dbus_bus_get(DBUS_BUS_SESSION, &error);
if (dbus_error_is_set(&error)) {
fprintf(stderr, "Error connecting to the D-Bus session bus: %s\n", error.message);
dbus_error_free(&error);
return 1;
}
DBusMessage *message = dbus_message_new_method_call("org.freedesktop.Notifications",
"/org/freedesktop/Notifications",
"org.freedesktop.Notifications",
"Notify");
DBusMessageIter args, array;
dbus_message_iter_init_append(message, &args);
dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &app_name);
dbus_message_iter_append_basic(&args, DBUS_TYPE_UINT32, &notification_id);
dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &app_icon);
dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &summary);
dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &body);
dbus_message_iter_open_container(&args, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING_AS_STRING, &array);
dbus_message_iter_close_container(&args, &array);
DBusMessageIter dict_entry;
const char *key = "";
dbus_uint32_t value = 0;
dbus_message_iter_open_container(&args, DBUS_TYPE_DICT_ENTRY, NULL, &dict_entry);
dbus_message_iter_append_basic(&dict_entry, DBUS_TYPE_STRING, &key);
DBusMessageIter variant;
dbus_message_iter_open_container(&dict_entry, DBUS_TYPE_VARIANT, DBUS_TYPE_UINT32_AS_STRING, &variant);
dbus_message_iter_append_basic(&variant, DBUS_TYPE_UINT32, &value);
dbus_message_iter_close_container(&dict_entry, &variant);
dbus_message_iter_close_container(&args, &dict_entry);
dbus_message_iter_append_basic(&args, DBUS_TYPE_INT32, &timeout);
DBusPendingCall* pending;
dbus_connection_send_with_reply(conn, message, &pending, DBUS_TIMEOUT_INFINITE);
dbus_connection_flush(conn);
dbus_message_unref(message);
dbus_pending_call_block(pending);
message = dbus_pending_call_steal_reply(pending);
dbus_pending_call_unref(pending);
DBusMessageIter args2;
int arg, id;
if(!dbus_message_iter_init(message, &args2))
fprintf(stderr, "message has no arugments!\n");
else if (DBUS_TYPE_UINT32 != (arg=dbus_message_iter_get_arg_type(&args2))) {
fprintf(stderr, "Argument is not int!\n");
switch(arg){
case DBUS_TYPE_STRING:
char *string;
dbus_message_iter_get_basic(&args2, &string);
fprintf(stderr, "ITS A STRING: %s\n", string);
break;
}}
else {
dbus_message_iter_get_basic(&args2, &id);
printf("ID: %d\n", id);
}
dbus_message_unref(message);
dbus_connection_close(conn);
return 0;
}
Edit: I fixed the segfaults, but now I get a even more obsucure reply from dbus when reading the reply arguments
While this doesn’t directly answer your question, it will help in the long run: You probably don’t want to use dbus-glib or libdbus to connect to D-Bus. Both are old and have poor API designs which make them hard to use. Using a D-Bus binding with a better-designed API will make your code easier to write and maintain in the long run.
See this answer for a comparison of the D-Bus bindings available to you which are easier to use. It is unfortunately quite confusing that there are so many bindings and that some of them are not recommended.

DBus: Watch when name disappears from bus

I am implimenting the StatusNotifierWatcher service using the low-level DBus C library. The StatusNotifierWatcher specification requires that the watcher can know when "A StatusNotifierItem instance has disappeared from the bus" So that it can send the StatusNotifierItemUnregistered signal.
An example implimentation:
#include <stdio.h>
#include <stdlib.h>
#include <dbus/dbus.h>
DBusConnection *conn = NULL;
void item_unregistered_signal(const char *name) {
DBusMessage *signal = dbus_message_new_signal(
"/org/freedesktop/StatusNotifierWatcher",
"org.freedesktop.StatusNotifierWatcher",
"StatusNotifierItemUnregistered");
dbus_message_append_args(signal,
DBUS_TYPE_STRING, &name,
DBUS_TYPE_INVALID);
dbus_connection_send(conn, signal, NULL);
dbus_message_unref(signal);
}
void watch_name(const char *name, void(*cb)(const char *)) {
// Not sure how to impliment
}
dbus_bool_t register_item(DBusConnection *connection, DBusMessage *message, void *_data) {
DBusError error;
char *name;
if (!dbus_message_get_args(message, &error,
DBUS_TYPE_STRING, &name,
DBUS_TYPE_INVALID)) {
fprintf(stderr, "Error parsing method args: %s\n", error.message);
return FALSE;
}
watch_name(name, item_unregistered_signal);
return TRUE;
}
static void check_and_abort(DBusError *error) {
if (dbus_error_is_set(error)) {
fprintf(stderr, "dbus_err: %s\n", error->message);
exit(EXIT_FAILURE);
}
}
int main() {
DBusError error;
dbus_error_init(&error);
conn = dbus_bus_get(DBUS_BUS_SESSION, &error);
check_and_abort(&error);
dbus_bus_request_name(conn, "org.freedesktop.StatusNotifierWatcher",
DBUS_NAME_FLAG_REPLACE_EXISTING,
&error);
check_and_abort(&error);
dbus_connection_add_filter(conn, register_item, NULL, free);
while(1) {
dbus_connection_read_write_dispatch(conn, 1000);
}
}
If I have the well-known name to a DBus service, how do I know when the name disappears from the bus?
Well, I figured this out and I'll post an answer for any future poor souls who need to work with libdbus.
org.freedesktop.DBus sends the NameOwnerChanged signal whenever any DBus name changes. One can use this signal to track if an item has disappeared because the NewOwner argument is a null string.
This function can do that:
static DBusHandlerResult signal_handler(DBusConnection *connection,
DBusMessage *message, void *_usr_data) {
if (dbus_message_is_signal(message, "org.freedesktop.DBus",
"NameOwnerChanged")) {
const char *name;
const char *old_owner;
const char *new_owner;
if (!dbus_message_get_args(message, NULL,
DBUS_TYPE_STRING, &name,
DBUS_TYPE_STRING, &old_owner,
DBUS_TYPE_STRING, &new_owner,
DBUS_TYPE_INVALID)) {
fprintf(stderr, "Error getting OwnerChanged args");
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
if (strcmp(name, "") != 0) {
// Name not lost, just swapped owners
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
name_lost(name);
return DBUS_HANDLER_RESULT_HANDLED;
}
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
One also needs to add a match so that your program will be called with this signal. I added this in main()
dbus_bus_add_match(conn,
"type='signal',\
sender='org.freedesktop.DBus',\
interface='org.freedesktop.DBus',\
member='NameOwnerChanged'",
&error);
check_and_abort(&error);
dbus_connection_add_filter(conn, signal_handler, NULL, free);
For those using GDBus (recommended) instead of libdbus (discouraged), the equivalent is g_bus_watch_name().

Segfault on Server after Multithreading in C

So I'm trying to code a multi-threading server. I've spent an enormous time on the internet figuring out the correct way to do this and the answer as always seems to be it depends. Whenever I execute my code, the client successfully connects, and executes but when the thread terminates and returns to the while loop the whole program segfaults.
I probably could use a good spanking on a few other things as well such as my usage of global variables. The entirety of code is below, sorry for the inconsistent space/tabbing.
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdbool.h>
#include <signal.h>
#include <math.h>
#include <pthread.h>
#include <sys/stat.h>
#include <fcntl.h>
/* ---------------------------------------------------------------------
This is a basic whiteboard server. You can query it, append to it and
clear in it. It understands both encrypted and unencrypted data.
--------------------------------------------------------------------- */
struct whiteboard {
int line;
char type;
int bytes;
char string[1024];
} *Server;
int serverSize, threadcount, id[5];
bool debug = true;
struct whiteboard *Server;
pthread_mutex_t mutex;
pthread_t thread[5];
/* -------------------------------------------
function: sigint_handler
Opens a file "whiteboard.all" in writemode
and writes all white board information in
command mode.
------------------------------------------- */
void sigint_handler(int sig)
{
if (debug) printf("\nInduced SIGINT.\n");
FILE *fp;
fp=fopen("whiteboard.all","w");
int x=0;
for (x;x<serverSize;x++) // Loop Responsible for iterating all the whiteboard entries.
{
if (debug) printf("#%d%c%d\n%s\n",Server[x].line,Server[x].type,Server[x].bytes,Server[x].string);
fprintf(fp,"#%d%c%d\n%s\n",Server[x].line,Server[x].type,Server[x].bytes,Server[x].string);
}
if (debug) printf("All values stored.\n");
free(Server); // Free dynamically allocated memory
exit(1);
}
/* -------------------------------------------
function: processMessage
Parses '!' messages into their parts -
returns struct in response.
------------------------------------------- */
struct whiteboard processMessage(char * message)
{
int lineNumber, numBytes;
char stringType, entry[1028];
if (debug) printf("Update Statement!\n");
// Read line sent by Socket
sscanf(message,"%*c%d%c%d\n%[^\n]s",&lineNumber,&stringType,&numBytes,entry);
if (debug) printf("Processed: Line: %d, Text: %s\n",lineNumber,entry);
// Parse information into local Struct
struct whiteboard Server;
Server.line = lineNumber;
Server.type = stringType;
Server.bytes = numBytes;
strcpy(Server.string,entry);
// If there is no bytes, give nothing
if (numBytes == 0)
{
strcpy(Server.string,"");
}
return Server;
}
/* -------------------------------------------
function: handleEverything
Determines type of message recieved and
process and parses accordingly.
------------------------------------------- */
char * handleEverything(char* message, struct whiteboard *Server, char* newMessage)
{
bool updateFlag = false, queryFlag = false;
// If message is an Entry
if (message[0] == '#')
{
if (debug) printf("Triggered Entry!\n");
// Create Temporary Struct
struct whiteboard messageReturn;
messageReturn = processMessage(message);
// Store Temporary Struct in Correct Heap Struct
Server[messageReturn.line] = messageReturn;
sprintf(newMessage,"!%d%c%d\n%s\n",messageReturn.line, messageReturn.type, messageReturn.bytes, messageReturn.string);
return newMessage;
}
// If message is a query
if (message[0] == '?')
{
if (debug) printf("Triggered Query!\n");
int x;
queryFlag = true;
sscanf(message,"%*c%d",&x); // Parse Query
if (x > serverSize) // Check if Query out of Range
{
strcpy(newMessage,"ERROR: Query out of Range.\n");
return newMessage;
}
sprintf(newMessage,"!%d%c%d\n%s\n",Server[x].line,Server[x].type,Server[x].bytes,Server[x].string);
if (debug) printf("newMessage as of handleEverything:%s\n",newMessage);
return newMessage;
}
}
/* -------------------------------------------
function: readFile
If argument -f given, read file
process and parse into heap memory.
------------------------------------------- */
void readFile(char * filename)
{
FILE *fp;
fp=fopen(filename,"r");
int line, bytes, count = 0, totalSize = 0;
char type, check, string[1028], individualLine[1028];
// Loop to determine size of file. **I know this is sloppy.
while (fgets(individualLine, sizeof(individualLine), fp))
{
totalSize++;
}
// Each line shoud have totalSize - 2 (to account for 0)
// (answer) / 2 to account for string line and instruction.
totalSize = (totalSize - 2) / 2;
serverSize = totalSize+1;
if (debug) printf("Total Size is: %d\n",serverSize);
// Open and Allocate Memory
fp=fopen(filename,"r");
if (debug) printf("File Mode Calloc Initialize\n");
Server = calloc(serverSize+2, sizeof(*Server));
// Write to Heap Loop
while (fgets(individualLine, sizeof(individualLine), fp)) {
if (individualLine[0] == '#') // Case of Header Line
{
sscanf(individualLine,"%c%d%c%d",&check,&line,&type,&bytes);
if (debug) printf("Count: %d, Check:%c, Line:%d, Type: %c, Bytes:%d \n",count,check,line,type,bytes);
Server[count].line = line;
Server[count].type = type;
Server[count].bytes = bytes;
count++;
}
else
{
// For case of no data
if (individualLine[0] == '\n')
{
strcpy(string,"");
}
// Then scan data line
sscanf(individualLine,"%[^\n]s",string);
if (debug) printf("String: %s\n",string);
strcpy(Server[count-1].string,string);
}
}
return;
}
void *threadFunction(int snew)
{
char tempmessage[1024], message[2048];
// Compile and Send Server Message
strcpy(tempmessage, "CMPUT379 Whiteboard Server v0\n");
send(snew, tempmessage, sizeof(tempmessage), 0);
// Recieve Message
char n = recv(snew, message, sizeof(message), 0);
pthread_mutex_lock(&mutex);
if (debug) printf("Attempt to Malloc for newMessage\n");
char * newMessage = malloc(1024 * sizeof(char));
if (debug) printf("goto: handleEverything\n");
newMessage = handleEverything(message, Server, newMessage);
if (debug) printf("returnMessage:%s\n",newMessage);
strcpy(message,newMessage);
free(newMessage);
pthread_mutex_unlock(&mutex);
if (debug) printf("message = %s\n", message);
send(snew, message, sizeof(message), 0);
printf("End of threadFunction\n");
return;
}
/* -------------------------------------------
function: main
Function Body of Server
------------------------------------------- */
int main(int argc, char * argv[])
{
int sock, fromlength, outnum, i, socketNumber, snew;
bool cleanMode;
// Initialize Signal Handling
struct sigaction act;
act.sa_handler = sigint_handler;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
sigaction(SIGINT, &act, 0);
// For correct number of arguments.
if (argc == 4)
{
// If "-n" parameter (cleanMode)
if (strcmp(argv[2], "-n") == 0)
{
// Get size + 1
cleanMode = true;
sscanf(argv[3],"%d",&serverSize);
serverSize += 1;
if (debug) printf("== Clean Mode Properly Initiated == \n");
if (debug) printf("serverSize: %d\n",serverSize);
if (debug) printf("Clean Mode Calloc\n");
Server = calloc(serverSize, sizeof(*Server));
int i = 0;
for (i; i < serverSize; i++) // Initialize allocated Memory
{
Server[i].line = i;
Server[i].type = 'p';
Server[i].bytes = 0;
strcpy(Server[i].string,"");
}
}
// If "-f" parameter (filemode)
else if (strcmp(argv[2], "-f") == 0)
{
// Read File
cleanMode = false;
readFile(argv[3]);
if (debug) printf("== Statefile Mode Properly Initiated == \n");
if (debug) printf("serverSize: %d\n",serverSize);
}
// Otherwise incorrect parameter.
else
{
printf("Incorrect Argument. \n");
printf("Usage: wbs279 pornumber {-n number | -f statefile}\n");
exit(1);
}
sscanf(argv[1],"%d",&socketNumber);
}
// Send Error for Incorrect Number of Arguments
if (argc != 4)
{
printf("Error: Incorrect Number of Input Arguments.\n");
printf("Usage: wbs279 portnumber {-n number | -f statefile}\n");
exit(1);
}
// == Do socket stuff ==
char tempmessage[1024], message[2048];
struct sockaddr_in master, from;
if (debug) printf("Assrt Socket\n");
sock = socket (AF_INET, SOCK_STREAM, 0);
if (sock < 0)
{
perror ("Server: cannot open master socket");
exit (1);
}
master.sin_family = AF_INET;
master.sin_addr.s_addr = INADDR_ANY;
master.sin_port = htons (socketNumber);
if (bind (sock, (struct sockaddr*) &master, sizeof (master)))
{
perror ("Server: cannot bind master socket");
exit (1);
}
// == Done socket stuff ==
listen (sock, 5);
int threadNumber = 0;
while(1)
{
printf("But what about now.\n");
if (debug) printf("-- Wait for Input --\n");
printf("Enie, ");
fromlength = sizeof (from);
printf("Meanie, ");
snew = accept (sock, (struct sockaddr*) & from, & fromlength);
printf("Miney, ");
if (snew < 0)
{
perror ("Server: accept failed");
exit (1);
}
printf("Moe\n");
pthread_create(&thread[threadNumber],NULL,threadFunction(snew), &id[threadNumber]);
//printf("Can I join?!\n");
//pthread_join(thread[0],NULL);
//printf("Joined?!\n");
threadNumber++;
close (snew);
}
}
I'm also curious as to how exactly to let multiple clients use the server at once. Is how I've allocated the whiteboard structure data appropriate for this process?
I'm very sorry if these don't make any sense.
You seem to somehow expect this:
pthread_create(&thread[threadNumber],NULL,threadFunction(snew), &id[threadNumber]);
/* ... */
close (snew);
To make sense, while it clearly doesn't.
Instead of starting a thread that runs threadFunction, passing it snew, you call the thread function and pass the return value to pthread_create(), which will interpret it as a function pointer. This will break, especially considering that the thread function incorrectly ends with:
return;
This shouldn't compile, since it's declared to return void *.
Also assuming you managed to start the thread, passing it snew to use as its socket: then you immediately close that socket, causing any reference to it from the thread to be invalid!
Please note that pthread_create() does not block and wait for the thread to exit, that would be kind of ... pointless. It starts off the new thread to run in parallel with the main thread, so of course you can't yank the carpet away from under it.
This signal handler is completely unsafe:
void sigint_handler(int sig)
{
if (debug) printf("\nInduced SIGINT.\n");
FILE *fp;
fp=fopen("whiteboard.all","w");
int x=0;
for (x;x<serverSize;x++) // Loop Responsible for iterating all the whiteboard entries.
{
if (debug) printf("#%d%c%d\n%s\n",Server[x].line,Server[x].type,Server[x].bytes,Server[x].string);
fprintf(fp,"#%d%c%d\n%s\n",Server[x].line,Server[x].type,Server[x].bytes,Server[x].string);
}
if (debug) printf("All values stored.\n");
free(Server); // Free dynamically allocated memory
exit(1);
}
Per 2.4.3 Signal Actions of the POSIX standard (emphasis added):
The following table defines a set of functions that shall be
async-signal-safe. Therefore, applications can call them, without
restriction, from signal-catching functions. ...
[list of async-signal-safe functions]
Any function not in the above table may be unsafe with respect to signals. Implementations may make other interfaces
async-signal-safe. In the presence of signals, all functions defined
by this volume of POSIX.1-2008 shall behave as defined when called
from or interrupted by a signal-catching function, with the exception
that when a signal interrupts an unsafe function or equivalent
(such as the processing equivalent to exit() performed after a return
from the initial call to main()) and the signal-catching function
calls an unsafe function, the behavior is undefined. Additional
exceptions are specified in the descriptions of individual functions
such as longjmp().
Your signal handler invokes undefined behavior.

D-BUS in BeagleBone Black

My goal: Is to monitor the state of my network interface (mainly wireless) from my firmware (in C) by monitoring the wpa_supplicant through the D-Bus interfaces. I would like to stick with C and low-level API of D-bus.
What I have so far
I've written a small program in C, copied most of the code as is from this SO user.
I've gone through all possible tutorials on D-Bus and wpa_supplicant
My program compiles and works properly. However it does not produce the expected output.
Here's my code:
#include <stdio.h>
#include <dbus/dbus.h>
#define WPAS_DBUS_SERVICE "fi.epitest.hostap.WPASupplicant"
#define WPAS_DBUS_PATH "/fi/epitest/hostap/WPASupplicant"
#define WPAS_DBUS_INTERFACE "fi.epitest.hostap.WPASupplicantAAA"
#define WPAS_DBUS_PATH_INTERFACES WPAS_DBUS_PATH "/Interfaces"
#define WPAS_DBUS_IFACE_INTERFACE WPAS_DBUS_INTERFACE ".Interfaces"
#define WPAS_DBUS_NETWORKS_PART "Networks"
#define WPAS_DBUS_IFACE_NETWORK WPAS_DBUS_INTERFACE ".Network"
#define WPAS_DBUS_BSSIDS_PART "BSSIDs"
#define WPAS_DBUS_IFACE_BSSID WPAS_DBUS_INTERFACE ".BSSID"
int ret;
char signalDesc[1024]; // Signal description as string
// Signal handling
signal(SIGKILL, stopLoop);
signal(SIGTERM, stopLoop);
void loop(DBusConnection* conn)
{
DBusMessage* msg;
DBusMessageIter args;
DBusMessageIter subArgs;
int argType;
int i;
int buffSize = 1024;
char strValue[buffSize];
const char* member = 0;
while (1)
{
// non blocking read of the next available message
dbus_connection_read_write(conn, 0);
msg = dbus_connection_pop_message(conn);
// loop again if we haven't read a message
if (!msg)
{
printf("No message received, waiting a little ...\n");
sleep(1);
continue;
}
else printf("Got a message, will analyze it ...\n");
// Print the message member
printf("Got message for interface %s\n",
dbus_message_get_interface(msg));
member = dbus_message_get_member(msg);
if(member) printf("Got message member %s\n", member);
// Check has argument
if (!dbus_message_iter_init(msg, &args))
{
printf("Message has no argument\n");
continue;
}
else
{
// Go through arguments
while(1)
{
argType = dbus_message_iter_get_arg_type(&args);
if (argType == DBUS_TYPE_STRING)
{
printf("Got string argument, extracting ...\n");
char* str = NULL;
dbus_message_iter_get_basic(&args, &str);
printf("Received string: \n %s \n",str);
}
else
printf("Arg type not implemented yet !\n");
if(dbus_message_iter_has_next(&args))
dbus_message_iter_next(&args);
else break;
}
printf("No more arguments!\n");
}
// free the message
dbus_message_unref(msg);
}
}
int main()
{
DBusConnection *connection;
DBusError error;
char *name = "org.share.linux";
dbus_error_init(&error);
connection = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
if ( dbus_error_is_set(&error) )
{
printf("Error connecting to the daemon bus: %s",error.message);
dbus_error_free(&error);
return 1;
}
// request a name on the bus
ret = dbus_bus_request_name(connection, WPAS_DBUS_SERVICE, 0, &error);
if (dbus_error_is_set(&error))
{
printf(stderr, "Name Error (%s)\n", error.message);
dbus_error_free(&error);
}
/* Connect to signal */
// Interface signal ..
printf(signalDesc, "type='signal',interface='%s'",WPAS_DBUS_IFACE_INTERFACE);
dbus_bus_add_match(connection, signalDesc, &error);
dbus_connection_flush(connection);
if (dbus_error_is_set(&error))
{
fprintf(stderr, "Match Error (%s)\n", error.message);
return 1;
}
// Do main loop
loop(connection);
dbus_connection_close(connection);
return 0;
}
List of D-bus services on my BBB
Output
Some pointers
I would like to catch the signals as shown in the D-Bus API of wpa_supplicant.
Some things I would like to do -- see when a wireless interface say wlan0 is enabled, connects to access point etc. Also capability to set AP and stuff.
Its catching signal from other interfaces for which no match has been added.
I run this program and change the state of the networking interfaces but I dont get any signals. Also, I dont know if requesting name on the bus is necessary as I'm just listening.
What's the possible issue here? Any pointers will be really helpful.

Sending protobuf-c data via zeromq

I have client and server code communicating with each other using protobuf-c over 0mq
below is the client cod snipped
void *context = zmq_ctx_new ();
void *requester = zmq_socket (context, ZMQ_REQ);
char collector[100];
char buffer[MAX_MSG];
sprintf(collector,"tcp://%s:%s",argv[2],argv[3]);
zmq_connect (requester, collector);
LogMsg proto_msg = LOG_MSG__INIT;
void *buf; // Buffer to store serialized data
unsigned len; // Length of serialized data
proto_msg.name=argv[1];//assigning arg1 the node name
proto_msg.ip="127.0.0.1"; //TODO get IP im connected to
proto_msg.pid=getpid();
proto_msg.has_pid = 1;
//sending Hello to Collector to register
proto_msg.level = "HELLO";
len = log_msg__get_packed_size (&proto_msg);
buf = malloc (len);
log_msg__pack (&proto_msg, buf);
printf("Writing %d serialized bytes to socket: Handshaking with Collector\n",len); // See the length of message
zmq_send(requester, buf,len, 0);
on the Server side i have the following code
#include "generator.h"
int main (void)
{
// Socket to talk to clients
void *context = zmq_ctx_new ();
void *responder = zmq_socket (context, ZMQ_REP);
int rc = zmq_bind (responder, "tcp://*:5555");
uint8_t buffer[MAX_MSG];
int i=0;
assert (rc == 0);
zmq_recv (responder, buffer, MAX_MSG, 0);
printf ("recieved -> %s\n",buffer);
LogMsg *ptr_msg;
ptr_msg = log_msg__unpack(NULL,i,buffer); // Deserialize the serialized input
if (ptr_msg == NULL)
{ // Something failed
fprintf(stderr,"error unpacking incoming message\n");
return 1;
}
log_msg__free_unpacked(ptr_msg,NULL);
return 0;
}
But when the server receives the message it is giving the following error
recieved ->
B1 127.0.0.1??"HELLO/??
message 'Log_msg': missing required field 'name'
For reference .proto file is as below
message Log_msg
{
required string name=1; //Node Name
optional string IP=2 [default = "127.0.0.1"]; //Node IP Addr
optional int32 PID=3 [default = 9999]; //Process ID
optional string level=4 [default = "INFO"]; //Log Info Level
optional int64 datim=5; //UNIX Time Stamp
optional string msg=6; //Log message
}
I assume when i am transmitting it on wire then it gets corrupted. Any ideas how i can send it properly. Examples online show this for c++. I need for C.
zmq_send and zmq_recv seems to handle zmq_msg_t structures rather than just the buffer.
Maybe you should try to create such structures rather than just sending your buffer ?
See the examples in http://api.zeromq.org/2-1:zmq-send and http://api.zeromq.org/2-1:zmq-recv

Resources