Message queue in linux - linux

In linux, what should be the output of message queue, when message queue is empty?
First I have send 2 message in one message queue then I have received 2 message from message queue. Now again I am trying to receive message from message queue then I am getting garbage value. Then tell me why I am getting this garbage value ?
Receive.c
#include <stdio.h>
#include <sys/msg.h>
#include <error.h>
#include <strings.h>
int main()
{
int msqid;
struct message
{
long type;
char text[20];
} msg;
struct msqid_ds buf;
int msgtype = 3;
int num_messages;
int count;
int key = 1234;
msqid = msgget(key,0644);
count = msgctl(msqid,IPC_STAT,&buf);
num_messages = buf.msg_qnum;
printf("Number of messages = %d\n",num_messages);
if (msgrcv(msqid, (void *) &msg, sizeof(msg.text), msgtype, MSG_NOERROR| IPC_NOWAIT)==-1);
{
perror("msgrcv");
}
/* if(num_messages==0)
{
printf("Queue is empty\n");
}
else
{ */
printf("%s \n", msg.text);
// }
return 0;
}
Send.c
#include <string.h>
#include <sys/msg.h>
#include <stdio.h>
int main()
{
struct message
{
long type;
char text[20];
} msg;
int msqid;
int key = 1234;
msqid = msgget(key,IPC_CREAT|0644);
msg.type = 3;
strcpy(msg.text, "This is message 1");
msgsnd(msqid, (void *) &msg, sizeof(msg.text), IPC_NOWAIT);
strcpy(msg.text, "This is message 2");
msgsnd(msqid, (void *) &msg, sizeof(msg.text), IPC_NOWAIT);
printf("2 messages are succesfully send \n");
return 0;
}

You need to check the return value of msgrcv (you do that already) and errno. From msgrcv documentation:
IPC_NOWAIT Return immediately if no message of the requested type is in the queue. The system call fails with errno set to ENOMSG.
If you ignore the failure and try to read msg, its values are going to be undetermined because it was not initialized. E.g.:
if(msgrcv(msqid, &msg, sizeof(msg.text), msgtype, MSG_NOERROR | IPC_NOWAIT))
{
if(ENOMSG == errno)
fprintf(stderr, "No messages found\n");
else
perror("msgrcv");
}
else {
// Successfully received a message into msg.
}
(Note that in the original code you have a semi-colon after if, which is probably not what you want).

Related

Linux Netlink Socket Communication Crashes VM

