0

I'm trying to send a 1KB string over a message queue between a parent process and its forked child. Unfortunately, my calls to msgsnd, msgrcv, etc. are suddenly all returning -1 and causing the EINVAL error.

I found that this error (in the case of msgsnd, for example) occurs when msqid is invalid, the message type argument is set at <1, or the msgsz is out of range. But upon testing, as far as I can tell, msgget is returning a perfectly valid ID number and the type is set fine. There must be a problem with my buffer ranges, but I thought I set them up correctly. In the code, I have added comments to explain (sorry about all of the frantically-added #includes):

#include <errno.h>  
#include <stdio.h>
#include <iostream> 
#include <stdlib.h>
#include <string.h>
#include <string> 
#include <cstring> 
#include <sys/msg.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/time.h>
#include <sstream> 

#define PERMS (S_IRUSR | S_IWUSR) 
#define NUMBYTES 1024 //number of chars (bytes) to be sent 

using namespace std; 

//Special structure for messages
typedef struct {
  long mtype; 
  char mtext[NUMBYTES];  
} mymsg_t; 

int main(){

  //Construct a generic test message of the specified size
  char message[NUMBYTES];
  for(int i = 0; i < NUMBYTES; i++)
    message[i] = 'a';  

  //Create the message queue (accessed by both parent
  //and child processes)
  int msqid;
  int len;  
  if(msqid = msgget(IPC_PRIVATE, PERMS) == -1)
    perror("Failed to create new message queue!\n");   

  if(fork() == 0){  //Child process...does the sending

    mymsg_t* mbuf;
    len = sizeof(mymsg_t) + strlen(message); //doesn't work with " + sizeof(message)" either 

    void* space; 
    if((space = malloc(len)) == NULL) //this works fine; no error output 
      perror("Failed to allocate buffer for message queue.\n"); 
    mbuf = (mymsg_t*)space;  

    strcpy(mbuf->mtext, message); 
    mbuf->mtype = 1; //a default   

//Some error checks I tried... 
//cout<<"msqid is " << msqid << endl;
//cout << "mbuf ptr size is " << sizeof(mbuf) << ". And this non-ptr: "<<sizeof(*mbuf)<<". And 
//len: "<<len<<endl; 

    if(msgsnd(msqid, mbuf, len+1, 0) == -1)
      perror("Failed to send message.\n");  //this error occurs every time! 

    free(mbuf);  
  }    

  else{ //Parent process...does the receiving 

    usleep(10000); //Let the message come     

    mymsg_t mymsg; //buffer to hold message
    int size; 
    if((size = msgrcv(msqid, &mymsg, len+1, 0, 0)) == -1) //error every time
      perror("Failed to read message queue.\n");  

    //checking that it made it 
    //cout << "Hopefully printing it now? : " << endl; 
    //if(write(STDOUT_FILENO, mymsg.mtext, size) == -1)
    //  perror("Failed to write to standard output!\n"); 


  }

  ostringstream oss;
  oss << "ipcrm -q " << msqid; 
  string command = oss.str(); 

  if(system(command.c_str()) != 0)  //also errors every time, but not main focus here 
    perror("Failed to clean up message queue!"); 
}

What is going on here? I thought I had the buffer procedure working fine and with sufficient space..

Deanie
  • 2,316
  • 2
  • 19
  • 35
norman
  • 5,128
  • 13
  • 44
  • 75
  • This: `strlen(message)` in conjunction with a char buffer containing exactly 1024 `'a'` chars **and no set terminator** is not going to play nice with a fairily important concept: **predictability**. The undefined behavior is a bonus. – WhozCraig Apr 20 '13 at 02:55
  • So, in short, I need to properly null-terminate my "strings" ? – norman Apr 20 '13 at 03:09
  • 1
    That is a substantial issue, and needs to be addressed. Another (and likely the root of your main problem) is the use of `len` when it is unintialized in the parent process (see your `msgrcv()` call). Note you set it in the if-child area of the `fork()` if-else section, but it is *not* set in the else-parent section at all. Therefore it is indeterminate, and will thus produce undefined behavior. Always initialize your variables on declaration, whether you think they need it or not. At least then you will have predictable failure if your logic is wrong. – WhozCraig Apr 20 '13 at 04:38
  • `if(msqid = msgget(IPC_PRIVATE, PERMS) == -1)` needs to be `if((msqid = msgget(IPC_PRIVATE, PERMS)) == -1)` – suspectus Apr 20 '13 at 07:22

0 Answers0