Compiling the Paho MQTT C Client Library - c

I want to integrate the [Paho MQTT C Client Library][1] to one of my C programs. Since I am from EE, I find it difficult achieve this task. However my efforts are described below along with my problem.
The purpose is to simply use username, password and subscribe to perticular MQTT topic using a C program. If this is done, I can proceed to do the rest of things such as saving the data to a .txt file and etc which I am completely familiar with in C.
Since I am from an electronics background, my familiarity with compiling complex projects like these and making them work is not really at best but I really want to get there.
I do know how to compile small projects using "make all" and use the binary executable produced to use such software. I simply do, make clean and make all.
However, the idea of compiling a library doesn't make sense to me. Why do I need to compile any library in the first place? Usually, when I write C program, I integrate someone else's library by uisng #include "library2.h". From this method, I am able to call functions in that library and get things done. Why cant we use Paho the same way? I do not understand why Paho MQTT C library requires compiling. I would like to know the technical reason for this.
Secondly, and most importantly, I would really appreciate if you can provide me step by step guidance to write a simple C program that can subscribe to my MQTT server to printout the messages published in that topic. I use Ubuntu 14.10 LTS.
I understand that this question may be a very basic question. I have asked answers to this question from other people in the lab and also tried fiddling with the example available on [1]
When I do so, I am bombarded with many error messages and I just cant seem to get this to work. May be one of you can shred some light with proper guiding steps for me to get my client to work.
I would really appreciate your efforts on this. It would help me a lot.
update:
As per request of Gaurav Pathak I post my erros below.
Step 1: I downloaded the coursecode of Paho MQTT libray from
github dot com/eclipse/paho.mqtt.c
Step 2: I went into the /home/user/paho.mqtt.c/ and ran Make Clean and Make All
Step 3: Then, I made a copy of the following example code provided on http://www.eclipse.org/paho/files/mqttdoc/MQTTClient/html/subasync.html in side /home/user/paho.mqtt.c/src . This example code is given below.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "MQTTClient.h"
#define ADDRESS "tcp://localhost:1883"
#define CLIENTID "ExampleClientSub"
#define TOPIC "MQTT Examples"
#define PAYLOAD "Hello World!"
#define QOS 1
#define TIMEOUT 10000L
volatile MQTTClient_deliveryToken deliveredtoken;
void delivered(void *context, MQTTClient_deliveryToken dt)
{
printf("Message with token value %d delivery confirmed\n", dt);
deliveredtoken = dt;
}
int msgarrvd(void *context, char *topicName, int topicLen, MQTTClient_message *message)
{
int i;
char* payloadptr;
printf("Message arrived\n");
printf(" topic: %s\n", topicName);
printf(" message: ");
payloadptr = message->payload;
for(i=0; i<message->payloadlen; i++)
{
putchar(*payloadptr++);
}
putchar('\n');
MQTTClient_freeMessage(&message);
MQTTClient_free(topicName);
return 1;
}
void connlost(void *context, char *cause)
{
printf("\nConnection lost\n");
printf(" cause: %s\n", cause);
}
int main(int argc, char* argv[])
{
MQTTClient client;
MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer;
int rc;
int ch;
MQTTClient_create(&client, ADDRESS, CLIENTID,
MQTTCLIENT_PERSISTENCE_NONE, NULL);
conn_opts.keepAliveInterval = 20;
conn_opts.cleansession = 1;
MQTTClient_setCallbacks(client, NULL, connlost, msgarrvd, delivered);
if ((rc = MQTTClient_connect(client, &conn_opts)) != MQTTCLIENT_SUCCESS)
{
printf("Failed to connect, return code %d\n", rc);
exit(EXIT_FAILURE);
}
printf("Subscribing to topic %s\nfor client %s using QoS%d\n\n"
"Press Q<Enter> to quit\n\n", TOPIC, CLIENTID, QOS);
MQTTClient_subscribe(client, TOPIC, QOS);
do
{
ch = getchar();
} while(ch!='Q' && ch != 'q');
MQTTClient_disconnect(client, 10000);
MQTTClient_destroy(&client);
return rc;
}
Step 3: Then I ran GCC client.c -o client
user#userpc:~/paho.mqtt.c/src$ gcc client.c -o client
/tmp/ccEkSjap.o: In function `msgarrvd':
client.c:(.text+0xc5): undefined reference to `MQTTClient_freeMessage'
client.c:(.text+0xd1): undefined reference to `MQTTClient_free'
/tmp/ccEkSjap.o: In function `main':
client.c:(.text+0x1eb): undefined reference to `MQTTClient_create'
client.c:(.text+0x21d): undefined reference to `MQTTClient_setCallbacks'
client.c:(.text+0x233): undefined reference to `MQTTClient_connect'
client.c:(.text+0x29a): undefined reference to `MQTTClient_subscribe'
client.c:(.text+0x2cb): undefined reference to `MQTTClient_disconnect'
client.c:(.text+0x2da): undefined reference to `MQTTClient_destroy'
collect2: error: ld returned 1 exit status
[1]: eclipse dot org/paho/files/mqttdoc/MQTTClient/html/index.html