I have written a kernel module and userspace program such that the kernel module sends netlink multicast messages, and the userspace program reads these messages and prints them out. The kernel module and userspace program are available here (https://github.com/akshayknarayan/netlink-test) and replicated below. The code was adapted from this post: Multicast from kernel to user space via Netlink in C
If line 69 of the userspace program (the call to usleep) is commented out, then everything works; once the kernel module is loaded, it repeatedly multicasts messages and the userspace program prints them out.
However, if line 69 of the userspace program is uncommented, within a second of loading the kernel module, my VM hangs and becomes unresponsive.
Why is this the case? How can I prevent the kernel from hanging?
Linux ubuntu-xenial 4.4.0-75-generic #96-Ubuntu SMP Thu Apr 20 09:56:33 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
Userspace program:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <linux/netlink.h>
#include <unistd.h>
/* Multicast group, consistent in both kernel prog and user prog. */
#define MYMGRP 22
int nl_open(void) {
int sock;
struct sockaddr_nl addr;
int group = MYMGRP;
sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_USERSOCK);
if (sock < 0) {
printf("sock < 0.\n");
return sock;
}
memset((void *) &addr, 0, sizeof(addr));
addr.nl_family = AF_NETLINK;
addr.nl_pid = getpid();
if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
printf("bind < 0.\n");
return -1;
}
if (setsockopt(sock, 270, NETLINK_ADD_MEMBERSHIP, &group, sizeof(group)) < 0) {
printf("setsockopt < 0\n");
return -1;
}
return sock;
}
void nl_recv(int sock) {
struct sockaddr_nl nladdr;
struct msghdr msg;
struct iovec iov;
char buffer[65536];
int ret;
iov.iov_base = (void *) buffer;
iov.iov_len = sizeof(buffer);
msg.msg_name = (void *) &(nladdr);
msg.msg_namelen = sizeof(nladdr);
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
ret = recvmsg(sock, &msg, 0);
if (ret < 0)
printf("ret < 0.\n");
else
printf("Received message payload: %s\n", (char*) NLMSG_DATA((struct nlmsghdr *) &buffer));
}
int main(int argc, char *argv[]) {
int nls;
nls = nl_open();
if (nls < 0)
return nls;
while (1) {
nl_recv(nls);
usleep(5000);
}
return 0;
}
Kernel module:
#include <linux/module.h>
#include <linux/netlink.h>
#include <linux/skbuff.h>
#include <linux/gfp.h>
#include <net/sock.h>
#define MYMGRP 22
struct sock *nl_sk = NULL;
static struct timer_list timer;
void nl_send_msg(unsigned long data) {
struct sk_buff *skb_out;
struct nlmsghdr *nlh;
int res;
char *msg = "hello from kernel!\n";
int msg_size = strlen(msg);
skb_out = nlmsg_new(
NLMSG_ALIGN(msg_size), // #payload: size of the message payload
GFP_KERNEL // #flags: the type of memory to allocate.
);
if (!skb_out) {
printk(KERN_ERR "Failed to allocate new skb\n");
return;
}
nlh = nlmsg_put(
skb_out, // #skb: socket buffer to store message in
0, // #portid: netlink PORTID of requesting application
0, // #seq: sequence number of message
NLMSG_DONE, // #type: message type
msg_size, // #payload: length of message payload
0 // #flags: message flags
);
memcpy(nlmsg_data(nlh), msg, msg_size+1);
res = nlmsg_multicast(
nl_sk, // #sk: netlink socket to spread messages to
skb_out, // #skb: netlink message as socket buffer
0, // #portid: own netlink portid to avoid sending to yourself
MYMGRP, // #group: multicast group id
GFP_KERNEL // #flags: allocation flags
);
if (res < 0) {
printk(KERN_INFO "Error while sending to user: %d\n", res);
} else {
mod_timer(&timer, jiffies + msecs_to_jiffies(1));
}
}
static int __init nl_init(void) {
struct netlink_kernel_cfg cfg = {};
printk(KERN_INFO "init NL\n");
nl_sk = netlink_kernel_create(&init_net, NETLINK_USERSOCK, &cfg);
if (!nl_sk) {
printk(KERN_ALERT "Error creating socket.\n");
return -10;
}
init_timer(&timer);
timer.function = nl_send_msg;
timer.expires = jiffies + 1000;
timer.data = 0;
add_timer(&timer);
nl_send_msg(0);
return 0;
}
static void __exit nl_exit(void) {
printk(KERN_INFO "exit NL\n");
del_timer_sync(&timer);
netlink_kernel_release(nl_sk);
}
module_init(nl_init);
module_exit(nl_exit);
MODULE_LICENSE("GPL");
For posterity: I believe the problem was the allocation in nlmsg_new, which should not occur inside an interrupt handler (the timer handler, nl_send_msg), as explained here.
Without the sleep, I believe nlmsg_new does not need to sleep when allocating, so the requirement that an interrupt handler not sleep is not violated. However, if the userspace process lags behind the kernel, it is possible for the kernel to sleep during the allocation, causing a hang.

Linux Message Queue receive with particular mtype failed between two Process

send.c create a message queue and sends message with mtype 5
send.c
#include<stdio.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<string.h>
struct msgbuf
{
long mtype;
char mtext[40];
};
void main()
{
int key,id;
struct msgbuf vara;
key = ftok("/usr", 65);
id = msgget(key, IPC_CREAT|0666);
vara.mtype=5;
strcpy(vara.mtext,"hi");
msgsnd(id,&vara, strlen(vara.mtext)+1, 0);
perror("status:");
printf("msg sent\n");
}
receive.c is trying to receive message from message queue with mtype 5
recieve.c
#include<stdio.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<string.h>
#define MAXSIZE 128
struct msgbuf
{
long mtype;
char mtext[40];
};
void main()
{
int key; int id;
struct msgbuf vars;
key = ftok("/usr", 65);
id = msgget(key, IPC_CREAT|0666);
msgrcv(id,&vars,MAXSIZE,5,0);
perror("status ");
printf("msg rcvd --> %s\n", vars.mtext);
}
Im not able receive message with particular mtype mentioned in msgrcv function in receive.c file however i able receive message if mtype set to 0

