System V Msg Queues on Linux don't work as expected - c

I have the following application which replicates an issue I'm having in a larger application with system v message queues. basically, the main function generates a key, then creates a message queue with msgget(). Then 3 forks are spawned, each with a different id. each of them runs msgrcv with a different posative number (so they are waiting for different messages).
Main then sleeps for a few seconds a sends a message to id = 3. However it isn't the third thread that wakes up but a different one instead. This code is completely isolated so you can try it out yourself. What's wrong with this code?
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/wait.h>
struct dummy_struct {
long mtype;
char message[255];
};
int msg_queue_id;
void recv_thread(int id);
int main(int argc, char **argv)
{
int i;
key_t key;
struct dummy_struct dummy = { 3, "hello" };
//create a unique key
if (key = ftok("/mnt/mydocuments/code/sys_v_fork_test/main.c", 'a') == -1)
{
printf("ftok didn't work\n");
exit(1);
}
//create the unix sys 5 message queue
if ((msg_queue_id = msgget(key, 0644 | IPC_CREAT)) == -1)
{
printf("msgget failed\n");
exit(1);
}
else
printf("my message queue id: %i\n", msg_queue_id);
//fork off multiple recievers
for (i = 1; i < 4; i++) // <- NOTE: 1 -> 4
{
if (fork() == 0)
recv_thread(i);
}
printf("sleeping\n");
sleep(5);
//wait a little then send a message
printf("sending message\n");
if (msgsnd(msg_queue_id, &dummy, sizeof(struct dummy_struct), 0) == -1)
{
printf("msgsnd failed\n");
}
printf("main thread exiting");
_exit(0);
}
void recv_thread(int id)
{
struct dummy_struct dummy;
printf("recv_thread with id: %i\n", id);
if (msgrcv(msg_queue_id, &dummy, sizeof(struct dummy_struct), id, 0) == -1)
printf("error in msgrcv\n");
else
printf("thread %i got %s back\n", id, dummy.message);
}
If I wait for 2 that means messages whose struct contains a mtype set to exactly 2. 3 for 3 and so one. My point of reference was this guide: http://www.ecst.csuchico.edu/~beej/guide/ipc/mq.html. Can anyone help please? (you may need to modify the ftok line of code to point to a valid file on your own machine to test successfully). I'm running Fedora 10 on an EeePC 1000H

Ahh think i've fixed it. It's because I was using an int rather than a long for the first member set in the structure for the "mtype". passing in { 1l, "hello" } instead and changing the definition of i to long seems to have fixed it

Related

C Unix msgsnd not sending some messages