However, the idea of compiling a library doesn't make sense to me.
Compiling the library from source is the first thing that you need to do. Even if you don't want to compile the library to create an archive .a file you need to include the source code (*.c and *h files) of the same library in your project.
Why do I need to compile any library in the first place?
Very Good question! The answer is because it's not easy to find a pre-compiled library for specific processor architecture. You may get a pre-compiled library for x86 or x64 but it is difficult to find a pre-compiled library for other architectures for e.g. Power PC, ARM, etc. So, the best way is to download the source code and either make a library out of it to statically link with your project or just directly include the source code in your existing project and compile it with your project.
Usually, when I write C program, I integrate someone else's library by
uisng #include "library2.h".
Don't you need to link the source of the library with your project? Just including the headers won't link the library. I guess you need to first understand what are the steps of the compilation process, and especially what is the significance of linker and linking process.
Please read this post for getting an understanding of how the program is compiled and linked.
Also, please read this post to understand the difference between library and header file.
When I do so, I am bombarded with many error messages and I just cant
seem to get this to work.
If you provide your code and tell us your specific error then may be we can help.

Related

Undefined reference ld error when using Windows <bluetoothapis.h>

I am new to programming and want to work with the Windows BluetoothApi.h library in C. I've written smaller programs that reference header files I've created, but none of the APIs given by windows.
I am attempting to return information from a local bluetooth speaker to a terminal session on my PC. I've been referencing the BluetoothFindFirstRadio and BLUETOOTH_FIND_RADIO_PARAM documentation, as well as some posts on Stack to see some viable examples. I believe I'm close to being able to compile but I keep getting an error about an undefined reference to the functions I'm calling that I do believe are in the BluetoothAPI.h header file.
From what I've seen, again on Stack, it seems that it's possible that "there is not enough space left at \user\tmp"?
or
Looking at the documentation for ld, it may be possible I need to try to compile using a different command altogther?
PS C:\scripts\C_Lang\Bluetooth> gcc bluetest.c -o test
C:\Users\Ryan\AppData\Local\Temp\cce0FxKH.o:bluetest.c:(.text+0x2b): undefined reference to `BluetoothFindFirstRadio#8'
C:\Users\Ryan\AppData\Local\Temp\cce0FxKH.o:bluetest.c:(.text+0x48): undefined reference to `BluetoothFindRadioClose#4'
collect2.exe: error: ld returned 1 exit status
Code is below:
#include <stdio.h>
#include <string.h>
#include <Windows.h> //not sure if needed
#include <Ws2bth.h> //not sure if needed
#include <bthsdpdef.h>
#include bluetoothapis.h>
//#include <bluetoothleapis.h>
#pragma comment(lib, "Bthprops.lib");
int main(void)
{
BLUETOOTH_FIND_RADIO_PARAMS btfrp; // structure
btfrp.dwSize = sizeof(btfrp); // creating space in memory for parameters?
HANDLE hRadio; // not sure what a handle is, something similar to a pointer?
HBLUETOOTH_RADIO_FIND hFind = BluetoothFindFirstRadio(&btfrp, &hRadio);
// BluetoothGetDeviceInfo(hRadio, &pbtdi);
printf("Bluetooth test!");
BluetoothFindRadioClose(hFind);
return 0;
}
It seems that my issue was not 100% my code, but about how I was attempting to compile my code. After looking further into the documentation I read the line, "Link only to Bthproprs.lib, and avoid linking to Ilprops.lib." So, I don't fully understand why I would need to link, when I have a #pragma comment(lib, "Bthprops.lib"); but that is most likely due to my own ignorance. I did notice the answer on this post which helped clear up my ignorance of HOW to link the Bthproprs.lib library. So, my code didn't change, but my compile did, gcc bluetest.c -o test -lbthprops.
Now, to return something actually useful.

Why does using curl_easy_init() output unusual error code?