IPC using msgsnd and msgrcv

For learning, I wrote 2 IPC programs, a server and a client that use message sending. For some reason, the server does not seem to be receiving the data it has been send. Could you give me some hints on how I could go about debugging such a problem?
#include <sys/ipc.h>
#include <sys/types.h>
#include <sys/msg.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define CENTRAL_MAILBOX 1200
#define CLIENT_MAILBOX 1201
struct {
long priority;
int value;
int pid;
} msgp, cmbox;
int main(int argc, char **argv) {
int uid = 0; // Process id of the server(this process) set to 0
int length = -1; // Length of the structure we are going to send over
int result = -1; // Result of the msgrcv operation
int status = -1;
if ( argc != 2 ) {
fprintf(stderr, "Usage: ./server <temperature>\n");
exit(-1);
}
printf("[+] Starting server\n");
printf("[+] Creating the mailbox\n");
int server_msgid = msgget(CENTRAL_MAILBOX, 0600 | IPC_CREAT);
printf("[+] Creating a mailbox for the client process\n");
int client_msgid = msgget(CLIENT_MAILBOX, 0600 | IPC_CREAT);
printf("[+] Initializing data to be sent across\n");
msgp.priority = 1;
msgp.value = 31337;
msgp.pid = uid;
length = ( sizeof(msgp) > sizeof(long) ? sizeof(msgp)-sizeof(long) : sizeof(long)-sizeof(msgp) );
printf("[+] Calculating the size of the message we are about to send across=%d\n", length);
// msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
result = msgrcv(server_msgid, &cmbox, length, 1, 0);
printf("Result = %d\n", result);
printf("[+] Received message pid=%d, value=%d, priority=%ld\n", cmbox.pid, cmbox.value, cmbox.priority);
printf("[+] Sending message\n");
// int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
result = msgsnd(client_msgid, &msgp, length, 0);
printf("[+] Shutting down server\n");
status = msgctl(server_msgid, IPC_RMID, 0);
if ( status != 0 ) {
fprintf(stderr, "[*] ERROR: closing mailbox failed\n");
}
}
My Client :-
#include <sys/ipc.h>
#include <sys/types.h>
#include <sys/msg.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define CENTRAL_MAILBOX 1200
#define CLIENT_MAILBOX 1201
struct {
long priority;
int value;
int pid;
} msgp, cmbox;
int main(int argc, char **argv) {
int temp = atoi(argv[1]);
int uid = getpid(); //7171;
int length, result, status;
if ( argc != 2 ) {
// TODO find actual process id
fprintf(stderr, "Usage: ./client <temperature>\n");
exit(-1);
}
printf("[+] Creating server mailbox\n");
int server_msgid = msgget(CENTRAL_MAILBOX, 0600 | IPC_CREAT);
printf("[+] Creating client mailbox\n");
int client_msgid = msgget(CLIENT_MAILBOX, 0600 | IPC_CREAT);
printf("[+] Initializing the data to be sent across\n");
cmbox.priority = 2;
cmbox.value = 1337;
cmbox.pid = uid;
length = ( sizeof(msgp) > sizeof(long) ? sizeof(msgp)-sizeof(long) : sizeof(long)-sizeof(msgp) );
printf("[+] Calculating the size of the message we are about to send across=%d\n", length);
printf("[+] Sending message to server\n");
result = msgsnd(server_msgid, &cmbox, length, 0);
printf("Result = %d\n", result);
result = msgrcv(client_msgid, &msgp, length, 1, 0);
printf("[+] Received message pid=%d, value=%d, priority=%ld\n", msgp.pid, msgp.value, msgp.priority);
printf("[+] Removing the mailbox\n");
status = msgctl(client_msgid, IPC_RMID, 0);
if ( status != 0 ) {
printf("Error when closing mailbox\n");
}
}
Your server blocks on the 1st msgrcv() because it expects message of type 1 (what you called priority, in your msgp, cmbox structures):
// msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
result = msgrcv(server_msgid, &cmbox, length, 1, 0);
When the client send a message of type 2:
printf("[+] Initializing the data to be sent across\n");
cmbox.priority = 2;
// [...]
printf("[+] Sending message to server\n");
result = msgsnd(server_msgid, &cmbox, length, 0);
Have a look at how to use the msgtyp value in the man page:
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
[...]
The msgp argument is a pointer to caller-defined structure of the following general form:
struct msgbuf {
long mtype; /* message type, must be > 0 */
char mtext[1]; /* message data */
};
[...]
msgrcv()
[...]
The argument msgtyp specifies the type of message requested as follows:
If msgtyp is 0, then the first message in the queue is read.
If msgtyp is greater than 0, then the first message in the queue of type msgtyp is read, unless MSG_EXCEPT was specified in msgflg, in which case the first message in the queue of type not equal to msgtyp will be read.
If msgtyp is less than 0, then the first message in the queue with the lowest type less than or equal to the absolute value of msgtyp will be read.

