[SOLVED] Strange behavior of cdb_subscribe() - hangs, crashes etc

I develop a module that uses both Data Provider and CDB APIs.

Most of code for now is copied from examples, user guide and kick start guide, so I don’t see a reason to repeat it all here. But I can not get these APIs to work together.

If I initialize subscriptions first, I get:
TRACE Connected (maapi) to ConfD
TRACE MAAPI_LOAD_ALL_NS
TRACE MAAPI_LOAD_HASH_DB
Connecting…
TRACE Connected (dp) to ConfD
Subscribing…
TRACE CDB_SUBSCRIBE /framerDEBUG EOF on socket to ConfD
–> CONFD_EOF
cdb_subscribe() failed
No other error messages are shown. CLI does not even show a subsystem start message.

Then I try to initialize control/worker sockets first and get this:
TRACE Connected (maapi) to ConfD
TRACE MAAPI_LOAD_ALL_NS
TRACE MAAPI_LOAD_HASH_DB
TRACE Connected (dp) to ConfD
TRACE Received daemon id 23
TRACE Connected (dp) to ConfD
TRACE Picked up old user session: 30 for user:root ctx:cli
TRACE Picked up old user session: 26 for user:system ctx:system
TRACE Picked up old user session: 25 for user:system ctx:system
TRACE Picked up old user session: 24 for user:system ctx:system
TRACE Picked up old user session: 23 for user:system ctx:system
TRACE Picked up old user session: 22 for user:system ctx:system
TRACE Picked up old user session: 21 for user:system ctx:system
TRACE Picked up old user session: 20 for user:system ctx:system
TRACE Picked up old user session: 19 for user:system ctx:system
TRACE Picked up old user session: 18 for user:system ctx:system
TRACE Picked up old user session: 17 for user:system ctx:system
TRACE Picked up old user session: 16 for user:system ctx:system
TRACE Picked up old user session: 15 for user:system ctx:system
TRACE Picked up old user session: 14 for user:system ctx:system
TRACE Picked up old user session: 13 for user:system ctx:system
TRACE Picked up old user session: 12 for user:system ctx:system
TRACE Picked up old user session: 11 for user:system ctx:system
TRACE Picked up old user session: 10 for user:system ctx:system
TRACE Picked up old user session: 9 for user:system ctx:system
TRACE Picked up old user session: 1 for user:system ctx:system
Connecting…
TRACE Connected (dp) to ConfD
Subscribing…
TRACE CDB_SUBSCRIBE /framer
And deadlock here. cdb_subscribe() just does not return control ever.
I see a subsystem start message in CLI, but no interaction with this subsystem is possible, even operational data does not work.

If I comment out all subscription stuff from my code, all works fine.

I found this topic, but it seems to be related to some older version of confd (no daemon context in cdb_connect() etc) and does not solve my issue.

Any suggestions? Thanks in advance.

Perhaps you are trying to use the same socket for your data providers and subscribers? You need one socket per thread. No sharing of sockets between threads.

From ConfD UG chapter The Protocol and a Library Threads Discussion:

ConfD API functions are thread-safe as such, but multiple threads using them with the same socket will have unpredictable results, just as multiple threads using the read() and write() system calls on the same file descriptor in general will. In the ConfD case, one thread may end up getting the response to a request from another, or even a part of that response, which will result in errors that can be very difficult to debug.

Nope, three different sockets, and fourth one in read_conf(). As I said, most code is copied from UG.

I believe your issues are copy paste errors in both cases,

TRACE CDB_SUBSCRIBE /framerDEBUG EOF on socket to ConfD
–> CONFD_EOF

The socket you did a cdb_subscribe() on was likely connected as a DP worker socket using confd_connect(.., my_subscriber_socket, WORKER_SOCKET, ..., ...)

TRACE CDB_SUBSCRIBE /framer
And deadlock here. cdb_subscribe() just does not return control ever.

The socket you did a cdb_subscribe() on was likely connected as a DP control socket using confd_connect(..., my_subscriber_socket, CONTROL_SOCKET, ..., ...)

You need to connect your subscriber socket using cdb_connect(my_subscriber_socket, CDB_SUBSCRIPTION_SOCKET, ... , ...)

static int ctlsock;
static int workersock;
static int cdbsubsock;

// ==== Common initialization of ConfD library
confd_init("scpc_daemon", stderr, debuglevel);
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
addr.sin_family = AF_INET;
addr.sin_port = htons(CONFD_PORT);
if ((dctx = confd_init_daemon("scpc_daemon")) == NULL) {
    confd_fatal("Failed to initialize confdlib\n");
}
if (confd_load_schemas((struct sockaddr*)&addr, sizeof (struct sockaddr_in)) != CONFD_OK) {
    confd_fatal("Failed to load schemas from confd\n");
}
// ==== Data provider stuff
// Create control socket
if ((ctlsock = socket(PF_INET, SOCK_STREAM, 0)) < 0 ) {
    confd_fatal("Failed to open ctlsocket\n");
}
if (confd_connect(dctx, ctlsock, CONTROL_SOCKET, (struct sockaddr*)&addr, sizeof (struct sockaddr_in)) < 0) {
    confd_fatal("Failed to confd_connect() to confd \n");
}

// Create worker socket
if ((workersock = socket(PF_INET, SOCK_STREAM, 0)) < 0 ) {
    confd_fatal("Failed to open workersocket\n");
}
if (confd_connect(dctx, workersock, WORKER_SOCKET,(struct sockaddr*)&addr, sizeof (struct sockaddr_in)) < 0) {
    confd_fatal("Failed to confd_connect() to confd \n");
}

// Register callbacks and complete context
if (confd_register_trans_cb(dctx, &trans) == CONFD_ERR) {
    confd_fatal("Failed to register trans cb \n");
}
if (confd_register_data_cb(dctx, &data) == CONFD_ERR) {
    confd_fatal("Failed to register data cb \n");
}
if (confd_register_done(dctx) != CONFD_OK) {
    confd_fatal("Failed to complete registration \n");
}

// ==== CDB access stuff
// Create CDB subscriber socket
if ((cdbsubsock = socket(PF_INET, SOCK_STREAM, 0)) < 0 ) {
    confd_fatal("Failed to open CDB subscriber socket\n");
}
fprintf(stderr, "Connecting...\n");
if (confd_connect(dctx, cdbsubsock, CDB_SUBSCRIPTION_SOCKET,(struct sockaddr*)&addr, sizeof(struct sockaddr_in)) < 0) {
    confd_fatal("Failed to confd_connect() to confd \n");
}

// First read of configuration
// read_conf(&addr, CDB_RUNNING);

// Subscribe to CDB keypaths
fprintf(stderr, "Subscribing...\n");
if (cdb_subscribe(cdbsubsock, 3, satcloud_dev_rev1__ns, &framer_spoint, "/framer") != CONFD_OK) {
    confd_fatal("cdb_subscribe() failed");
}
fprintf(stderr, "Subscribed\n");
if (cdb_subscribe_done(cdbsubsock) != CONFD_OK) {
    confd_fatal("cdb_subscribe_done() failed");
}
fprintf(stderr, "Subscribe finished\n");

Should be cdb_connect(cdbsubsock, CDB_SUBSCRIPTION_SOCKET,(struct sockaddr*)&addr, sizeof(struct sockaddr_in))

Use confd_connect() for the DP API and cdb_connect() for the CDB API.

Easy to miss, done it myself a few times :wink:

1 Like

True.
I made a really silly mistake. Even Homer sometimes nods.
Thanks for help.