Is it possible and if so how to archive it that one application using libmosquitto get messages from one broker and publish it to another?
Its pretty simple to just change topic in mosquito_publish function, but set of broker takes place in
mosquitto_connect(mosq, "localhost",1883 , 60);
Running mosquitto_connet second time
e.g.
mosquitto_connect(mosq, "mqtt.example.io",1883 , 60);
ends up connecting to last one.
I tried to create two mosquitto structs but I dont know how to inform second one about message form subbed channel in order to get info from it, change it and push to proper broker.
Something like this should do the job (I've not tested it though). You'll have to add error checking.
#include <stdio.h>
#include <mosquitto.h>
void on_connect1(struct mosquitto *mosq, void *obj, int result)
{
int rc = MOSQ_ERR_SUCCESS;
if(!result){
mosquitto_subscribe(mosq, NULL, "/v1/topic1", 0);
}else{
fprintf(stderr, "%s\n", mosquitto_connack_string(result));
}
}
void on_message1(struct mosquitto *mosq, void *obj, const struct mosquitto_message *message)
{
struct mosquitto *mosq2 = (struct mosquitto *)obj;
mosquitto_publish(mosq, NULL, "/v1/topic2", message->payloadlen, message->payload, message->qos, message->retain);
}
int main(int argc, char *argv[])
{
struct mosquitto *mosq1, *mosq2;
mosquitto_lib_init();
mosq2 = mosquitto_new(NULL, true, NULL);
mosq1 = mosquitto_new(NULL, true, mosq2);
mosquitto_connect_callback_set(mosq1, on_connect1);
mosquitto_message_callback_set(mosq1, on_message1);
mosquitto_connect(mosq2, "mqtt.example.io", 1883, 60);
mosquitto_connect(mosq1, "localhost", 1883, 60);
mosquitto_loop_start(mosq2);
mosquitto_loop_forever(mosq1, -1, 1);
mosquitto_destroy(mosq1);
mosquitto_destroy(mosq2);
mosquitto_lib_cleanup();
return 0;
}
Yes,
You need two totally separate instances of client. Which means two separate instances the mosquitto structure returned by the mosquitto_new() function. One for each broker.
At the moment you are re-using the same structure so it is only holding the details of the last call to mosquitto_connect()
This command line using mosquitto can do the job:
mosquitto_sub -h localhost -t '#' | { while [ 1 -lt 2 ] ; do read message ; if [[ "$message" != "$prev_message" ]]; then mosquitto_pub -h localhost -t "tenewtest" -m "$message" ; prev_message=$message ; fi ; done ; }
If you simply want to forward the messages, then there is a 'bridge' functionality in mosquitto broker. It makes it easier through configuration. It has a feature where you can specify the topics you want to forward & also authentication options. It is quite feature rich.
Related
I am using C library iperf3 to measure network. When I start network testing my aplication freezes and wait for results. I tried async and threads but any progress. Any advise? I'd like to run my test and asynchronously call another methods (at best, call this library again, but other methods). Is it possible?
My network.dart
final DynamicLibrary iperfLib = Platform.isAndroid
? DynamicLibrary.open("libiperf.so")
: DynamicLibrary.process();
typedef RunTestFunc = ffi.Pointer<ffi.Uint8> Function(
ffi.Pointer<ffi.Uint8> context);
typedef RunTest = ffi.Pointer<ffi.Uint8> Function(
ffi.Pointer<ffi.Uint8> context);
RunTest _run_test = iperfLib
.lookup<ffi.NativeFunction<RunTestFunc>>('run_test')
.asFunction<RunTest>();
ffi.Pointer<ffi.Uint8> runTest(ffi.Pointer<ffi.Uint8> context) {
return _run_test(context);
}
and iperf.c
Iperf* run_test(Iperf* test) {
__android_log_print( ANDROID_LOG_INFO, "DONE ", "server_hostname %s", test->server_hostname );
int cc = iperf_run_client( test ) ;
__android_log_print( ANDROID_LOG_INFO, "DONE ", " %d",cc );
iperf_free_test( test );
return test
}
Async Callbacks
The problem is that C routines called from dart are blocking and therefore congest the single existing dart isolate, consequently freezing the UI.
To work around this problem you have to open a port on the dart isolate through which your C routines can asynchronously send messages to the dart isolate. To signal to the dart compiler that this is a non-blocking operation, simply delay the completion of the function until a message on the designated port has been received.
Future<int> asyncData() async {
var receiveData;
bool receivedCallback = false;
var receivePort = ReceivePort()..listen((data) {
print('Received data from c');
receiveData = data;
receivedCallback = true;
});
var nativeSendPort = receivePort.sendPort.nativePort;
nativeTriggerFunction(nativeSendPort);
while(!receivedCallback) {
await Future.delayed(Duration(milliseconds: 100));
}
receivePort.close();
return receiveData;
}
In C, you need to create a trigger function which should ideally be as lightweight as possible, passing the port number to your C code and calling the actual function you want to execute on a different thread.
The trigger function will finish almost instantly, allowing your dart thread to do other work and as soon as the newly created thread is done, it sends its result through the native port back to the dart isolate which can pick up where it left off.
void native_trigger_function(Dart_Port port) {
pthread_t t;
Dart_Port *args = (Dart_Port *) malloc(sizeof(Dart_Port));
*args = port;
pthread_create(&t, NULL, _native_function, args);
}
void *_native_function(void *args) {
Dart_Port port = *(Dart_Port *) args;
int rc = 0;
// do some heavy work
// send return code to dart
Dart_CObject obj;
obj.type = Dart_CObject_kInt32;
obj.value.as_int32 = rc;
Dart_PostCObject_DL(port, &obj);
free(args);
pthread_exit(NULL);
}
Note: This logic relies on the native dart api to work which can be found here. Before use, the interface needs to be attached to the current dart isolate which can be achieved by calling Dart_InitializeApiDL(dart_api_data) from C where dart_api_data is a void pointer which can be obtained from your dart code using the dart:ffi package through NativeApi.initializeApiData.
Update: Thanks #fdollack for fixing the example snippets!
Thank you #Lucas Aschenbach!
This minimum example was so hard to find.
2 small additions.
First, the allocated pointer should be casted to (Dart_Port*),
and the port argument from dart has to be assigned/copied to where the pointer is at!
void native_trigger_function(Dart_Port port) {
pthread_t t;
Dart_Port *args= (Dart_Port*)malloc(sizeof(Dart_Port));
*args = port; // assign port
pthread_create(&t, NULL, _native_function, args);
}
The second thing is inside the _native_function the response to Dart has to be
Dart_PostCObject_DL(port, &obj);
instead of
Dart_PostCObject_DL(args_c.send_port, &obj);
I am trying to authenticate against a git server with libgit2 using SSH keys.
So far, this is working for URLs like ssh://myuser#host.domain:1234/dirs/repo.git, where my application accepts the URL as an argument.
However, if I remove the username from the URL (i.e. ssh://host.domain:1234/dirs/repo.git) the connection fails, even if I set the user name programmatically (see below).
Consider the following MCVE for a program that checks whether a certain repository is reachable (no error checks except for the necessary):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <pwd.h>
#include <git2.h>
#include <git2/sys/repository.h>
int my_cred_cb(git_cred **out, const char *url,
const char *username_from_url, unsigned int allowed_types, void *payload)
{
uid_t uid = geteuid(); // Get effective user ID
struct passwd* pw = getpwuid(uid); // Get password file entry
char privkeypath[strlen(pw->pw_dir) + 13];
strcpy(privkeypath, pw->pw_dir);
strcat(privkeypath, "/.ssh/id_rsa"); // "~user/.ssh/id_rsa"
char publkeypath[strlen(privkeypath) + 5];
strcpy(publkeypath, privkeypath);
strcat(publkeypath, ".pub"); // "~user/.ssh/id_rsa.pub"
const char* username = (username_from_url != NULL ? username_from_url : pw->pw_name);
printf("Using username: %s, priv key %s and publ key %s\n", username, privkeypath, publkeypath);
return git_cred_ssh_key_new(out, username, publkeypath, privkeypath, ""); // No passphrase for keys
}
int main(int argc, char** argv)
{
git_remote* remote = NULL;
git_repository* repo = NULL;
git_remote_callbacks cbs;
const git_error* err;
if (argc != 2) return EXIT_FAILURE;
git_libgit2_init();
git_repository_new(&repo);
git_remote_create_anonymous(&remote, repo, argv[1]);
git_remote_init_callbacks(&cbs, GIT_REMOTE_CALLBACKS_VERSION);
cbs.credentials = my_cred_cb;
if (git_remote_connect(remote, GIT_DIRECTION_FETCH, &cbs, NULL, NULL)) {
err = giterr_last();
printf ("Error %d: %s\n", err->klass, err->message);
return EXIT_FAILURE;
}
git_libgit2_shutdown();
printf("git repo exists and is reachable.\n");
}
This can be compiled with gcc -Wall -pedantic -std=c99 -o myapp main.c -lssh2 -lgit2, assuming the include and library paths are set properly.
Now consider the output for different URLs:
$ ./myapp ssh://myuser#host.domain:1234/dirs/repo.git
Using username: myuser, priv key /home/myuser/.ssh/id_rsa and publ key /home/myuser/.ssh/id_rsa.pub
git repo exists and is reachable.
And now the failing case:
$ ./myapp ssh://host.domain:1234/dirs/repo.git # Note the missing user name
Using username: myuser, priv key /home/myuser/.ssh/id_rsa and publ key /home/myuser/.ssh/id_rsa.pub
Error 23: callback returned unsupported credentials type
I do not understand why I receive this error, since I pass the exact same information to the library (why is it "unsupported credentials type" in the first place?).
Even worse, I usually use Host entries in my ~/.ssh/config, such that instead of putting host.domain:1234 I can simply use myhost (e.g. git clone ssh://myhost/dirs/repo.git works just fine). For my application, this is the output:
$ ./myapp ssh://myhost/dirs/repo.git
Error 12: failed to resolve address for myhost: Name or service not known
It looks like libgit2 does not configure libssh2 to read in the ssh-config. That's a related, yet probably a different problem. Still I feel these two problems belong together.
Summarizing my questions:
How do I pass the username to the git credentials programmatically (vs. in the URL)?
How do I tell libgit2 to retrieve information from my ssh-config before attempting to connect?
These really are two separate unrelated questions.
You should be checking the allowed_types parameter in your callback and only return a git_cred_ssh_key_new credential if it contains GIT_CREDTYPE_SSH_KEY. The backend is probably requesting a credential of type GIT_CREDTYPE_USERNAME because the URL doesn't have one. In that case you should be returning a credential created by git_cred_username_new. Your callback will be called twice, once to get the username, and a second time to create the ssh credential.
Reading config settings from your OpenSSH config file at ~/.ssh/config isn't supported by libgit2 because it isn't support by libssh2. If you want to read settings from there, you have to do it yourself.
Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 6 years ago.
Improve this question
I am trying to connect to an MQTT broker in SSL/TLS using libmosquitto (in C). I am sure it is working on the server side as I successfully connected to the borker using mosquitto_sub (or mosquitto_pub) in the command line and with the same certificate I am using in my code.
When I try to connect using my C program, I always get the following error : "Error: Unable to create TLS context."
I am using libmosquitto 1.4.8 on Linux. Here is the code I am using :
#include <mosquitto.h>
static struct SomeStruct *data = NULL;
// The variable mosq is included in the struct
// The struct has been created somewhere else
void foo(void)
{
// I usually check the return values but removed
// it to make the code easier to read
mosquitto_lib_init();
data->mosq = mosquitto_new("foobar", true, data);
// Connect the callbacks
mosquitto_username_pw_set(data->mosq, "user", "pass");
mosquitto_tls_set(data->mosq, "/path/to/ca/file.crt,
NULL, NULL, NULL, NULL);
mosquitto_tls_insecure_set(data->mosq, 1)
mosquitto_tls_opts_set(data->mosq,
1, // also tried 0
NULL, // also tried "tlsv1.2"
NULL);
// All the return values are correct up to here
mosquitto_connect(data->mosq, "mqtt.example.com", 8883, 30); // Fails
// Logs : Error: Unable to create TLS context.
// A TLS error occurred.
}
Does anyone know what could be the issue ?
Cheers,
Antoine
EDIT : I forgot to add that I am not using mosquitto's main loop beacause another library I use already has one and I need to have a very limited number of threads. I therefore call mosquitto_loop() everytime the file descriptor changes.
This problem can only occur if SSL_CTX_new() fails. This seems pretty unlikely if mosquitto_sub works just fine on the same machine. Try "tlsv1", "tlsv1.1" as other options to tls_opts_set. You can also try patching the mosquitto client library to get more information about why openssl is unhappy:
diff --git a/lib/net_mosq.c b/lib/net_mosq.c
index 08f24d9..d4c57fd 100644
--- a/lib/net_mosq.c
+++ b/lib/net_mosq.c
## -409,6 +409,8 ## int _mosquitto_socket_connect(struct mosquitto *mosq, const char *host, uint16_t
#ifdef WITH_TLS
int ret;
BIO *bio;
+ int e;
+ char ebuf[256];
#endif
if(!mosq || !host || !port) return MOSQ_ERR_INVAL;
## -441,6 +443,11 ## int _mosquitto_socket_connect(struct mosquitto *mosq, const char *host, uint16_t
#endif
if(!mosq->ssl_ctx){
_mosquitto_log_printf(mosq, MOSQ_LOG_ERR, "Error: Unable to create TLS context.");
+ e = ERR_get_error();
+ while(e){
+ _mosquitto_log_printf(mosq, MOSQ_LOG_ERR, "OpenSSL Error: %s", ERR_error_string(e, ebuf));
+ e = ERR_get_error();
+ }
COMPAT_CLOSE(sock);
return MOSQ_ERR_TLS;
}
Example code that reproduces the problem:
#include <stdio.h>
#include <mosquitto.h>
void my_log_callback(struct mosquitto *mosq, void *obj, int level, const char *str)
{
printf("LOG: %s\n", str);
}
int main(int argc, char *argv[])
{
struct mosquitto *mosq = NULL;
int rc;
printf("Calling connect before lib init, this should fail.\n");
mosq = mosquitto_new(NULL, true, NULL);
mosquitto_log_callback_set(mosq, my_log_callback);
mosquitto_tls_set(mosq, "mosquitto.org.crt", NULL, NULL, NULL, NULL);
rc = mosquitto_connect(mosq, "test.mosquitto.org", 8883, 60);
printf("connect returned %d\n", rc);
mosquitto_destroy(mosq);
mosquitto_lib_init();
printf("Calling connect after lib init, this should be fine.\n");
mosq = mosquitto_new(NULL, true, NULL);
mosquitto_log_callback_set(mosq, my_log_callback);
mosquitto_tls_set(mosq, "mosquitto.org.crt", NULL, NULL, NULL, NULL);
rc = mosquitto_connect(mosq, "test.mosquitto.org", 8883, 60);
printf("connect returned %d\n", rc);
mosquitto_destroy(mosq);
mosquitto_lib_cleanup();
printf("Calling connect after lib cleanup, this should fail.\n");
mosq = mosquitto_new(NULL, true, NULL);
mosquitto_log_callback_set(mosq, my_log_callback);
mosquitto_tls_set(mosq, "mosquitto.org.crt", NULL, NULL, NULL, NULL);
rc = mosquitto_connect(mosq, "test.mosquitto.org", 8883, 60);
printf("connect returned %d\n", rc);
mosquitto_destroy(mosq);
return 0;
}
This produces the output:
Calling connect before lib init, this should fail.
LOG: Error: Unable to create TLS context.
LOG: OpenSSL Error: error:140A90A1:lib(20):func(169):reason(161)
connect returned 8
Calling connect after lib init, this should be fine.
LOG: Client mosq/7v?>w#YfTKk\U=;sO] sending CONNECT
connect returned 0
Calling connect after lib cleanup, this should fail.
LOG: Error: Unable to create TLS context.
LOG: OpenSSL Error: error:140A90F1:lib(20):func(169):reason(241)
connect returned 8
The final OpenSSL error is the same as yours, so you need to check whether you've deinitialised openssl. This is something mosquitto_lib_cleanup() does, but it could be something your code is doing completely independently of libmosquitto.
I am trying to write an AMQP 1.0 client using Qpid Proton in C. I do not want to use messenger. I want to use the proton-c engine. I am having a little trouble figuring out how to do this. My main sticking point is setting the endpoint for the connection. The only example of a C client using the proton-c engine I can find is here.
https://github.com/apache/qpid-proton/blob/master/examples/engine/c/psend.c
However, it uses structs that are not part of the Qpid Proton C API 0.12.0. Specifically, I don’t see pn_driver_t or pn_connector_t as part of the 0.12.0 API.
I am trying to follow the general workflow defined in the AMQP 1.0 spec 1) create a connection, 2) create a session, 3) create a sender link. I am not very experienced with C and this is my first time using the non-messenger part of the Qpid Proton library so forgive me if I missed something obvious. Here is my current code. I have been trying different options and searching for days.
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include "proton/message.h"
#include "proton/messenger.h"
#include "proton/connection.h"
#include "proton/session.h"
#include "proton/link.h"
#include "proton/delivery.h"
#include "proton/event.h"
#include "proton/engine.h"
//State integer values are defined in Connection macros
//https://qpid.apache.org/releases/qpid-proton-0.12.0/proton/c/api/group__connection.html
void print_state(char * name, pn_state_t state)
{
printf("[%s] local: %i, remote: %i\n", name, PN_LOCAL_MASK & state, PN_REMOTE_MASK & state);
}
//Reference https://github.com/apache/qpid-proton/blob/master/examples/engine/c/psend.c
void send_engine()
{
struct pn_connection_t * connection;
connection = pn_connection();
//STACKOVERFLOW - I have a feeling this is not right, but cannot find an alternative to set protocol (amqp or ws) the hostname and port. I see a way to set the hostname only
pn_connection_set_container(connection, "amqp://amqpserver:port");
print_state("Connection Initialized", pn_connection_state(connection));
pn_transport_t * transport;
transport = pn_transport();
int r = pn_transport_bind(transport, connection);
if (r != 0)
{
printf("transport bind error: %i\n", r);
}
pn_connection_open(connection);
print_state("Connection Opened", pn_connection_state(connection));
pn_session_t * sess;
sess = pn_session(connection);
print_state("Session Initialized", pn_session_state(sess));
pn_session_open(sess);
print_state("Session Opened", pn_session_state(sess));
pn_link_t * sender;
sender = pn_sender(sess, "c-client");
//the queue name in "toserver"
pn_terminus_set_address(pn_link_target(sender), "toserver");
print_state("Sender Link Initialized", pn_link_state(sender));
pn_link_open(sender);
print_state("Sender Link Opened", pn_link_state(sender));
pn_delivery_t *delivery;
char *tagID = "uid";
delivery = pn_delivery(sender, pn_dtag(tagID, strlen(tagID)));
char *msg = "abc";
printf("%zd\n", pn_link_send(sender, msg, strlen(msg)));
pn_delivery_settle(delivery);
printf("Delivery stettled %d\n", pn_delivery_settled(delivery));
print_state("Connection End", pn_connection_state(connection));
print_state("Session End", pn_session_state(sess));
print_state("Sender Link End", pn_link_state(sender));
//TODO free everything
}
int main (int argc, char *argv[])
{
send_engine();
printf("done\n");
return 0;
}
On my AMQP server I have enable frame level tracing and do not see any communication from the client. This is not a problem with the server. It works with many other clients, including a C client using the messenger API. What am I missing in this sample? Thank you!
Note: I have tried to solve this exhaustively and provided as much context as possible.
The driver API was removed in Apache Qpid Proton release 0.9 in March, 2015.
commit 4b53bfca06432e440c95d60648b5e7be54ae4296
Author: Rafael Schloming
Date: Fri Feb 13 08:27:23 2015 -0500
removed driver API and bindings
C code examples in Proton are Messenger based.
A lot of recent work has gone into a reactor-based C++ implementation that is not Messenger based. See release 0.12.1 documentation for more details and examples.
I am working on a game written in C using SDL. Given that it already uses SDL, SDL_image, and SDL_ttf, I decided to add SDL_mixer and SDL_net to my engine. Getting SDL_mixer set up and working was very easy, but I am having a lot of trouble with SDL_net.
To test I created a very simple application with the following rules:
Run without arguments act as a TCP server on port 9999
Run with an argument try to connect to the server at the given IP address on port 9999
Here are some of the key lines of the program (I'm not going to post my whole event-driven SDL engine because its too long):
char *host = NULL;
if (argc > 1) host = argv[1];
and...
IPaddress ip;
TCPsocket server = NULL;
TCPsocket conn = NULL;
if (host) { /* client mode */
if (SDLNet_ResolveHost(&ip,host,port) < 0)
return NULL; //this is actually inside an engine method
if (!(conn = SDLNet_TCP_Open(&ip)))
return NULL;
} else { /* server mode */
if (SDLNet_ResolveHost(&ip,NULL,port) < 0)
return NULL;
if (!(server = SDLNet_TCP_Open(&ip)))
return NULL;
}
and... inside the event loop
if (server) {
if (!conn)
conn = SDLNet_TCP_Accept(server);
}
if (conn) {
void *buf = malloc(size); //server, conn, size are actually members of a weird struct
while (SDLNet_TCP_Recv(conn,buf,size))
onReceive(buf); //my engine uses a callback system to handle things
free(buf);
}
The program seems to start up just fine. However for some reason when I run it in client mode trying to connect to my home computer (which I have on a different IP) from my laptop I find that the call to SDLNet_TCP_Open blocks the program for awhile (5-10 seconds) then returns NULL. Can anybody see what I did wrong? Should I post more of the code? Let me know.