Wednesday, May 16, 2012

Understanding Message Queues in Linux

Many times we see Inter Process Communication happening in our applications and amongst the big list, one of them is Message Queues.

Here is an attempt to help understand how you can create and use your own message queue.


A Message queue is used to transmit "messages" over the IPC between processes. To achieve this, we first need to 'create' the message queue and then 'send' from one process and 'receive' at the other end.

Lets see how we create a message queue.

mqd_t mq_open(const char *name, int oflag);
mqd_t mq_open(const char *name, int oflag, mode_t mode,
                     struct mq_attr *attr);
Ex:
MQDes = mq_open(MQName, O_RDWR|O_CREAT|O_EXCL, 777, NULL);

Once you have created your message queue and kept it 'open' to write, you are now ready to 'send' your message.

int mq_send(mqd_t mqdes, const char *msg_ptr, size_t msg_len, unsigned msg_prio);

Ex:
ret = mq_send(MQDes, Message, sizeof(Message), MESSAGE_PRIO);

With this, the server is ready to send messages on the queue.

At the client end, we now need to 'receive' the message.

ssize_t mq_receive(mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned *msg_prio); 

Ex:
NoOfBytesRx = mq_receive(MQDes, Message, (MQStat.mq_msgsize) , MESSAGE_PRIO);

Make sure you have opened the same message queue in read mode in the client.

These three calls will help you accomplish the Message Queue you intended to create. 

You might have noticed the 'MQStat.mq_msgsize' in the mq_receive call. Now where did that come from. 

int mq_getattr(mqd_t mqdes, struct mq_attr *attr); 
int mq_setattr(mqd_t mqdes, struct mq_attr *newattr, struct mq_attr *oldattr);

Ex:
ret = mq_getattr(MQDes, &MQStat);

Once you are done, you can close & unlink the message queue with the below calls.

int mq_close(mqd_t mqdes);
Ex:
ret = mq_close(MQDes);

int mq_unlink(const char *name);
Ex:
ret = mq_unlink(MQName);


You might want the client to receive the message only when there is a notification for a new message waiting on the queue. You can subscribe to this with the notify call.

int mq_notify(mqd_t mqdes, const struct sigevent *sevp);

Ex:
SIGNAL.sigev_notify = SIGEV_THREAD;
SIGNAL.sigev_notify_function = RxMessage;
SIGNAL.sigev_notify_attributes = NULL;
ret = mq_notify(MQDes, &SIGNAL);


We are now familiar with all the calls required to make a message queue.

With this information you should be able to successfully write your first Message Queue and test.

Here are some possible caveats that you might fall into.

  • When you create a new Queue, make sure you use the correct prototype. You need to provide the mode & attributes. If you give NULL as the attribute, you accept the default attributes.
  • Make sure you add the "\" in the queue name. ex:"/MQServer"
  • In the mq_receive call, you might run into issues with the message size. It is always advisable to do a 'getattr' and accordingly set the size for receiving. 
  • Unless otherwise stated, the message queue will be in Blocking mode. If you need it to be non-blocking use the O_NONBLOCK flag during open/create.
  • You need to register mq_notify for every message that you receive. Otherwise, after processing the first message, the notification will stop.
  • Note that once the message is consumed from the queue, it is no longer available in the queue and there is no way of reading it back.

Sample Code
Server :

Client:


 
 


Tuesday, March 13, 2012

How to create a dynamic library with symbols hidden. "-fvisibility"


The requirement is you need to provide a .so to the application exposing only your new symbols and not the symbols of the other .o/.so files that you might have used in creating your file.

Lets see an example of how to do it.

The ace card we use for this game is the gcc flag "-fvisibility=hidden".

Lets create a lib1.o which will serve as the .o that we want to include into our new file. After that we create a lib2.o that provides a wrapper (lib2_fun2) around the function (lib1_fun1) that we want to provide to the application. Finally we test this concept with a test application where we will call all the functions to check their visibility/ availability at this layer.


Step 1:

