I'm working on a C application that is suppose to talk to PostgreSQL. Right now I need to handle notices and warnings sent by the server but I'm at a loss on how to make it work.
The (very unclear) documentation says we should use PQsetNoticeReceiver to set a method as the receiver of notifications, as the default receiver just forwards the notification to PQnoticeProcessor and this prints to stderr.
I've defined a method thus
static void noticeReceiver(void *arg, const PGresult *res)
and I'm setting it as the default notice receiver on startup thus
PQsetNoticeReceiver(conn, noticeReceiver, NULL);
In my method implementation I'm simply printing some random characters to screen but it doesn't get called. Step by step debugging shows that its being set as the default notice receiver but its never called.
Any ideas?
The only way I could see it not working is if you change the connection after setting the receiver. Keep in mind that the receiver is a parameter of the connection, so if you disconnect and reconnect it would go away.
This works:
#include "libpq-fe.h"
static void myrecv(void *arg, const PGresult *res);
int main() {
PGconn *conn;
PGresult *res;
conn = PQconnectdb("");
if (PQstatus(conn) == CONNECTION_BAD)
{
printf("connection error: %s\n",
PQerrorMessage(conn));
return -1;
}
PQsetNoticeReceiver(conn, myrecv, NULL);
res = PQexec(conn, "select noisy_func();");
if (PQresultStatus(res) == PGRES_FATAL_ERROR)
printf("%s: error: %s\n",
PQresStatus(PQresultStatus(res)),
PQresultErrorMessage(res));
return 0;
}
static void
myrecv(void *arg, const PGresult *res)
{
printf("hey, got a notice saying \"%s\"\n",
PQresultErrorField(res,
PG_DIAG_MESSAGE_PRIMARY));
}
Related
I am experimenting with libmosquitto-dev on Raspbian and having some issues.
My code works absolutely fine so far. I can connect to a broker and once the topic gets an update my programm prints the message as it should.
It's just the point when the broker dies after connection and gets restarted.
My code realize the connection dropped and tries to reconnect. Once the broker is back online my code reconnects. But from this on it does not print any updates on the channel.
Why not? I thought this would catch up the connection fine, but it does not.
Her's my code:
[...]
static int run = 1;
void connect_callback(struct mosquitto *mosq, void *obj, int result)
{
printf("connect callback, rc=%d\n", result);
}
void message_callback(struct mosquitto *mosq, void *obj, const struct mosquitto_message *message)
{
bool match = 0;
printf("got message '%.*s' for topic '%s'\n", message->payloadlen, (char*) message->payload, message->topic);
mosquitto_topic_matches_sub("Heizung", message->topic, &match);
if (match) {
printf("got message for HEIZUNG topic\n");
}
}
int main(int argc, char *argv[])
{
uint8_t reconnect = true;
char clientid[24];
struct mosquitto *mosq;
int rc = 0;
mosquitto_lib_init();
memset(clientid, 0, 24);
snprintf(clientid, 23, "mylog_%d", getpid());
mosq = mosquitto_new(clientid, true, 0);
if(mosq){
mosquitto_connect_callback_set(mosq, connect_callback);
mosquitto_message_callback_set(mosq, message_callback);
rc = mosquitto_connect(mosq, mqtt_host, mqtt_port, 60);
mosquitto_subscribe(mosq, NULL, "Heizung", 0);
// rc = mosquitto_loop_forever(mosq,20,5); // Tried with this function but same issue.
while(run){
rc = mosquitto_loop(mosq, -1, 1);
if(run && rc){
printf("connection error!\n");
sleep(10);
mosquitto_reconnect(mosq);
}
}
mosquitto_destroy(mosq);
}
mosquitto_lib_cleanup();
return rc;
}
What I see as output is the following:
connect callback, rc=0
got message 'ON1' for topic 'Heizung'
got message for Heizung topic
got message 'ON2' for topic 'Heizung'
got message for Heizung topic
got message 'ON3' for topic 'Heizung'
got message for Heizung topic
connection error!
connect callback, rc=0
You see the connection error (where "systemctl stop mosquitto" took place). And you see reconnection appears to be successful once the broker is back again. But it does not print any of the new messages which are send by the subscriber after the broker is back. Running the mosquitto_sub command in parallel sees all messages!
Any idea what is wrong here?
Thanks a lot!
/KNEBB
Move the call to mosquitto_subscribe to the connect_callback that way it will get called on a reconnect.
Since you are connecting with the CleanSession flag set to true each time you reconnect there will be no persistent session so the broker will not know to keep the subscription.
I'm doing a multiplatform shared library in C, which sends UDP messages using libuv, however I don't know much about libuv and I don't know if my implementation is good, or if there is another solution besides libuv.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <uv.h>
#define IP "0.0.0.0"
#define PORT 8090
#define STR_BUFFER 256
void on_send(uv_udp_send_t *req, int status) {
if (status) {
fprintf(stderr, "Send error %s\n", uv_strerror(status));
return;
}
}
int send_udp(char *msg){
uv_loop_t *loop = malloc(sizeof(uv_loop_t));
uv_loop_init(loop);
uv_udp_t send_socket;
uv_udp_init(loop, &send_socket);
struct sockaddr_in send_addr;
uv_ip4_addr(IP, PORT, &send_addr);
uv_udp_bind(&send_socket, (const struct sockaddr*)&send_addr, 0);
char buff[STR_BUFFER];
memset(buff,0,STR_BUFFER);
strcpy(buff,msg);
uv_buf_t buffer = uv_buf_init(buff,STR_BUFFER);
uv_udp_send_t send_req;
uv_udp_send(&send_req, &send_socket, &buffer, 1, (const struct sockaddr*)&send_addr, on_send);
uv_run(loop, UV_RUN_ONCE);
uv_loop_close(loop);
free(loop);
return 0;
}
int main() {
send_udp("test 123\n");
return 0;
}
Your implementation has multiple issues to date:
I'm not sure a single loop iteration is enough to send an UDP message on every platform. This is something you can check easily with the value returned by uv_run, see the documentation for uv_run when using the UV_RUN_ONCE mode:
UV_RUN_ONCE: Poll for i/o once. Note that this function blocks if there are no pending callbacks. Returns zero when done (no active handles or requests left), or non-zero if more callbacks are expected (meaning you should run the event loop again sometime in the future).
If you would keep your code as-is, I would suggest to do at least this:
int done;
do {
done = uv_run(loop, UV_RUN_ONCE);
} while (done != 0);
But keep on reading, you can do even better ! :)
It's quite costly in terms of performance, uv_loops are supposed to be long lasting, not to be created for each message sent.
Incomplete error handling: uv_udp_bind, uv_udp_send, ... they can fail !
How to improve
I would suggest you to change your code for one of the two following solutions:
Your library is used in a libuv context (a.k.a, you don't try to hide the libuv implementation detail but require all people who wish to use your library to use libuv explicitly.
You could then change your function signature to something like int send_udp(uv_loop_t *loop, char *msg) and let the library users manage the event loop and run it.
Your library uses libuv as an implementation detail: you don't want to bother your library users with libuv, therefore its your reponsibility to provide robust and performant code. This is how I would do it:
mylib_init: starts a thread and run an uv_loop on it
send_udp: push the message on a queue (beware of thread-safety), notify your loop it has a message to send (you can use uv_async for this), then you can send the message with approximately the same code you are already using.
mylib_shutdown: stop the loop and the thread (again, you can use an uv_async to call uv_stop from the right thread)
It would look like this (I don't have a compiler to test, but you'll have most of the work done):
static uv_thread_t thread; // our network thread
static uv_loop_t loop; // the loop running on the thread
static uv_async_t notify_send; // to notify the thread it has messages to send
static uv_async_t notify_shutdown; // to notify the thread it must shutdown
static queue_t buffer_queue; // a queue of messages to send
static uv_mutex_t buffer_queue_mutex; // to sync access to the queue from the various threads
static void thread_entry(void *arg);
static void on_send_messages(uv_async_t *handle);
static void on_shutdown(uv_async_t *handle);
int mylib_init() {
// will call thread_entry on a new thread, our network thread
return uv_thread_create(&thread, thread_entry, NULL);
}
int send_udp(char *msg) {
uv_mutex_lock(&buffer_queue_mutex);
queue_enqueue(&buffer_queue, strdup(msg)); // don't forget to free() after sending the message
uv_async_send(¬ify_send);
uv_mutex_unlock(&buffer_queue_mutex);
}
int mylib_shutdown() {
// will call on_shutdown on the loop thread
uv_async_send(¬ify_shutdown);
// wait for the thread to stop
return uv_thread_join(&thread);
}
static void thread_entry(void *arg) {
uv_loop_init(&loop);
uv_mutex_init_recursive(&buffer_queue_mutex);
uv_async_init(&loop, ¬ify_send, on_send_messages);
uv_async_init(&loop, ¬ify_shutdown, on_shutdown);
uv_run(&loop, UV_RUN_DEFAULT); // this code will not return until uv_stop is called
uv_mutex_destroy(&buffer_queue_mutex);
uv_loop_close(&loop);
}
static void on_send_messages(uv_async_t *handle) {
uv_mutex_lock(&buffer_queue_mutex);
char *msg = NULL;
// for each member of the queue ...
while (queue_dequeue(&buffer_queue, &msg) == 0) {
// create a uv_udp_t, send the message
}
uv_mutex_unlock(&buffer_queue_mutex);
}
static void on_shutdown(uv_async_t *handle) {
uv_stop(&loop);
}
It's up to you to develop or find a queue implementation ;)
Usage
int main() {
mylib_init();
send_udp("my super message");
mylib_shutdown();
}
I have two simple programs: a client and a server. I'm trying to use zstr_sendfm and zstr_recv to send and receive a simple string. Roughly speaking, I'm using the code from the file transfer test in the zeromq tutorial. Here's the server function:
#define PIPELINE = 10;
int server()
{
char *name = "someName";
zctx_t *ctx = zctx_new();
void *router = zsocket_new(ctx, ZMQ_ROUTER);
zsocket_set_hwm(router, PIPELINE*2);
if (0 == zsocket_connect(router, tcp://127.0.0.1:6000))
{
printf("failed to connect to router.\n");
}
printf( "sending name %s\n, name);
zstr_sendfm( router, name );
return 0;
}
Here's the client function:
int client()
{
zctx_t *ctx = zctx_new ();
void *dealer = zsocket_new (ctx, ZMQ_DEALER);
zsocket_bind(dealer, "tcp://*:6000")
char *receivedName = zstr_recv( dealer );
printf("received the following name: %s\n", receivedName);
return 0
}
Both of these are run in two separate programs (which do nothing other than run their respective functions) on the same computer.
Here's how things always play out:
Start client function, which holds at "zstr_recv" as it's supposed to
Start server function, which connects successfully, claims to have sent the data, and exits
Client function continues to sit and wait, but claims to have not received anything from the server.
What am I missing here? I've added a bunch of error checking and even tried this out in gdb with no luck.
Help and advice appreciated.
I think you have your client and server mixed up, although in ZeroMQ client and server is not as strict as with normal sockets. Normally you would create a server with a REP socket that binds/receives/sends and a client with a REQ socket that connects/sends/receives. You should try this first and then experiment with ROUTER for the server (instead of REP) and DEALER for the client (instead of REQ).
I'm trying to use czmq, the first test was ok with the inproc protocol and if the "puller" and the "pusher" in the same program.
But I want to use it on different processus, I also tried ipc and tcp, and I can not achieve to make communicate the server and the client.
The server:
#include <czmq.h>
int main (void)
{
zctx_t *ctx = zctx_new ();
void *reader = zsocket_new (ctx, ZMQ_PULL);
int rc = zsocket_connect (reader, "tcp://localhost:5555");
printf("wait for a message...\n");
char *message = zstr_recv (reader);
printf("Message: %s",message);
zctx_destroy (&ctx);
return 0;
}
and the client:
#include <czmq.h>
int main (void)
{
zctx_t *ctx = zctx_new ();
void *writer = zsocket_new (ctx, ZMQ_PUSH);
int rc = zsocket_bind (writer, "tcp://*:5555");
assert (rc == service);
zstr_send (writer, "HELLO");
zsocket_destroy (ctx, writer);
return 0;
}
Could you tell me what is wrong with my code. I have also tried other sample codes found, but without more success.
Update
The server is waiting for messages in zstr_recv, but the messages send by the client triggers nothing on the server process.
After sending the message, the client process is destroying the socket too quickly. With inproc, you "get away with it" because inproc is fast, while TCP has to go through more hurdles before the message gets to the TCP stack.
It is true that zsocket_destroy() should block until the message is sent, if ZMQ_LINGER = -1 (the default with raw ZMQ), but the default linger for CZMQ is 0. That means dropping in-transit messages when the socket is destroyed.
Try setting the linger (with zctx_set_linger) to something bigger than zero; 10ms perhaps, but use whatever value is good for you.
Here's the situation. I'm debugging a code to do a logging function. When the user log in, the log file will be create with .part format. This file is save locally inside the host. I do not know why it's name as .part. When the user finish their session, the log file will be rename as .username only. Beside the local log file, this code is also connected to a server where this server will also save the logging file. The problem is when the logging is still running, but the host suddenly reboot. The reboot might be caused by command from root, or a force reboot, or maybe a hardware fault. This causes the logging file to stay as .part and the server also follows.
So, my question is:
How to make it rename the file before the process is killed or terminated during reboot?
Whats the signal that I should handle?
I'm thinking this might involve a race condition, is there a way for me to delay the reboot?
My approach
tried to handle SIGPWR,SIGSTOP,SIGTERM,SIGQUIT
create a bash script to do renaming when the process start.
Here is the main code:
int main(int argc, char **argv)
{
int ch;
int NoFork = 0;
struct event_config *evconfig;
struct event *signal_event_int;
struct event *signal_event_quit;
struct event *signal_event_term;
struct event *signal_event_hup;
struct event *signal_event_chld;
struct event *signal_event_pwr;
struct event *signal_event_stop;
syspath_init_from_argv0(argv[0]);
load_config(); /* load config first, the command line parameters will override */
event_set_log_callback(my_event_log_cb);
evconfig = event_config_new();
if (event_config_require_features(evconfig, EV_FEATURE_FDS)!=0) {
log_error("event_config_require_features_failed");
}
while (!done) {
/* ignore HUP first, just in case someone send us a HUP
when we are reloading config, that will create a condition
that makes us exit, with HangUp */
sig_catch(SIGHUP,SIG_IGN);
base = event_base_new_with_config(evconfig);
local_listener = create_local_listener(base);
if (!local_listener) {
log_error("Could not create a local listener!");
return 1;
}
http_listener = create_http_listener();
if (!http_listener) {
log_error("Could not create a remote listener!");
return 1;
}
evhttp_set_cb(http_listener, "/mrexec", http_mrexec_cb, NULL);
if (options.accept_remote) {
evhttp_set_cb(http_listener, "/rlog", http_rlog_cb, NULL);
}
if (pidfile_create(ACTSLOGD_PIDFILE)==-1) {
log_error("pidfile_create:failed:%d:%s", errno, strerror(errno));
}
LIST_INIT(&clientlist);
if (options.log_remote) {
start_log_remote();
}
signal_event_int = evsignal_new(base, SIGINT, exit_cb, (void *)base);
event_add(signal_event_int, NULL);
signal_event_quit = evsignal_new(base, SIGQUIT, exit_cb, (void *)base);
event_add(signal_event_quit, NULL);
signal_event_term = evsignal_new(base, SIGTERM, exit_cb, (void *)base);
event_add(signal_event_term, NULL);
signal_event_hup = evsignal_new(base, SIGHUP, reload_config_cb, (void *)base);
event_add(signal_event_hup, NULL);
signal_event_chld = evsignal_new(base, SIGCHLD, sigchld_cb, (void *)base);
event_add(signal_event_chld, NULL);
signal_event_pwr = evsignal_new(base, SIGPWR, power_off_cb, (void *)base);
event_add(signal_event_pwr, NULL);
signal_event_stop = evsignal_new(base, SIGSTOP, power_off_cb, (void *)base);
event_add(signal_event_chld, NULL);
actslog_event_start(AGENT_ACTSLOGD);
actslog_event_start(AGENT_ESCALATED);
event_base_dispatch(base);
printf("finished dispatch\n");
evconnlistener_free(local_listener);
evhttp_free(http_listener);
http_listener = NULL;
event_free(signal_event_int);
event_free(signal_event_quit);
event_free(signal_event_term);
event_free(signal_event_hup);
event_free(signal_event_pwr);
event_free(signal_event_stop);
if (options.log_remote) {
end_log_remote();
}
event_base_free(base);
if (!done) {
load_config();
}
while (clientlist.lh_first != NULL) {
struct bufferevent *bev = clientlist.lh_first->bev;
bufferevent_free(bev);
LIST_REMOVE(clientlist.lh_first, clients);
}
}
if (rlog) {
rlog_close(rlog);
}
unlink(PATH_ACTSLOG);
pidfile_cleanup(ACTSLOGD_PIDFILE);
return 0;
}
This is the signal handler
static void exit_cb(evutil_socket_t sig, short events, void *user_data)
{
struct event_base *base = user_data;
struct timeval delay = { 2, 0 };
actslog_event_stop(AGENT_ACTSLOGD);
actslog_event_stop(AGENT_ESCALATED);
done = 1; //when this is 1, there is a function that will connect to the server to tell that the logging is stopped.
/* need to give some delay for us to send out the stop message to Logger */
event_base_loopexit(base, &delay);
}
static void power_off_cb(evutil_socket_t sig, short events, void *user_data)
{
struct event_base *base = user_data;
struct timeval delay = { 5, 0 };
char logfile_partial[MAXPATHLEN];
char logfile_complete[MAXPATHLEN];
char id[1024];
done =1;
event_base_loopexit(base,&delay);
snprintf(logfile_partial, //the logfile_partial will be the one with .part file
sizeof(logfile_partial),
"%s/SHELL.%s.part", logpath2, id);
snprintf(logfile_complete, //the logfile_complete will be the complete without .part
sizeof(logfile_complete),
"%s/SHELL.%s", logpath2, id);
if (rename(logfile_partial, logfile_complete)!=0) {
if (errno==ENOENT) {
int tmp;
log_error("mastershell [%s] log is incomplete", logfile_complete);
tmp = creat(logfile_complete, LOG_FILE_MODE);
if (tmp==-1) {
log_error("creat:%s:failed:%d:%s!!\n", logfile_complete, errno, strerror(errno));
} else {
close(tmp);
}
} else {
log_error("rename:%s:%s:failed:%d:%s!!\n", logfile_partial, logfile_complete, errno, strerror(errno));
}
}
if (rlog) {
rlog_close(rlog);
}
unlink(PATH_ACTSLOG);
pidfile_cleanup(ACTSLOGD_PIDFILE);
}
I have tested to handle all signal in exit_cb function. Also all signals inside power_off_cb function. Neither one of them works. I have tested on CentOS and Ubuntu. The logging process is a upstart process. Any comment or suggestion are really appreciated.
Here's the situation. I'm debugging a code to do a logging function.
When the user log in, the log file will be create with .part format.
This file is save locally inside the host. I do not know why it's name
as .part. When the user finish their session, the log file will be
rename as .username only. Beside the local log file, this code is also
connected to a server where this server will also save the logging
file. The problem is when the logging is still running, but the host
suddenly reboot. The reboot might be caused by command from root
If it is caused by a command from root you can handle it creating a script in /etc/init.d/.
, or a
force reboot, or maybe a hardware fault. This causes the logging file
to stay as .part and the server also follows.
You can't predict the future, neither the OS. If there is a reboot caused by a power or hardware failure there is no way to predict it.