I have written a program in c that creates a child process for receiving messages and the parent sends messages. It will not receive messages from its parent process, this is by design and my reason for using MSG_EXCEPT. So it is intended to have 2 instances of the program running, and they can send and receive messages. The issue is that the program only sends some messages, not all, and I have no clue why...
Also, I have to use gcc -D_GNU_SOURCE chat.c -o chat to compile, otherwise it has an error about MSG_EXCEPT. Does anyone know a better way to get MSG_EXCEPT to work without using those compiler flags? Something in code would be preferable, so that this can be portable.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/msg.h>
#include <time.h>
#include <signal.h>
#include <errno.h>
typedef struct messageBuffer {
long type;
char text[256];
} MsgBuf;
typedef struct MessageStruct {
MsgBuf message;
int success;
} Message;
void handler(int sig){
_exit(0);
}
int open_queue( key_t keyval )
{
int qid;
if((qid = msgget( keyval, IPC_CREAT | 0666 )) == -1)
{
return(-1);
}
return qid;
}
void SendMessage(int qid, int msgtype, char* msgtxt)
{
MsgBuf msg;
time_t t;
msg.type = msgtype;
snprintf(msg.text, sizeof(msg.text), "%s", msgtxt);
time(&t);
if(msgsnd(qid, (void*)&msg, sizeof(msg.text), IPC_NOWAIT) == -1)
{
perror("msgsnd error");
exit(EXIT_FAILURE);
}
}
Message ReceiveMessage(int qid, int msgtype)
{
Message msg;
msg.success = 1;
if(msgrcv(qid, (void*)&msg.message, sizeof(msg.message.text), msgtype, IPC_NOWAIT | MSG_NOERROR | MSG_EXCEPT) == -1)
{
if (errno != ENOMSG)
{
perror("msgrcv");
exit(EXIT_FAILURE);
}
else
msg.success = 0;
}
return msg;
}
void ClearCurrentConsoleLine()
{
printf("\x1b[1F"); // Move to beginning of previous line
printf("\x1b[2K"); // Clear entire line
}
int main(void)
{
pid_t pid;
pid_t ppid = getpid();
int msgkey = 6666;
char str[256];
Message msg;
char* writemsg = "Write your message below:\n";
pid = fork();
int qid = open_queue(msgkey);
if(qid == -1)
{
perror("msgget");
exit(EXIT_FAILURE);
}
if(pid < 0)
{
perror("Forking error!");
abort();
}
else if(pid == 0)
{
signal(SIGCONT,handler);
while(1)
{
msg = ReceiveMessage(qid, ppid);
if(msg.success)
{
ClearCurrentConsoleLine();
printf("message: %ld: %s\n", msg.message.type, msg.message.text);
printf("%s", writemsg);
}
}
exit(0);
}
while(1)
{
printf("%s", writemsg);
fgets(str, sizeof(str), stdin);
int n = strlen(str);
if(str[n-1] == '\n')
str[n-1] = '\0';
ClearCurrentConsoleLine();
ClearCurrentConsoleLine();
printf("Me: %s\n", str);
if(strcmp(str, "exit") == 0)
{
printf("exiting\n");
break;
}
SendMessage(qid, ppid, str);
}
printf("Killing: %d\n", pid);
kill(pid,SIGCONT);
exit(0);
}
MSG_EXCEPT should not be used here, just remove this flag
MSG_EXCEPT
Used with msgtyp greater than 0 to read the first message
in the queue with message type that differs from msgtyp.
Turns out there was just an issue with that specific message queue. So I just closed the message queue and started a new one and all fixed. In regards to the MSG_EXCEPT, I need to use that because I don't want to just get any message currently in the queue, as I would with 0, I want to get any message that is not submitted by myself, any message except one with the key that I am using to send them. Another way I could do this would be to have 2 message queues per process, one for acquiring the key and message queue of another chat process, and one for sending messages between that other chat process, but this would increase complexity and this is just meant to be a simple implementation.

Message queue error: No message of desired type

I am trying to understand how message queues work. I created this little program where the child process sends a message to the parent process. Most of the times, it works, but sometimes I would recieve the error: Error parent: No message of desired type. I tried also to wait for the child process to finish, but I would still get the error.
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
int main(){
struct msg{
long mtype;
char text[100];
};
int key = ftok(".", 10);
int qid = msgget(key, 0666|IPC_CREAT);
int pid = fork();
if(pid == 0){
struct msg send;
send.mtype = 1;
strcpy(send.text, "hello");
if(msgsnd(qid, (void*)&send, strlen(send.text), IPC_NOWAIT)<0){
printf("Error child: ");
}
}
else{
struct msg recieve;
if(msgrcv(qid, (void*)&recieve, 100, 1, IPC_NOWAIT)<0){
perror("Error parent: ");
};
printf("%s\n", recieve.text);
}
return 0;
}
Thanks.
http://pubs.opengroup.org/onlinepubs/7908799/xsh/msgrcv.html
The argument msgflg specifies the action to be taken if a message of the desired type is not on the queue. These are as follows:
If (msgflg & IPC_NOWAIT) is non-zero, the calling thread will return immediately with a return value of -1 and errno set to [ENOMSG]
...
You're specifying IPC_NOWAIT which means you're not giving the child process enough time to produce any message. If you drop that from the parameter msgflg, i.e.
if(msgrcv(qid, (void*)&recieve, 100, 1, 0) < 0)
The parent process will block until something is available in the queue.

Message queue is giving me an invalid argument