I am currently learning C, using CLion on Windows, and as so I am starting off with a very simple program using cURL.
I have finally successfully included the library in my code using CMake as performed in this question:
How do I link dynamically built cmake files on Windows?
The code now builds without error.
The issue is, as soon as I write the curl_easy_init(), the program outputs with an unusual exit code not referenced in the cURL docs and print functions fail to output like normal.
#include <stdio.h>
#include <curl/curl.h>
int main(void) {
printf("Hello world!\n");
CURL *curl;
CURLcode res;
curl = curl_easy_init(); // Line that changes program
return 0;
}
Whenever that dreadful line is written, the program no longer outputs a happy old "Hello World!" with an exit code of zero, and instead, outputs this:
Process finished with exit code -1073741515 (0xC0000135)
What even is that exit code??
Any information is much appreciated.
0xC0000135 is "application not correctly initialized", which generally indicates that the loader cannot find a dll required by your application. Most probably you linked the libcurl import library, but the corresponding dll (libcurl.dll) cannot be found in the same directory of the executable and isn't in the global dll search paths. Make sure the dll is available when you launch your application, or link libcurl statically.

C HTTP uriparser lib setup

I am currently working on a simple HTTP proxy as an educational personal project. I am fairly new to socket programming, C, and the need for and use of specific libraries.
After reading up on different ways to parse HTTP request URLs in C, I found that using parsing libraries, like uriparser, seemed to be the most popular and the safest choice.
Unfortunately, I have really been struggling to get this library working properly.
After downloading the library from here, I unpacked the "tarball" and ran the following:
./configure
make
sudo make install
The output for 'sudo make install' claimed that that the libraries were installed in '/usr/local/lib', which they have been. However, when I try to use a UriUriA obj as shown in Uriparser's documentation here, the object is clearly not recognized.
Is this library installed in the right place?
Am I missing something obvious like not including a header file for this library? I could't find one in the linked documentation.
RELEVANT CODE:
(functionality is pretty bare right now, mainly pointing at UriUri instantiation which still produces unknown type compile error. I still have yet to be able to use the lib)
int parse_req(char * buffer, char * url){
UriUriA uri;
char *reqs[] = {"GET ", "CONNECT "};
int i = 0;
//Determine Request Types
while(reqs[i] != NULL){
int check = strncmp(reqs[i],buffer,strlen(reqs[i]));
if (check == 0){
break;
}
i++;
}
return -1;
}
If anyone has any experience with this library, any help is appreciated! Thanks!

Tcl interpreter undefined reference error while compiling with gcc