SIGUSR1 not received

This is my first Program....ctrlcsignal.c
enter code here
#include<stdio.h>
#include<unistd.h>
#include<signal.h>
void signal_handler(int sigNo)
{
//if Ctrl+c signal
if(sigNo==SIGINT){
printf("value of SIGINT:-%d\t",SIGINT);
printf("received SIGINT\n");
}
// if some other signal , but this part wont get executed
// as the signal_handler function is registered with SIGINT only
else
{
printf("Some other signal found");
printf("value of other signal:-%d",sigNo);
}
}
int main(void)
{
//registering the signal handler function with a signal
kill(19574,SIGUSR1);
if(signal(SIGINT,signal_handler)==SIG_ERR)
{
printf("\n can't catch SIGINT\n");
}
while(1) //infinite loop
sleep(1); // 1s ,so that the CPU is not busy
return 0;
}
and this my second program....userdefinedsignals.c
enter code here
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
void signal_handler(int sigNo)
{
printf("function entered...");
// check for userdefined Signal SIGUSR1
if (sigNo == SIGUSR1)
{
printf("received SIGUSR1 with value :- %d",SIGUSR1);
}
//checking for KILL Signal
else if (sigNo == SIGKILL)
{
printf("received SIGKILL with value :- %d",SIGKILL);
}
//checking for STOP Signal
else if (sigNo == SIGSTOP)
{
printf("received SIGSTOP with value :- %d",SIGSTOP);
}
// if some other signal , but this part wont get executed
// as the signal_handler function is registered with SIGINT only
else
{
printf("Some other signal found");
printf("value of other signal:-%d",sigNo);
}
}
int main(void)
{
int pid_t;
printf("process id is %d",getpid());
//registering the signal handler function with a signal
if(signal(SIGUSR1,signal_handler) == SIG_ERR)
{
printf("\n can't catch SIGSIGUSR1\n");
}
if(signal(SIGKILL,signal_handler)==SIG_ERR)
{
printf("\n can't catch SIGKILL\n");
}
if(signal(SIGSTOP,signal_handler)==SIG_ERR)
{
printf("\n can't catch SIGSTOP\n");
}
while(1) //infinite loop
sleep(1); // 1s ,so that the CPU is not busy
return 0;
}
I get the pid of the second process ... suppose xxxx
then i use the following command...
enter code here
kill -USR1 xxxx
but it shows nothing ....
also then i tried by calling the following function int the first program...but no use..
enter code herekill(xxxx,SIGUSR1);
HELP ME..!!!!
Works here.
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <stdarg.h> /* vsnprintf() */
#include <signal.h> /* signal */
void myprintf(FILE *fp, char *fmt, ...)
{
char buff[512];
int rc,fd;
va_list argh;
va_start (argh, fmt);
rc = vsnprintf(buff, sizeof buff, fmt, argh);
if (rc < 0 || rc >= sizeof buff) {
rc = sprintf(buff, "Argh!: %d:\n", rc);
}
if (!fp) fp = stderr;
fd = fileno(fp);
if (fd < 0) return;
if (rc > 0) write(fd, buff, rc);
return;
}
void signal_handler(int sigNo)
{
switch (sigNo ) {
case SIGUSR1:
myprintf(NULL, "received SIGUSR1 with value :- %d\n", SIGUSR1);
break;
case SIGKILL:
myprintf(NULL, "received SIGKILL with value :- %d\n", SIGKILL);
break;
case SIGSTOP:
myprintf(NULL, "received SIGSTOP with value :- %d\n", SIGSTOP);
break;
default:
myprintf(NULL, "Some other signal occured: %d\n", sigNo);
break;
}
return;
}
int main(void)
{
pid_t mypid;
mypid = getpid();
printf("process id is %d\n", (int) mypid);
if(signal(SIGUSR1,signal_handler) == SIG_ERR)
{ printf("\n can't catch SIGSIGUSR1\n"); }
if(signal(SIGKILL,signal_handler)==SIG_ERR)
{ printf("\n can't catch SIGKILL\n"); }
if(signal(SIGSTOP,signal_handler)==SIG_ERR)
{ printf("\n can't catch SIGSTOP\n"); }
if(signal(SIGCONT,signal_handler)==SIG_ERR)
{ printf("\n can't catch SIGCONT\n"); }
while(1) {
sleep(1);
}
return 0;
}
You're catching the signal all right, but not seeing the message because you don't terminate lines properly, and the standard output stream on your system is line buffered (assuming your program runs in a terminal).
Standard C defines three levels of buffering for output streams:
unbuffered, where output is transmitted immediately
line buffered, where output is transmitted when a newline character is encountered
fully buffered, where output is transmitted when an internal buffer fills
(This is a simplification - see a C reference or the Standard for details).
Consider:
#include <stdio.h>
#include <unistd.h>
int main(void)
{
printf("Hello");
pause();
}
This produces no output in a terminal. Fix it by terminating the line:
printf("Hello\n");
This will produce the expected output in a terminal.
If stdout is not connected to a terminal - for example, you redirect to a file - then the stream becomes fully buffered. This:
./a.out > foo
Ctrl-C
cat foo
produces no output, even with the newline character added. Here you need an explicit flush to transmit the output before the buffer is full.
#include <stdio.h>
#include <unistd.h>
int main(void)
{
printf("Hello\n");
fflush(stdout);
pause();
}
This produces output even when redirected to a file.