I'm having some trouble with my code. It should create a message queue and send a message, than wait some time for another program to receive that message and answer. The problem is, when I run it, I get an invalid argument both on the msgsnd and on the msgrcv.
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/msg.h>
typedef struct my_msg{
long type;
char text[100];
char sqdr;
}message;
static void score(int messagge_id, char* A_B){
message send;
send.type=1;
strcpy(send.text, "Try to score");
send.sqdr = *A_B;
if((msgsnd(messagge_id, &send, sizeof(send), 0))<0)perror("Error msgsnd\n");
sleep(3);
if((msgrcv(messagge_id, &send, sizeof(send), 4, 0))==-1)perror("Error msgrcv 1\n");
int test=atoi(send.text);
printf("%d\n", test);
}
int main(){
int caso, key;
char team= 'A';
key=1234;
int msg_id=msgget(key, S_IRUSR|S_IWUSR);
printf("Try function score\n");
score(msg_id, &team);
printf("After score\n");
return 0;
}
You need to ensure that the message queue is created. You either use the key IPC_PRIVATE or you add IPC_CREAT to the flags. You also need to try to read the message correctly. You sent a 'type 1' message and attempted to read a 'type 4' message, so the read hangs.
This code also removes the message queue. That's not critical if it is a private queue (such queues are deleted when the program terminates), but it is important for queues using IPC_CREAT and a user-defined key. (I also changed the message text so that atoi() returned something more interesting — and convincing — than zero. The code also uses separate send and receive buffers so that we know the code is not cheating and reusing data already in the buffer.)
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <sys/msg.h>
#include <fcntl.h>
typedef struct my_msg
{
long type;
char text[100];
char sqdr;
} message;
static void score(int messagge_id)
{
message send;
message recv;
send.type = 1;
strcpy(send.text, "47 tries to score");
send.sqdr = 'A';
if ((msgsnd(messagge_id, &send, sizeof(send), 0)) < 0)
perror("Error msgsnd");
printf("Dozing...\n");
sleep(3);
printf("Unslumbering...\n");
if ((msgrcv(messagge_id, &recv, sizeof(recv), -4, 0)) == -1)
perror("Error msgrcv");
int test = atoi(recv.text);
printf("%d\n", test);
}
int main(void)
{
int key = 1234;
int flags = S_IRUSR|S_IWUSR|IPC_CREAT;
// int key = IPC_PRIVATE;
// int flags = S_IRUSR|S_IWUSR;
int msg_id = msgget(key, flags);
if (msg_id < 0)
perror("Error msgget");
else
{
printf("Try function score\n");
score(msg_id);
printf("After score\n");
if (msgctl(msg_id, IPC_RMID, 0) < 0)
perror("Error msgctl");
}
return 0;
}
Sample output:
Try function score
Dozing...
Unslumbering...
47
After score
There's a 3 second pause between 'Dozing' and 'Unslumbering', of course.
use like this:-
if((msgsnd(messagge_id, (void *)&send, sizeof(send), 0))<0)perror("Error msgsnd\n");
if((msgrcv(messagge_id, (void *)&send, sizeof(send), 4, 0))==-1)perror("Error msgrcv 1\n");

Usage of message queue fork + execlp + ftok

The main purpose here is to create a message queue by executing thise command : ./create_msg_queue fileForQueue
We want to create the file fileForQueue if it doesn't exist.
Regarding my code, if the file doesn't exist, I get this error
ftok: No such file or directory
So how can I have this file create BEFORE ftok() is called with the file name ?
Provided code :
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
// IPC and KEYS -------------
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/wait.h>
//---------------------------
#define _XOPEN_SOURCE
// message structure
typedef struct {
// id message
long type;
// Size : 12 bytes
double mesure;
pid_t pidClient;
} message_t;
int main (int argc, char * argv []) {
key_t key;
message_t message;
int file;
int pid;
// Check arg number
if (argc != 2) {
fprintf(stderr, "Syntaxe : %s fichier_clé\n",argv[0]);
exit(EXIT_FAILURE);
}
// Create the empty file given in parameter
if ((pid = vfork()) == -1)
{
perror("fork");
exit(1);
}
if (pid)
{
// code replacement to create the FILE
execlp("touch", "touch", argv[1], NULL);
perror("execlp");
exit(1);
}else
{
// Trying to wait for the forked() process to finish its file creation
wait (NULL);
// I GET ERROR HERE IF THE FILE DON'T EXIST BEFORE I LAUNCH THE PROGRAM
// Create key with the file given in parameter and then created
if ((key = ftok(argv[1], 0)) == -1) {
// errNo value
perror("ftok");
exit(EXIT_FAILURE);
}
// Create message queue
if ((file = msgget(key, IPC_CREAT | 0666)) == -1) {
perror("msgget");
exit(EXIT_FAILURE);
}
// Registering message content
message.type = 1;
message.mesure = -1;
message.pidClient = getpid();
// Sending message
if (msgsnd(file, (void *) & message, 12, 0) <0) {
perror("msgsnd");
exit(EXIT_FAILURE);
}
}
return EXIT_SUCCESS;
}
Thanks in advance for help. I struggle :)
key_t ftok(const char *path, int id);
ftok(argv[1], 0))
Only the low-order 8-bits of id are significant. The behavior of
ftok() is unspecified if these bits are 0.
Also note that you have to
#define _XOPEN_SOURCE
at the very begin

