Home > database >  C Unix msgsnd not sending some messages
C Unix msgsnd not sending some messages

Time:10-18

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);
}

CodePudding user response:

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.

CodePudding user response:

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.

  • Related