Read timeout on pty file descriptor failing

I am trying to set a read timeout on a file descriptor representing a PTY. I have set VMIN = 0 and VTIME = 10 in termios, which I expect to return when a character is available, or after a second if no characters are available. However, my program sits forever in the read call.
Is there something special about PTY that makes this not work? Are there other TERMIOS settings that cause this to work? I tried this same configuration on the stdin file descriptor and it worked as expected.
#define _XOPEN_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <termios.h>
#include <fcntl.h>
#define debug(...) fprintf (stderr, __VA_ARGS__)
static void set_term (int fd)
{
struct termios termios;
int res;
res = tcgetattr (fd, &termios);
if (res) {
debug ("TERM get error\n");
return;
}
cfmakeraw (&termios);
termios.c_lflag &= ~(ICANON);
termios.c_cc[VMIN] = 0;
termios.c_cc[VTIME] = 10; /* One second */
res = tcsetattr (fd, TCSANOW, &termios);
if (res) {
debug ("TERM set error\n");
return;
}
}
int get_term (void)
{
int fd;
int res;
char *name;
fd = posix_openpt (O_RDWR);
if (fd < 0) {
debug ("Error opening PTY\n");
exit (1);
}
res = grantpt (fd);
if (res) {
debug ("Error granting PTY\n");
exit (1);
}
res = unlockpt (fd);
if (res) {
debug ("Error unlocking PTY\n");
exit (1);
}
name = ptsname (fd);
debug ("Attach terminal on %s\n", name);
return fd;
}
int main (int argc, char **argv)
{
int read_fd;
int bytes;
char c;
read_fd = get_term ();
set_term (read_fd);
bytes = read (read_fd, &c, 1);
debug ("Read returned\n");
return 0;
}
From the linux pty (7) manpage (italics are mine):
A pseudoterminal (sometimes abbreviated "pty") is a pair of virtual character devices that
provide a bidirectional communication channel. One end of the channel is called the
master; the other end is called the slave. The slave end of the pseudoterminal provides
an interface that behaves exactly like a classical terminal
Your program, however, is reading from the master, which cannot be expected to behave exactly like a terminal device
If you change/expand the last few lines of get_term thusly ...
int slave_fd = open (name, O_RDWR); /* now open the slave end..*/
if (slave_fd < 0) {
debug ("Error opening slave PTY\n");
exit (1);
}
return slave_fd; /* ... and use it instead of the master..*/
... your example program will work as expected.

Resources