How to distinguish between two different SIGUSR2 signals sent from the Server?

My server needs to support multiple clients , for the moment let's assume that we're
working with 2 clients .
Here's the server :
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <fcntl.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/fcntl.h>
#include <sys/stat.h>
#define FIFONAME "fifo_clientTOserver"
#define SHM_SIZE 1024 /* make it a 1K shared memory segment */
#define ROWS 10
#define COLS 10
void error(char* str)
{
perror(str);
exit(1);
}
int main(int argc, char *argv[])
{
unlink(FIFONAME); // remove any previous fifo pipes
// create a FIFO named pipe - only if it's not already exists
if(mkfifo(FIFONAME , 0666) < 0)
error("mkfifo");
/**
* process 1
*/
// open the fifo for reading
int server_to_client = open(FIFONAME, O_RDONLY);
int reading;
while (1)
{
if (read(server_to_client, &reading ,sizeof(int)) < 0)
perror("read");
else
break;
}
printf("Reading from the fifo : %d\n" , reading);
if (close(server_to_client) < 0)
error("close");
// casting into pid_t
pid_t pid = (pid_t)reading;
// signal to the process that he's the first
kill(pid, SIGUSR2);
/**
* process 2
*/
printf("Now waiting for process 2...\n");
// doing it again - this time for the second process
// remove any previous fifo pipes
unlink(FIFONAME);
// create a FIFO named pipe - only if it's not already exists
if(mkfifo(FIFONAME , 0666) < 0)
error("mkfifo");
printf("Server tester1\n");
server_to_client = open(FIFONAME, O_RDONLY);
// grab the PID of process 2
while (1)
{
if (read(server_to_client, &reading ,sizeof(int)) > 0)
break; // got the data
}
printf("Server tester2\n");
printf("Reading from the fifo : %d\n" , reading);
if (close(server_to_client) < 0)
error("close");
// casting into pid_t
pid = (pid_t)reading;
// signal to the process that he's the first
kill(pid, SIGUSR2);
return 0;
}
The problem is , that both clients needs to pass their PID (this is not a father-son relation !!! those are two separate processes) , and then the server signals with SIGUSR2 to the first process that he is the first one chosen , and if so , then that process works with a character of type X .
On the other hand ,if you're the second process ,you work with a character of type Y .
Here's the client :
int static flagger = 0;
char process_char = 'a';
/**
* handler for SIGUSR2
*/
void my_handler(int signum)
{
printf("foo bar\n");
if (signum == SIGUSR2)
{
printf("Received SIGUSR2!\n");
flagger++;
}
printf("flagger is :%d\n" , flagger);
if (flagger == 1)
{
// then process works with "X"
process_char = 'x';
printf("I'm process 1, working with X char\n");
// exit(1);
}
else if (flagger == 2)
{
process_char = 'Y';
printf("I'm process 2 , working with Y char\n");
// exit(1);
}
}
void error(char* str)
{
perror(str);
exit(1);
}
int main(int argc, char *argv[])
{
pid_t pid;
/* get the process id */
if ((pid = getpid()) < 0)
{
perror("unable to get pid");
}
else
{
printf("The process id is %d\n", pid);
}
int pidInt = (int)pid; // convert the pid to int
// write pid into the fifo
int fd = open("fifo_clientTOserver",O_WRONLY); // open the fifo for writing
if(fd < 0)
{
perror("open");
exit(1);
}
signal(SIGUSR2, my_handler);
printf("Tester1\n");
// writing the PID of the client into the pipe
write(fd, &pidInt ,sizeof(int));
close(fd); // closing the pipe
printf("Tester2\n");
while(1)
{
printf("Waiting for the signal...\n");
sleep(1);
}
// more code
}
I tried to use a static int variable in the client (the flagger) to distinguish between the SIGUSR2 signals (either 1st or 2nd) but it doesn't help since , to each client the static flagger is a new variable that starts with 0 and reaches 1 .
How can I distinguish between the 1st time that a process received SIGUSR2 and the second time that another process received SIGUSR2 ?
If you need to pass data around, then signals are not an appropriate mechanism. Consider using a different IPC method, such as named pipes.

Resources