Due to the variable length nature of the notification message, it is necessary to provide the ctSysQueueRead() function with a buffer large enough to contain the entire message; otherwise, the ctSysQueueRead() call will fail with error TQUE_ERR (638) and the message is not read.
When not requesting any optional values (contents set to 0 in ctNotify() call), the notification message length is fixed and the notification message size is sizeof(ctNOTBLK).
When requesting optional information, the message length size can be either retrieved by calling ctSysQueueMlen() or evaluated by adding to the fixed message length the lengths of each option requested as described in the following table.
ctNotify contents parameter |
Message length |
---|---|
ctNT_CON_UNQKEY |
+ 2* sizeof(COUNT) + If the size in bytes (keylen) of the key of the first unique index in your IFIL is known: 2* keylen Else MAXLEN, which is the maximum key length supported by FairCom DB |
ctNT_CON_NODNAME |
+ 32 |
ctNT_CON_RECBUF |
+ sizeof(LONG) + If the record is a fixed length record: record_length If the record is variable-length and you know that there is a maximum record size: max_record_size Else there is no way to guarantee that the message is large enough and ctSysQueueMlen() should be used. |
For instance, suppose that contents is ctNT_CON_UNQKEY | ctNT_CON_RECBUF and the key length is not known and the record length is fixed to 40, then the message length will be:
sizeof(ctNOTBLK) + 2 * sizeof(COUNT) + 2 * MAXLEN + sizeof(LONG) + 40
If the message length is known or can be estimated, a notification message can be read by passing the address of a buffer, whose size is greater or equal to the message size, the buffer size and the timeout value to ctSysQueueRead(),. For example:
NINT qhandle; /* Set by call to ctSysQueueOpen */
NINT rc;
pTEXT buffer;
buffer = (pTEXT) malloc (msglen);
/* Read next available queue message with 5 second timeout. */
rc = ctSysQueueRead(qhandle,buffer,msglen,5000);
If the message length is not known, it is necessary to determine the size with a call to ctSysQueueMlen(). This function takes the queue handle and an optional timeout, so it can be used to wait until the next message is available in the queue and to determine the size of the message. After determining the message size, allocate a sufficiently-sized buffer and pass its address and size to ctSysQueueRead(). For example:
NINT qhandle; /* Set by call to ctSysQueueOpen */
NINT rc;
NINT msglen;
pTEXT pbuffer;
/* Read size of next available queue message with 5 second timeout. */
msglen = ctSysQueueMlen(qhandle,5000);
/* Allocate buffer to hold queue message. */
pbuffer = (pTEXT)malloc(msglen);
/* Read next available queue message. */
rc = ctSysQueueRead(qhandle,pbuffer,msglen,0);
The following code demonstrates how to extract information from the message read from a notification queue.
Notification Queue Example
COUNT ProcessQueueMessage (pTEXT buff) /* buff is a pointer to the message */
{
/* cast the buffer to a ctNOTBLK structure */
/* in order to make easier to extract the */
/* information in the fixed portion */
pctNOTBLK pnotblk = (pctNOTBLK)buff;
/* set info to point at the beginning of the */
/* variable-length part */
pTEXT info = buff + sizeof(ctNOTBLK);
ctrt_printf("action actor tranlw opcode objhandle contents
controls datalw varlen\n");
ctrt_printf("%8d %5d %6d %6d %9d %8d %8d %6d %6d\n",
pnotblk->action, pnotblk->actor, pnotblk->tranlw, pnotblk->opcode,
pnotblk->objhandle, pnotblk->contents, pnotblk->controls,
pnotblk->datalw, pnotblk->varlen);
/* if the action is ctNT_CLSOBJ return */
if (pnotblk->action == ctNT_CLSOBJ)
return (1);
/* if contents contains ctNT_CON_UNQKEY there */
/* is unique key information to extract */
if (pnotblk->contents & ctNT_CON_UNQKEY)
{
FILNO rkeyno;
COUNT keylen;
/* extract relative index number */
cpybuf(&rkeyno, info, 2);
/* step over the index number */
info += 2;
/* extract the key length */
cpybuf(&keylen, info, 2);
/* step over the key length */
info += 2;
ctrt_printf("Unique Key:\n");
ctrt_printf("\tIndex number (relative) %d\n",rkeyno);
ctrt_printf("\tkeylen %d\n",keylen);
/* your key value handling here */
/* the key starts at the memory pointed by info */
/* and its length is keylen */
/* skip over the key */
info += keylen;
/* if the action is ctNT_RWTREC there is also */
/* the old key value to retrieve */
if (pnotblk->action == ctNT_RWTREC)
{
/* your key handling code here */
/* skip over the key */
info += keylen;
}
}
else
{
ctrt_printf("Unique Key [NOT REQUESTED]\n");
}
/* if contents contains ctNT_CON_NODNAM there */
/* is a node name information to extract */
if (pnotblk->contents & ctNT_CON_NODNAM)
{
/* print the node name that is pointed */
/* by info */
ctrt_printf("Node Name: %s\n",info);
/* skip over the nodename */
info += 32;
}
else
{
ctrt_printf("Node Name [NOT REQUESTED]\n");
}
/* if contents contains ctNT_CON_RECBUF */
/* there is a record image to extract */
if (pnotblk->contents & ctNT_CON_RECBUF)
{
LONG notrln;
/* extract the record length */
cpybuf(¬rln, info, 4);
/* skip over */
info += 4;
ctrt_printf("Record Buffer Length: %d\n",notrln);
/* your record buffer handling here */
/* the record buffer starts at info */
/* and is notrln bytes long */
info += notrln;
}
else
{
ctrt_printf("Record Buffer [NOT REQUESTED]\n");
}
/* sanity check to verify that we reached */
/* the end of the message */
if ((buff + sizeof(ctNOTBLK) + pnotblk->varlen) != info)
{
ctrt_printf("Message parsing problem\n");
}
return (0);
}