lib1.c : Function with Default visibility, built with hidden visibility.

void /*__attribute__ ((visibility ("default")) )*/ lib1_fun1(void);

void /*__attribute__ ((visibility ("default")) )*/ lib1_fun1(void)
{
    printf("%s\n",__FUNCTION__);
}


$ gcc -fvisibility=hidden -fPIC -Wall -c lib1.c

$ readelf -s lib1.o | grep fun
    Num:    Value  Size Type    Bind   Vis      Ndx Name
    12: 00000000    38 FUNC    GLOBAL HIDDEN     2 lib1_fun1

Notice the Vis column saying "HIDDEN". :-) wasn't that what we wanted.
---------------------------------------------------------------------------------
Step 2:

lib2.c : Function _fun1 with hidden visibility & _fun2 with Default visibility, file built with hidden visibility.

void __attribute__ ((visibility ("hidden")) ) lib2_fun1(void);
void __attribute__ ((visibility ("default")) ) lib2_fun2(void);

void __attribute__ ((visibility ("default")) ) lib2_fun2(void)
{
    printf("%s is calling ",__FUNCTION__);
    lib1_fun1(); //This is the function we want to wrap and provide functionality to outside world
}

$ gcc -fvisibility=hidden -fPIC -Wall -c lib2.c

$ readelf -s lib2.o | grep fun
    Num:    Value  Size Type    Bind   Vis      Ndx Name
    13: 00000000    38 FUNC    GLOBAL HIDDEN     2 lib2_fun1
    17: 00000026    53 FUNC    GLOBAL DEFAULT    2 lib2_fun2
    19: 00000000     0 NOTYPE  GLOBAL DEFAULT  UND lib1_fun1
---------------------------------------------------------------------------------

Make a .so file which includes both the object files in it.

$ gcc -fvisibility=hidden -shared -Wl,-soname,lib12.so -o lib12.so lib1.o lib2.o

$ readelf -s lib12.so | grep fun
    Num:    Value  Size Type    Bind   Vis      Ndx Name
     6: 000004ea    53 FUNC    GLOBAL DEFAULT   11 lib2_fun2
    45: 0000049c    38 FUNC    LOCAL  DEFAULT   11 lib1_fun1
    47: 000004c4    38 FUNC    LOCAL  DEFAULT   11 lib2_fun1
    51: 000004ea    53 FUNC    GLOBAL DEFAULT   11 lib2_fun2
  
Notice the lib1_fun1 is declared as 'LOCAL' even though the Visibilty is 'DEFAULT'

---------------------------------------------------------------------------------

With this we have achieved hiding the symbol from the outside world's usage. But the symbol is still exposed when we do a readelf. How do we get rid of that?

Thats were we use another tool called "strip"

$ strip --strip-all --discard-all lib12.so

$ readelf -s lib12.so | grep fun
    Num:    Value  Size Type    Bind   Vis      Ndx Name
     6: 000004ea    53 FUNC    GLOBAL DEFAULT   11 lib2_fun2

With this, the application writer can only "see" the symbols you want him to see and rest are completely removed. :-)

---------------------------------------------------------------------------------

Now make the testap to test all our theories.

int main(void)
{
    lib1_fun1();   
    lib2_fun1();   
    lib2_fun2();   
    return 0; 
}

$gcc -o testapp testlib.c -L. -l12

The result is

    /tmp/cc2DnM96.o: In function `main':
    testlib.c:(.text+0x7): undefined reference to `lib1_fun1'
    testlib.c:(.text+0xc): undefined reference to `lib2_fun1'
    collect2: ld returned 1 exit status

This shows that the only symbol available to the application out of the lib12.so is 'lib2_fun2' which we wanted to provide and hence declared as global.  The rest of the symbols are only 'Local' to the library and are NOT available outside the library to any application that might link to it.


For more information about the "-fvisibility" option, check the below links
http://blog.fesnel.com/blog/2009/08/19/hiding-whats-exposed-in-a-shared-library/
http://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Function-Attributes.html