Saturday, November 15, 2014

Unix Prog: IPC Message Queue

1. Message Queue Overview
A message queue is a linked list of messages stored within the kernel and identified by a message queue identifier. 

Using msgget can create a new queue or refer to one existing queue.
Using msgsnd can add new messages to the end of a queue.
Every message has a positive long integer type field, a non-negative length, and the actual data bytes.
Using msgrcv can fetch a message from the a queue, and we don't have to fetch the message in a first-in, first-out order, instead, we can fetch messages based on their type field.

Each message queue has the following msqid_ds structure associated with it:
 ubuntu@ip-172-31-23-227:~$ less /usr/include/x86_64-linux-gnu/bits/msq.h  
 ......  
 struct msqid_ds  
 {  
  struct ipc_perm msg_perm;   /* structure describing operation permission */  
  __time_t msg_stime;      /* time of last msgsnd command */  
 #ifndef __x86_64__  
  unsigned long int __glibc_reserved1;  
 #endif  
  __time_t msg_rtime;      /* time of last msgrcv command */  
 #ifndef __x86_64__  
  unsigned long int __glibc_reserved2;  
 #endif  
  __time_t msg_ctime;      /* time of last change */  
 #ifndef __x86_64__  
  unsigned long int __glibc_reserved3;  
 #endif  
  __syscall_ulong_t __msg_cbytes; /* current number of bytes on queue */  
  msgqnum_t msg_qnum;      /* number of messages currently on queue */  
  msglen_t msg_qbytes;     /* max number of bytes allowed on queue */  
  __pid_t msg_lspid;      /* pid of last msgsnd() */  
  __pid_t msg_lrpid;      /* pid of last msgrcv() */  
  __syscall_ulong_t __glibc_reserved4;  
  __syscall_ulong_t __glibc_reserved5;  
 };  
 ......  
Above structure defined the current status of the queue

2. Message Queue System Calls
1) msgget
 ubuntu@ip-172-31-23-227:~$ less /usr/include/x86_64-linux-gnu/sys/msg.h  
 ......  
 /* Get messages queue. */  
 extern int msgget (key_t __key, int __msgflg) __THROW;  
 ......  

msgget can be used to create a new queue or refer to one existing queue.
When a new queue is created, following members of the msqid_ds structure are initialized:
ipc_perm structure is initialized. msg_qnum, msg_lspid, msg_lrpid, msg_stime, and msg_rtime are all set to 0, msg_ctime is set to the current time, msg_qbytes is set to the system limit.

On success, msgget returns the non-negative queue ID.

2) msgctl

 ubuntu@ip-172-31-23-227:~$ less /usr/include/x86_64-linux-gnu/sys/msg.h  
 ......  
 /* Message queue control operation. */  
 extern int msgctl (int __msqid, int __cmd, struct msqid_ds *__buf) __THROW;  
 ......  

msgctl function performs various operations on a queue.
The cmd argument specifies the command to be performed:
 ubuntu@ip-172-31-23-227:~$ less /usr/include/x86_64-linux-gnu/bits/ipc.h  
 ......  
 /* Control commands for `msgctl', `semctl', and `shmctl'. */  
 #define IPC_RMID    0        /* Remove identifier. */  
 #define IPC_SET     1        /* Set `ipc_perm' options. */  
 #define IPC_STAT    2        /* Get `ipc_perm' options. */  
 #ifdef __USE_GNU  
 # define IPC_INFO    3        /* See ipcs. */  
 #endif  
 ......  

IPC_STAT: Fetch the msgid_ds structure for this queue, storing it in the structure pointed to by buf.
IPC_SET: Copy the following fields from the structure pointed to by buf to the msqid_ds structure associated with this queue: msg_perm.uid, msg_perm.gid, msg_perm.mode, and msg_qbytes. This command can only be executed by a process whose effective user id equals msg_perm.cuid or msg_perm.uid or by a process with superuser privilege.
IPC_RMID: rmeove the message queue from the system and any data still on the queue.The removal is immediate. And it can only be executed by a process whose effective user id equals msg_perm.cuid or msg_perm.uid or by a process with super user privilege.

3) msgsnd
msgsnd can be used to place a message into the message queue. And messages are always placed in the end of the queue.
 ubuntu@ip-172-31-23-227:~$ less /usr/include/x86_64-linux-gnu/sys/msg.h  
 ......  
 /* Send message to message queue.  
   
   This function is a cancellation point and therefore not marked with  
   __THROW. */  
 extern int msgsnd (int __msqid, const void *__msgp, size_t __msgsz,  
           int __msgflg);  
 ......  

msgp argument points to the long integer that contains the positive integer message type, and it is immediately followed by the message data.
 ubuntu@ip-172-31-23-227:~$ less /usr/include/x86_64-linux-gnu/sys/msg.h  
 ......  
 /* Template for struct to be used as argument for `msgsnd' and `msgrcv'. */  
 struct msgbuf  
  {  
   __syscall_slong_t mtype;  /* type of received/sent message */  
   char mtext[1];       /* text of the message */  
  };  
 ......  
msgp points to a msgbuf structure. The message type can be used by the receiver to fetch messages in an order other than first in , first out.

Note: length of mtext should be same as third argument msgsz in real world.

A flag value of IPC_NOWAIT can be specified. If the message queue is full, specifying the IPC_NOWAIT causes msgsnd to return immediately with an error of EAGAIN. If IPC_NOWAIT is not specified, we are blocked until there is room for the message, the queue is removed from the system, or a signal is caught and signal handler returns.

After msgsnd returns successfully, the msqid_ds structure associated with the message queue is updated to indicate the process ID that made the call

4) msgrcv
 ubuntu@ip-172-31-23-227:~$ less /usr/include/x86_64-linux-gnu/sys/msg.h  
 ......  
 /* Receive message from message queue.  
   
   This function is a cancellation point and therefore not marked with  
   __THROW. */  
 extern ssize_t msgrcv (int __msqid, void *__msgp, size_t __msgsz,  
             long int __msgtyp, int __msgflg);  
 ......  

As with msgsnd, the ptr argument points to a long integer(where the message type of the returned message is stored) followed by a data buffer for the actual message data. msgp can point to the struct msgbuf as indicated above.

If the returned message buffer is larger than msgsz, and the MSG_NOERROR bit in flag is set, and the message is truncated, and message is totally removed from the queue. If MSG_NOERROR bit is not set in flag, an error of E2BIG is returned, and message still stays on the queue.

For fourth argument, if msgtyp == 0, the first message on the queue is returned. If msgtyp > 0, the first message on the queue whose message type equals type is returned. If msgtyp < 0, the first message on the queue whose message type is the lowest value less than or equal to the absolute value of type is returned.

In client server model, message from clients normally has the type which is the process id of client. And server can based on process id as type to retrieve message from specific client.

If IPC_NOWAIT is specified, msgrc will return -1 with errno set to ENOMSG if a message of the specified type is not available. If IPC_NOWAIT is not specified, the operation blocks until a message of the specified type is available, the queue is removed from the ssytem, or a signal is caught and the signal handler returns.

No comments:

Post a Comment