I am new to Tcl scripting and would like to use C to embed Tcl codes.
This is the code that I have copied from a website to test the Tcl-C working.
test.c
#include <stdio.h>
#include <tcl.h>
void main ()
{
Tcl_Interp *myinterp;
char *action = "set a [expr 5 * 8]; puts $a";
int status;
printf ("Your Program will run ... \n");
myinterp = Tcl_CreateInterp();
status = Tcl_Eval(myinterp,action);
printf ("Your Program has completed\n");
getch();
}
I am using MinGW to compile this file.
I have copied the contents of the C:\Tcl\include folder into the C:\MinGW\include folder as well.
My gcc command for compiling :
gcc -o test.exe test.c
The error message shown :
C:\Users\user\AppData\Local\Temp\ccEHJKCb.o:tcl_connection_test.c:(.text+0x23): undefined reference to `_imp__Tcl_CreateInterp'
C:\Users\user\AppData\Local\Temp\ccEHJKCb.o:tcl_connection_test.c:(.text+0x3d): undefined reference to `_imp__Tcl_Eval'
c:/mingw/bin/../lib/gcc/mingw32/4.8.1/../../../../mingw32/bin/ld.exe: C:\Users\user\AppData\Local\Temp\ccEHJKCb.o: bad reloc address 0x20 in section `.eh_frame'
c:/mingw/bin/../lib/gcc/mingw32/4.8.1/../../../../mingw32/bin/ld.exe: final link failed: Invalid operation
collect2.exe: error: ld returned 1 exit status
I don't seem to have any libtcl file in the Tcl folder.
The Tcl version is ActiveTcl 8.5.15.0.297577.
Any help would be really appreciated.
Your example how to embed Tcl is outdated, and you are missing certain things in your link line (-ltcl85 for example). If you simply add -ltcl85 to your link line it should start to work.
It does not work in your case, because you installed the x64 (64-Bit version) of ActiveTcl, which provides x64 dlls, not 32-Bit ones. But the standard mingw gcc only works with 32-Bit libraries.
So to get this to work:
Download the 32-Bit ActiveTcl distribution
Compile your code with gcc -o test.exe test.c -Lc:/tcl/lib -Ic:/tcl/include -ltcl86
Adjust your path so the c:\tcl\bin\tcl86.dll is found in PATH, make also sure Tcl finds its libdir (set TCL_LIBRARY=c:\tcl\lib\tcl8.6)
run your program
But for more complex examples, you still need to initialise the library and a do some boilerplate code, so please call Tcl_FindExecutable(argv[0]); before the call to Tcl_CreateInterp() otherwise a few commands (e.g. clock might just not work as expected).
Have a look at http://www.tcl.tk/cgi-bin/tct/tip/66.html for some more details. Also have a look at the Tcl source distribution and the source for the tclsh shell.
You're very close to getting it right.
The Tcler's Wiki has a few examples, some of which are very confusing to be frank, but this one from this page is the best I've spotted recently. (The comments are mine.)
#include <stdlib.h>
#include <tcl.h>
int main (int argc, char *argv[]) {
Tcl_Interp *interp;
const char *script = "proc p1 a { puts $a }";
// Initialize the Tcl library; ***STRONGLY RECOMMENDED***
Tcl_FindExecutable(argv[0]);
// Create the interpreter, the execution context
interp = Tcl_CreateInterp();
// Initialise the interpreter
if (TCL_OK != Tcl_Init(interp)) {
fprintf(stderr, "Tcl_Init error: %s\n", Tcl_GetStringResult(interp));
exit(EXIT_FAILURE);
}
// Define a procedure
Tcl_Eval(interp, script);
fprintf(stderr, "res 1: %s\n", Tcl_GetStringResult(interp));
// Check if the procedure exists
Tcl_Eval(interp, "puts [info commands p*]");
fprintf(stderr, "res 2: %s\n", Tcl_GetStringResult(interp));
// Call the procedure
Tcl_Eval(interp, "p1 abc");
fprintf(stderr, "res 3: %s\n", Tcl_GetStringResult(interp));
// We could use Tcl_DeleteInterpreter to clean up here, but why bother?
return EXIT_SUCCESS;
}
What else were you missing? Simple. You forgot to tell the C compiler to use the Tcl library when building the executable; the compiler (or, more strictly, the linker) is in places a stupid piece of code. The exact option to use to get the linker to add the library in will depend on your system configuration, but is probably going to be -ltcl, -ltcl8.5 or -ltcl8.6; which it is depends on the filename and all sorts of things that we can't check exactly without being on your system. The names do fit a simple pattern though.
It's also possible that you might need to pass the -L option in to tell the linker about additional library locations. (There's an equivalent -I for telling the compiler where to find include files, so you don't have to copy everything into one gigantic unmanageable directory.)
The order of arguments can matter. Libraries should be listed after the source file:
gcc -o test.exe test.c -L/mingw/path/to/library/directory -ltcl86
(If you're using old, unsupported versions of Tcl — why would you do that?! — then the code above won't work because Tcl_Eval then took a writable string. But that was fixed many years ago and upgrading to a current version is the fix.)

Getting IP of post client

Well I know that I should have tried a lot before asking here, but my problem is. It's hard to get structured reference of fcgi documentation. So i hope you won't downvote me that much, even in aspect of little lack of self study.
I'm trying to find a way to archive the IP of the requesting client.
As I guess (if I understood right) I could request the HTTP header of the connection by the FCGX_stream handle. But I would prefer a easier way if there is one.
My first try was checking it about the getenv as provided in the first fcgi tutorial, but as I tryed it as described here:
https://stackoverflow.com/a/4107212/2003898
It compiled fine, but on first request my fcgi app just crashed. (but it wouldn't solve my problem anyway as I figured out the get env is just requesting MY, so the host ones, env's)
I were also trying arround with the
*FCGX_GetParam(const char *name, FCGX_ParamArray envp);
function. But either I'm to stupid to use or it is also just providing my local evniroment and not the POST side's one.
So if anyone could tell me how to acces those data (prefered without extracting from HTTP header) or how to use FCGX_GetParam to acces it,
I would be thankfull.
EDIT:
#include "fcgi_stdio.h"
#include <stdlib.h>
int main()
{
int count = 0;
while(FCGI_Accept() >= 0)
{
for (count = 0; environ[count] != NULL; count++)
{
printf("%s\n", environ[i]);
}
}
return 0;
}
Use getenv("REMOTE_ADDR")
The remote IP address isn't included in the HTTP headers anyway

Resources