I am writing a C program using GTK+ on a raspberry pi.
There is a device coupled to it via the Ethernet port (all UDP communication).
This device sends a heartbeat to the pi , which I'm able to receive.
Now I need to send something back to the device. Therefore I need to know its IP address.
I want my program to autodetect the IP address from the message, but I have no clue how to get it.
Here is the code to setup the socket:
gd->gXctlServer = G_SOCKET_ADDRESS(g_inet_socket_address_new(g_inet_address_new_any(G_SOCKET_FAMILY_IPV4),XCTLPORT));
gd->gXctlSocket = g_socket_new(G_SOCKET_FAMILY_IPV4,G_SOCKET_TYPE_DATAGRAM,G_SOCKET_PROTOCOL_UDP,&err);
if (gd->gXctlSocket == NULL)
{
g_print("Error creating Xctl socket: %s\n",err->message);
g_assert(err == NULL);
}
if (g_socket_bind(gd->gXctlSocket,gd->gXctlServer,TRUE,&err) == FALSE)
{
g_print("Error binding Xctl socket:%s\n",err->message);
g_assert(err == NULL);
}
// add receiver watch for Xctl messages:
gd->xctlChannel = g_io_channel_unix_new(g_socket_get_fd(gd->gXctlSocket));
// set channel encoding to NULL for binary data:
g_io_channel_set_encoding(gd->xctlChannel,NULL,&err);
if (err != NULL) g_print("error setting encoding: %s\n",err->message);
gd->xctlRrcvEvent = g_io_add_watch(gd->xctlChannel,G_IO_IN,(GIOFunc) xctlreceiver, NULL);
g_io_channel_unref(gd->xctlChannel);
gd is a pointer to some global data, among which the server, socket and channel
Here is the code of my listener:
// this function listens to all Xctl messages
static gboolean xctlreceiver(GIOChannel *channel, GIOCondition condition, gpointer data)
{
char buf[1024];
gsize read;
GError *err = NULL;
g_print("xctlreceiver\n");
if (condition & G_IO_HUP) return FALSE;
g_io_channel_read_chars(channel,buf,sizeof(buf),&read,&err);
if (err != NULL) g_print("error receiving xctl: %s\n",err->message);
g_print("received %d bytes\n",read);
if (isXtouchHeartbeat(buf,read))
{
g_print("received heartbeat from X-touch\n");
}
return TRUE;
}
The receiver is working and indicates that the heartbeat is received.
But the question is: How do I get the IP address of the device that sent me the heartbeat.
Can someone please help me out here?
Thanks,
Bart.
EDIT: The solution may be simpler than I thought.
Maybe I do not need to know the IP address of the sender. If I use the function g_io_channel_write_chars and I use the same channel as in the g_io_channel_read_chars function, it might work.
I will try this and will come back to it later.
I found a solution to my problem
My receiver function now looks like this:
static gboolean xctlreceiver(GIOChannel *channel, GIOCondition condition, gpointer data)
{
char buf[1024];
gsize read;
GError *err = NULL;
g_print("xctlreceiver\n");
GSocketAddress *addr;
if (condition & G_IO_HUP) return FALSE;
if (gd->connectedToController == -1)
{
read = g_socket_receive_from(gd->gXctlSocket,&gd->gXctlController,buf,sizeof(buf),NULL,&err);
g_print("received %d bytes from XCTL socket on address %s\n",read,g_inet_address_to_string(g_inet_socket_address_get_address(G_INET_SOCKET_ADDRESS(gd->gXctlController))));
for (int i=0; i<read; i++)
{
g_print("0x%02X ",buf[i]);
}
g_print("\n");
if (isXtouchHeartbeat(buf,read))
{
g_print("received heartbeat from X-touch\n");
gd->connectedToController = 1;
sendXtouchHeartbeat(NULL);
g_timeout_add_seconds(2,sendXtouchHeartbeat,NULL);
}
}
else
{
g_io_channel_read_chars(channel,buf,sizeof(buf),&read,&err);
if (err != NULL) g_print("error receiving xctl: %s\n",err->message);
g_print("received %d bytes from XCTL channel\n",read);
if (gd->connectedToController == -1)
{
//g_print("X-touch found on ip address: %s\n",inet_ntoa(si_recv.sin_addr));
gd->connectedToController = 1;
}
}
return TRUE;
}
The function g_socket_receive_from gives me the address of the sender in the second argument.
I put it into my gd struct, for later use.
Hope this helps anyone with the same problem.
Kr,
Bart.
Related
I want to connect/bridge two serial ports in C.
I have 2 threads reading the ports, and writing to the other port.
Here is one example:
void *rfid_to_uart_thread(void *) {
char rfid_read_buffer[100];
int writeCounter;
do {
writeCounter = read(rfidCom, rfid_read_buffer, sizeof(rfid_read_buffer)-1);
if (writeCounter > 0) {
write(uartCom, rfid_read_buffer, writeCounter);
} else
usleep(25);
} while (!bKillBridgeThreads);
return NULL;}
The problem is, it seems that the writes are too slow. I often receive only half of the String on the other side. It seems like the write is asynchronously and thus the buffer is overwritten again in the next loop and overwrites the last 'write', so that the data is crippled?!
Is that right?
The ports are opened NON_BLOCKING and RW, Baudrate is and has to be 9600.
Looking at the man:
read() attempts to read up to count bytes from file descriptor fd into the buffer starting at buf.
In other wordsread does not grants to return all bytes send by other task, can give you a single byte up to sizeof(rfid_read_buffer)-1
What you can do is:
loop reading from rfidCom until the number of chars matches the number of chars sent.
You can use a specific terminator of messages and check for it to validate received message
encapsulate chars into a protocol message with an header that embed the message length, so the receiver can count the received chars and stop reading when last char is received.
For example:
void *rfid_to_uart_thread(void *)
{
char rfid_read_buffer[100] = {0};
int writeCounter;
char RXchar;
ssize_t retVal;
bool send = false;
do
{
memset(rfid_read_buffer, 0x00, sizeof(rfid_read_buffer));
send = true;
do
{
retVal = read(rfidCom, &RXchar, 1);
if (retVal > 0)
{
rfid_read_buffer[writeCounter] = RXchar;
writeCounter++;
}
else if (retVal < 0)
{
send = false;
RXchar = '\r'
break;
}
else
{
usleep(25);
}
}
while(RXchar != '\r');
if (send)
{
write(uartCom, rfid_read_buffer, writeCounter);
}
}
while (!bKillBridgeThreads);
return NULL;
}
OK, I've found a solution to my problem I think.
void *rfid_to_uart_thread(void *) {
char rfid_read_buffer[10];
ssize_t writeCounter = -1;
do {
writeCounter = read(rfidCom, &rfid_read_buffer, sizeof(rfid_read_buffer)-1);
if (writeCounter>0){
rfid_read_buffer[writeCounter] = 0;
LOGE("RFID -> UART: %s", rfid_read_buffer);
write(uartCom, rfid_read_buffer, writeCounter);
}else{
usleep(25);
}
tcdrain(uartCom);
} while (!bKillBridgeThreads);
return NULL;}
I've created my own define for a tcdrain, because the Android NDK I am using is not offering it in termios.h
Now, all the values seem to get transmitted to the UART port.
tcdrain is now defined as:
#define tcdrain(fd) ioctl(fd, TCSBRK, 1)
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.
I'm trying to write an IRC type chat client which has clients that can connected to a server. I'm trying to get it to work locally atm (Using FIFOS instead of sockets).
I've run into the following issue which I can't seem to solve:
After accepting a new client connection, I want to create a new thread for that client (on the server) that'll handle inputs from that client.
To do this I have the following piece of code (the full code is at the bottom):
while(1) {
.
.
.
if (pthread_create(&thread, NULL, client_handler, &new_client) != 0)
printf("Couldn't create a thread to listen to the client.... Not ok \n");
}
This works fine with 1 connected client.
The moment I try to connect another client it seems the previous thread that executed the method client_handler stopped running.
I know this because the server stops accepting input from that client, but the new thread works just fine (the one that handles the newly connected client).
I was wondering if my methodology was wrong or if I'm not using the pthread_create correctly.
Has anyone got any suggestions?
void server_listen() {
Client new_client;
ClientNode temp;
buffint client_name_length;
char client_name[CLIENT_NAME_SIZE];
char fifo_in[FIFO_NAME_SIZE], fifo_out[FIFO_NAME_SIZE];
buffint client_pid;
char ack[4] = "/ack";
char inuse[6] = "/inuse";
pthread_t thread;
buffint length;
ClientNode it;
buffint message_length;
char message[MESSAGE_LENGTH];
pthread_mutexattr_t attr;
while (1) {
memset(client_name, 0, CLIENT_NAME_SIZE);
client_name_length.data =0;
if (read_helper(irc_server.server_fifo, client_name_length.buff,
sizeof(int)) == -1)
return; /* error */
if (read_helper(irc_server.server_fifo, client_pid.buff, sizeof(int))
== -1)
return; /* error */
if (read_helper(irc_server.server_fifo, client_name, client_name_length.data) == -1)
return; /* error */
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_ERRORCHECK_NP);
pthread_mutex_init(&new_client.fifo_in_lock, &attr);
printf("Reading from a new client, with name: %s\n", client_name);
new_client.pid = client_pid.data;
strncpy(new_client.name, client_name, client_name_length.data);
new_client.name_length = client_name_length.data;
sprintf(fifo_in, "fifo-%d-in", client_pid.data);
sprintf(fifo_out, "fifo-%d-out", client_pid.data);
new_client.fifo_in = open(fifo_in, O_WRONLY);
if (new_client.fifo_in == -1)
return; /* error */
new_client.fifo_out = open(fifo_out, O_RDONLY);
if (new_client.fifo_out == -1)
return; /* error */
read_lock();
temp = client_exists_by_name(&irc_server.clients, client_name, client_name_length.data);
read_unlock();
if (temp != NULL) {
pthread_mutex_lock(&new_client.fifo_in_lock);
length.data = 6;
if (write_helper(new_client.fifo_in, length.buff, sizeof(int))
== -1) {
//TODO: What do we do if writing to the fifo_out failed?
printf( "Writing to the fifo-out failed for some unknown reason \n");
return;
}
if (write_helper(new_client.fifo_in, inuse, length.data) == -1) {
//TODO: What do we do if writing to the fifo_out failed?
printf( "Writing to the fifo-out failed for some unknown reason \n");
return;
}
pthread_mutex_unlock(&new_client.fifo_in_lock);
continue;
}
write_lock();
insert_node(&irc_server.clients, new_client);
write_unlock();
length.data = 4;
pthread_mutex_lock(&new_client.fifo_in_lock);
if (write_helper(new_client.fifo_in, length.buff, sizeof(int)) == -1) {
//TODO: What do we do if writing to the fifo_out failed?
printf("Writing to the fifo-out failed for some unknown reason \n");
return;
}
if (write_helper(new_client.fifo_in, ack, length.data) == -1) {
//TODO: What do we do if writing to the fifo_out failed?
printf("Writing to the fifo-out failed for some unknown reason \n");
return;
}
pthread_mutex_unlock(&new_client.fifo_in_lock);
foreach(it, irc_server.clients){
pthread_mutex_lock(&it->client.fifo_in_lock);
strncpy(message, new_client.name, new_client.name_length);
strncat(message, " joined the chat", sizeof(" joined the chat"));
message_length.data = sizeof(" joined the chat") + new_client.name_length;
if (write_helper(it->client.fifo_in, message_length.buff, sizeof(int)) == -1) {
//TODO: What do we do if writing to the fifo_out failed?
printf("writing to the fifo_in a public message ERROR1 \n");
return;
}
if (write_helper(it->client.fifo_in, message, message_length.data) == -1) {
//TODO: What do we do if writing to the fifo_out failed?
printf("writing to the fifo_in a public message ERROR2 \n");
return;
}
pthread_mutex_unlock(&it->client.fifo_in_lock);
memset(message, 0, MESSAGE_LENGTH);
message_length.data = 0;
}
if (pthread_create(&thread, NULL, client_handler, &new_client) != 0)
printf("Couldn't create a thread to listen to the client.... Not ok \n");
if (pthread_create(&thread, NULL,client_handler1 ,&new_client ) != 0)
printf("Couldn't create a thread to listen to the client.... Not ok \n");
print_clients();
}
}
It looks like you're sharing a single instance of new_client between all the threads in the server. A call to pthread_create() doesn't magically copy new_client. So every thread you create is using the same new_client. So when your master thread fills in values for a second client, the thread handling the first client tries to use those too.
Allocate a new new_client for each client, fill in the values and pass that into pthread_create(). You'll also need a per-client variable for the first parameter in pthread_create().
Other things - you're seemingly passing raw binary data between your client and server, things like string length integers. That kind of thing is going to cause you a whole pile of woe as soon as you have to start doing clients for different OSes. I strongly recommend you adopt a serialisation technology, preferably ASN.1 (not free but really robust) or Google Protocol Buffers (free but not as rich or robust).
if (pthread_create(&thread, NULL,client_handler ,&new_client ) != 0)
...
if (pthread_create(&thread, NULL,client_handler1 ,&new_client ) != 0)
Why you are using same pthread_t variable every time? You can't use same thread variable. Prefer to use an array of pthread_t like this:
pthread_t thread[2];
if (pthread_create(&thread[0], NULL, client_handler, &new_client ) != 0)
...
if (pthread_create(&thread[1], NULL, client_handler1, &new_client ) != 0)
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;
}
I'm working on a proxy application in C for a project. I have an issue with getaddrinfo() being unsuccessful when I pass it the parsed host name. If I hard code the host, for example "www.google.ca" it doesn't error but when given the URL (from a GET request that the code receives) it does produce an error (The exact error is "Unknown name or service"). I've tried debugging in NetBeans and as far as I can tell the parsed URL is no different from the one I've hard coded. Below is the code that I'm using:
Snippet of code that receives the request and tries to forward it:
...
//Message is received in the code before this
if (get_host(message, &url) == 0)
{
//Tries to open a socket to the parsed URL. This is where the issue happens
forawrd_fd = create_forward_socket(url, "80");
}
...
The get host function:
int get_host(char *request, char **host_url)
{
char url[BUFFER_SIZE];
if(sscanf(request, "%*s %s HTTP/1.1\r\n", url) != 1)
{
return -1;
}
else
{
int len = strlen(url);
//If there is a / at the end of the URL remove it
if(url[len-1] == '/')
{
printf("%c%c\n", url[len-2], url[len-1]);
url[len-1] = '\0';
printf("%s\n", url);
}
*host_url = &url;
//If the start of the string is http:// remove it
if(url[0] == 'h' && url[1] == 't' && url[2] == 't'&& url[3] == 'p')
{
*host_url += 7;
}
return 0;
}
}
Function that gets the file descriptor and makes the getaddrinfo
int create_forward_socket(char* url, const char* port)
{
//Status variable needed for some calls
int status, socket_fd, received_data;
//Setup address info structs
struct addrinfo hints;
struct addrinfo *result, *current;
//Initialize our hints.
memset(&hints, 0, sizeof hints);
//IPv4 or IPv6 we don't
hints.ai_family = AF_UNSPEC;
//We want a stream socket not datagram
hints.ai_socktype = SOCK_STREAM;
//Whatever this means (I forget but again the interwebs says...)
hints.ai_flags = AI_PASSIVE;
//Get a linked list of address info that we will choose from
if ((status = getaddrinfo(url, port, &hints, &result)) != 0) //Status here is -2 when called with the parsed URL
{
return -1;
}
for (current = result; current != NULL; current = current->ai_next)
{
if ((socket_fd = socket(current->ai_family, current->ai_socktype, current->ai_protocol)) != -1)
{
if (connect(socket_fd, current->ai_addr, current->ai_addrlen) != -1)
{
//We found a usable socket
break;
}
else
{
close(socket_fd);
}
}
}
if (current == NULL)
{
return -2;
}
else
{
return socket_fd;
}
}
Any help would be appreciated. If more of my code is needed please let me know. I included only what I thought was important so the post wasn't too long.
My guess is that you are returning a pointer to a local variable. See, url is a local variable, and the *host_url = url; line (I'm assuming that this is an output parameter) will return it to the caller. But local variables will be destroyed just when the function returns, and then, *host_url will point to the middle of nowhere.
The code calling get_host() is like:
char *host;
get_host(req, &host);
//call getaddrinfo with host
But host will not point to valid memory outside of get_host.
The solution is that the caller allocates the buffer:
int get_host(char *request, char *url)
{ ... }
And when you call it:
char host[BUFFER_SIZE];
get_host(req, host);
//call getaddrinfo with host