I am trying to understand message queues. In the examples I saw, the msg strunct would have only one more attribute except of the first one (the type) which must be long. So, it would be something like struct msg{long mtype; char text[100]};.
I tried to add a new int attribute, x to see if I recieve both the text and the number and it worked.
Is this how message queues are supposed to work? Can I have as many attributes as I want in my struct?
And, also, is it ok to call the msgrcv and msgsnd functions with the length parameter set to sizeof(send) - sizeof(send.x) because I know that the sizeof a struct isn't always the same as the sum of the sizeof of each attribute?
Thank you.
int main(){
struct msg{
long mtype;
char text[100];
int x;
};
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");
send.x = 99;
if(msgsnd(qid, (void*)&send, sizeof(send) - sizeof(send.x), 0)<0){
printf("Error child: ");
}
}
else{
struct msg recieve;
if(msgrcv(qid, (void*)&recieve, sizeof(recieve) - sizeof(recieve.x), 1, 0)<0){
perror("Error parent: ");
};
printf("text: %s\nnumber: %d", recieve.text, recieve.x);
}
return 0;
}
From the man page, in:
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
msgp is defined as:
The msgp argument is a pointer to a caller-defined structure of the
following general form:
struct msgbuf {
long mtype; /* message type, must be > 0 */
char mtext[1]; /* message data */
};
Bold is mine
The major point here being the struct is caller-defined. So as long as the input struct (sent by msgsnd) and output struct (received by msgrcv) are the same, the data following mtype can be anything you want (as long as you specify the size correctly). For your case, you really only need:
msgsnd(qid, (void*)&send, sizeof(send) - sizeof(send.mtype), 0)
and
msgrcv(qid, (void*)&recieve, sizeof(recieve) - sizeof(send.mtype), 1, 0)
The char[] is just a placeholder, you can have whatever you want in the structure after the required long mtype field. The size on the msgsnd() call does NOT include mtype.
You almost had it correct.
Here is a working version:
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int main(void){
struct msg {
long mtype;
char text[100];
int x;
};
size_t sz = sizeof(struct msg) - sizeof(long); <=== /* SIZE */
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");
send.x = 99;
if (msgsnd(qid, (void*)&send, sz, 0)<0){
perror("Error child: ");
}
} else {
struct msg recieve;
if(msgrcv(qid, (void*)&recieve, sz, 1, 0)<0){
perror("Error parent: ");
};
printf("text: %s\nnumber: %d\n", recieve.text, recieve.x);
}
return 0;
}
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
Since the msgp parameter is declared as const void*, you can use whatever data type you want. There is nothing that says it has to be a struct with just a long and a char[]. This means you can just do sizeof(send). You do not need to adjust for the extra struct member that you are sending. In fact, doing so will cause problems because the entire struct will not be handled. The only thing that matters is that msgrcv() uses the same struct as the previous msgsnd(). See this example.
Related
I have written two programs one to send message using msgsnd and other to receive with msgrcv. I have been using these functions for quite a while, but I can't figure out "stack smashing detected" error in receiving file. In that file I try to copy one part of file to one char array and second part into second array. I get stack smashing detected after receiving program completion if msgrcv is ever called in a file. At the end of a file I call printf function to print two arrays. From my point arr1 and arr2 should contain complete message, while only arr1 contains message and arr2 is empty. But the biggest problem is stack smashing detected error. I place code for two files below:
Sending file:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/sem.h>
#include <sys/msg.h>
#include <stdint.h>
typedef struct message {
long type;
char text[128];
} message;
int main (int argc, char **argv) {
if (argc == 3 && strcmp (argv [1], "-m") == 0) {
key_t key = (key_t) atoi (argv[2]);
message msg;
int message_queue_id = msgget (key, IPC_CREAT | 0666);
int semaphore_set_id = semget (key, 1, IPC_CREAT | 0666);
struct semid_ds buf;
struct sembuf sb;
long long buf_address = (long long)&buf;
long long sb_address = (long long)&sb;
// sending message
msg.type = 6;
memset (msg.text, 0, 128);
printf ("%p %p\n", (void*)&buf, (void*)&sb);
sprintf (msg.text, "%lld %lld", buf_address, sb_address);
printf ("msg: %s\n", msg.text);
void* ptr = (void*)buf_address;
printf ("ptr = %p\n", ptr);
msgsnd(message_queue_id, (struct msgbuf*)&msg, sizeof (msg) - 4, 0);
sleep (1000);
}
}
Receiving file (without headers):
typedef struct message {
long type;
char text[128];
} message;
int main (int argc, char **argv) {
if (argc == 3 && strcmp (argv [1], "-m") == 0) {
key_t key = (key_t) atoi (argv[2]);
int message_queue_id = msgget (key, IPC_CREAT | 0666);;
int semaphore_set_id = semget (key, 1, IPC_CREAT | 0666);
message msg;
struct semid_ds buf;
struct sembuf sb;
msgrcv (message_queue_id, (struct msgbuf*)&msg, sizeof(msg) - 4, 6, IPC_NOWAIT);
printf ("msg = %s\n", msg.text);
char arr1[32] = "\0", arr2[32] = "\0";
int i = 0;
while (msg.text[i] != ' ') {
arr1[i] = msg.text[i];
i++;
}
i++;
while (msg.text[i]) {
arr2[i] = msg.text[i];
i++;
}
printf ("arr1 = %s, arr2 = %s\n", arr1, arr2);
printf ("sizeof(long) = %d\n", (int)sizeof(long));
}
}
msgrcv (message_queue_id, (struct msgbuf*)&msg, sizeof(msg) - 4, 6, IPC_NOWAIT);
The third parameter to msgrcv should be the size of the buffer stored in the message structure. When doing the calculation sizeof(msg) - 4, you seem to be assuming that the size of long is always 4, which is incorrect. Instead, you should simply use sizeof(msg.text).
You also have the same error in the sender. Because the size of long in 64-bit linux is 8 bytes and not 4, your code will write past the end of the msg variable, causing a buffer overflow.
I get this error when i run the following code , on line 21
Error
error invalid conversion from int to const char* [fpermissive]
Code
receive(struct sockaddr_in sockad, struct message m){
int rc;
int i;
int ibuf;
i = sizeof(sockad);
rc = recvfrom(sd,&m,strlen(ibuf),0,(struct sockaddr *)&sockad,(unsigned long)&i ); /* line 21*/
if (rc < 0) {
perror("recvfrom"); exit(1);
}
}
I tried the solutions that in stackoverflow but no luck
The error is caused by strlen(ibuf)... when int ibuf...
You should pass a string to strlen, although you might have intended to use sizeof(m).
You might have also intended to use pointers, as in struct message *m, so that:
void receive(struct sockaddr_in * sockad, struct message * m){
int rc;
socklen_t i;
i = sizeof(*sockad);
rc = recvfrom(sd, m, sizeof(*m),0, sockad, &i ); /* line 21*/
if (rc < 0) {
perror("recvfrom"); exit(1);
}
}
The issue is with the code:
strlen(ibuf)
ibuf is an integer, not string.
I've been working on a project and one of the tasks that I have to do is passing the string received from another process through a pipe to yet another process but this time I have to use a message queue.
I've managed to learn how msgqueue works and made a simple working program but, the thing is, it works when receiving a string from stdin through fgets.
My question is:
Can I pass a string that is already saved in other variable (for example
char s[20] = "message test"; ) to the msgqueues mtext?
My simple program looks like that:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <errno.h>
struct msgbuf {
long mtype;
char string[20];
};
struct msgbuf mbuf;
int open_queue( key_t keyval ) {
int qid;
if((qid = msgget( keyval, IPC_CREAT | 0660 )) == -1)
return(-1);
return(qid);
}
int send_message( int qid){
int result, size;
size = sizeof mbuf.string;
if((result = msgsnd( qid, &mbuf, size, 0)) == -1)
return(-1);
return(result);
}
int remove_queue( int qid ){
if( msgctl( qid, IPC_RMID, 0) == -1)
return(-1);
return(0);
}
int read_message( int qid, long type){
int result, size;
size = sizeof mbuf.string;
if((result = msgrcv( qid, &mbuf, size, type, 0)) == -1)
return(-1);
return(result);
}
int main(void){
int qid;
key_t msgkey;
msgkey = ftok(".", 'm');
if(( qid = open_queue( msgkey)) == -1) {
perror("openErr");
exit(1);
}
mbuf.mtype = 1;
fgets(mbuf.string, sizeof mbuf.string, stdin);
if((send_message( qid)) == -1) {
perror("sendErr");
exit(1);
}
mbuf.mtype = 1;
if((read_message(qid, mbuf.mtype))== -1){
perror("recERR");
exit(1);
}
printf("Queue: %s\n", mbuf.string);
remove_queue(qid);
return 0;
}
Your code uses fgets() to fill the buffer mbuf.string with input read from stdin. You can instead use something like strcpy(mbuf.string, "message test") where you can pass in a variable or use a hard coded string.
I recommend using the POSIX message queue API as the System V API is deprecated.
I want to create a file filled with 0 or other letters. Here's my function
int fill(const int d, struct aiocb *aiorp, void *buf, const int count){
int rv = 0;
memset( (void *)aiorp, 0, sizeof( struct aiocb ) ); // <-here second paramether is 0
aiorp->aio_fildes = d;
aiorp->aio_buf = buf;
aiorp->aio_nbytes = count;
aiorp->aio_offset = 0;
rv = aio_write( aiorp );
return rv;
}
Here's my main
int main(int argc, char * argv[]){
int des;
int rv;
struct aiocb aior;
char buffer[1000];
if(argc == 3){
printf("just %s\n", argv[1]);
des = createFile(argv[1]);
rv = fill(des, &aior, buffer, sizeof(buffer));
}
return 0;
}
So my output should be file filled with zero values, but my fle is filled with garbage
^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#$
y▒^X^#^#^#^#^#^#^#
s|▒^#^#^#^#^#^#^#^#^#^#^#^#▒r|▒^#^#^#^#▒▒^?▒(▒▒▒▒▒{▒▒
y▒^P^#^#^#▒
y▒^A^#^#^#d^Cy▒^#^#^#^#▒
y▒^T
y▒^P▒▒▒^#^#^#^#^#^#^#^
...
Why? What's wrong?
Here's the code :
sukurti - create new file if that file don't exist and
fill - fill created file
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <aio.h>
#define MB 1024
int sukurti(char *name);
int fill(const int d, struct aiocb *aiorp, void *buf, const int count);
int sukurti(char *name){
int dskr;
dskr = open( name, O_RDONLY );
if( dskr == -1 ){
printf("Failas sukurtas, nes jo nebuvo\n");
dskr = open( name, O_WRONLY | O_CREAT, 0644);
}else{
printf("Jau yra toks failas!\n");
exit(1);
}
return dskr;
}
int fill(const int d, struct aiocb *aiorp, void *buf, const int count){
int rv = 0;
memset( (void *)aiorp, 'A', sizeof( struct aiocb ) );
aiorp->aio_fildes = d;
aiorp->aio_buf = buf;
aiorp->aio_nbytes = count;
aiorp->aio_offset = 0;
rv = aio_write( aiorp );
return rv;
}
int main(int argc, char * argv[]){
int des;
int rv;
struct aiocb aior;
int x = atoi(argv[2]);
printf("%d\n", x);
int size = MB * MB * x;
char buffer[size];
if(argc == 3){
printf("just %s\n", argv[1]);
des = sukurti(argv[1]);
rv = fill(des, &aior, buffer, sizeof(buffer));
}else{
printf("Blogas\n");
}
return 0;
}
EDIT:
I know that my writting to file ends
Three ssues here:
buffer is not initalised. Do this using
memset(buffer,
<what ever 8bit value you want the file to be filled with>,
sizeof buffer);
right after defining it in main().
aior is initialise wrongly. Initialise it to all 0 using
memset(aiorb, 0, sizeof aior);
right after defining it in main() and remove the call to memset() in fill().
Finally the program most likely ends before the buffer had been asynchronously written to disk.
To fix this define a notification method as mentioned under man 7 aio. And make the program wait for this notification to be received before ending the program.
This for example can be done by asking for completion notification via signal and wait for this signal.
To do so modify your code as follows:
Add the following two lines to the intialisation of what aiorp is pointing to in fill():
aiorp->aio_sigevent.sigev_notify = SIGEV_SIGNAL;
aiorp->aio_sigevent.sigev_signo = SIGUSR1;
To be able to handle the notifying signal sent (without ending the program) a signal handler needs to be setup:
void handler(int sig)
{
/* Do nothing. */
}
Install this handler by calling
signal(handler, SIGUSR1);
right at the beginning of the program.
Before returning from main() call wait_for_completion(SIGUSR1) which might look like this:
void wait_for_completion(int sig)
{
sigset_t set;
sigemptyset(&set);
sigaddset(&set, sig);
sigwait(&set, &sig); /* This blocks until sig had
been received by the program. */
printf("Completion notification for asynchronous 'write'-operation received.\n");
}
Add error handling as appropriate. I left it out for the sake of readability.
memset( (void *)aiorp, '0', sizeof( struct aiocb ) );
0 is not '0', you need to actually use the ASCII value (48 if i recall correctly.)
i want to know if a queue message is empty or not . i have used msg_ctl() as follows it doesn't work :
struct msqid_ds buf;
int num_messages;
rc = msgctl(msqid, IPC_STAT, &buf);
and i've used this peek function :
int peek_message( int qid, long type )
{
int result, length;
if((result = msgrcv( qid, NULL, 0, type, IPC_NOWAIT)) == -1) {
if(errno==E2BIG)
return(1);
}
return(0);
}
in both cases i get the same result before and after sending a message to the queue.
the message gets to the queue successfully , i've tested that with reading what i've sent.
I wrote the sample code that does seem to work properly:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#include <errno.h>
struct msgbuf {
long mtype; /* message type, must be > 0 */
char mtext[1]; /* message data */
};
int main(void) {
int msqid;
//msqid = msgget(IPC_PRIVATE, (IPC_CREAT | IPC_EXCL | 0600));
msqid = msgget((key_t)1235, 0600 | IPC_CREAT);
printf("Using message queue %d\n", msqid);
struct msqid_ds buf;
int rc = msgctl(msqid, IPC_STAT, &buf);
uint msg = (uint)(buf.msg_qnum);
printf("# messages before post: %u\n", msg);
printf("Posting message to queue...\n");
struct msgbuf qmsg;
qmsg.mtype = 100;
qmsg.mtext[0] = 'T';
int res = msgsnd(msqid, &qmsg, 1, MSG_NOERROR);
rc = msgctl(msqid, IPC_STAT, &buf);
msg = (uint)(buf.msg_qnum);
printf("# messages after post: %u\n", msg);
return 0;
}
Maybe that will be helpful to you? The number of messages on the queue does seem to increment correctly when using this code.