2

I had a task from school in which I need to write a client that will send string using signals (only SIGUSR1 as 1 or SIGUSR2 as 0) to server, which then should display this string. The problem is that server can normally handle only a little amount of symbols. In other cases it pauses with client or just shows weird symbols. I've tried to write in different ways using global variable in client for confirmation from server (with and without pausing the client), using usleep()(100/600/1000/10000), using pause(), result is always the same as when I fast call client again and again.

I'm writing it using VirtualBox Ubuntu.

UPD: Problem solved using sleep (5) instead of pause() in client and increasing usleep() up to 1000

Client:

#include "minitalk.h"

int g_recieve;

void    sending_bits(char c, int pid)
{
    int i;

    i = 128;
    while(i >= 1)
    {
        if (g_recieve == 1)
        {
            if (i & c)
            {
                if (kill(pid, SIGUSR1) == -1)
                    errors("Error in sending signal!\n");
            }
            else
            {
                if (kill(pid, SIGUSR2) == -1)
                    errors("Error in sending signal!\n");
            }
            i /= 2;
            g_recieve = 0;
        }
        //usleep(600);
    }
}


int send_str(int pid, char *s)
{
    int i;

    i = 0;
    while (s[i])
    {
        sending_bits(s[i], pid);
        i++;
    }
    return (0);
}

void    cl_handler(int signum, siginfo_t *siginfo, void *context)
{
    (void)context;
    (void)siginfo;
    (void)signum;
    g_recieve = 1;
    write(1, "Recieved signal from server\n", 28);
    return ;
}

int main(int argc, char **argv)
{
    struct sigaction    sigac;

    g_recieve = 1;
    sigemptyset(&sigac.sa_mask);
    sigaddset(&sigac.sa_mask, SIGINT);
    sigaddset(&sigac.sa_mask, SIGQUIT);
    sigaddset(&sigac.sa_mask, SIGUSR1);
    sigac.sa_flags = SA_SIGINFO;
    sigac.sa_sigaction = cl_handler;
    if (sigaction(SIGUSR2, &sigac, NULL) == -1)
        errors("Error in client sigaction\n");
    if (ft_atoi(argv[1]) < 0)
        errors("Wrong PID!\n");
    if (argc == 3)
        send_str(ft_atoi(argv[1]), argv[2]);
    else
        errors("Wrong arguments!\n");
    while (1)
        pause ();
    return (0);
}

Server:

#include "minitalk.h"

void    sv_handler(int signum, siginfo_t *siginfo, void *unused)
{
    static int  ascii = 0;
    static int  power = 0;

    (void)unused;
    if (signum == SIGUSR1)
        ascii += (128 >> power);
    power += 1;
    if (power == 8)
    {
        ft_putchar(ascii);
        power = 0;
        ascii = 0;
    }
    if (siginfo->si_pid == 0)
        errors("Server didn't get client's PID\n");
    if (kill(siginfo->si_pid, SIGUSR2) == -1)
        errors("Error in returning signal!\n");
}

int main(int argc, char **argv)
{
    struct sigaction    sigac;

    (void)argv;
    if (argc != 1)
        errors("Error arguments\n");
    write(1, "Server started!\nPID: ", 21);
    ft_putnbr(getpid());
    write(1, "\n", 1);
    sigemptyset(&sigac.sa_mask);
    //sigaddset(&sigac.sa_mask, SIGINT);
    //sigaddset(&sigac.sa_mask, SIGQUIT);
    sigac.sa_flags = SA_SIGINFO;
    sigac.sa_sigaction = sv_handler;
    if ((sigaction(SIGUSR1, &sigac, 0)) == -1)
        errors("Error sigaction\n");
    if ((sigaction(SIGUSR2, &sigac, 0)) == -1)
        errors("Error sigaction\n");
    while (1)
        pause();
    return (0);
}
Makar
  • 21
  • 4
  • 3
    Your instructor has, very deliberately and with malice aforethought, assigned you a task which is the moral equivalent of driving screws with a hammer. Signals are for *events*, they are not for *data*. When you try to send gobs and gobs of signals, you always have horrible problems, because they don't queue well, because they were never designed for IPC. – Steve Summit Nov 12 '21 at 18:00
  • @SteveSummit is right: signals are a very, very poor fit for this problem. What does _"fast call client again and again"_ mean? Do you mean that you invoke the client program several times, simultaneously or overlapping, each with the same server PID as its target? That won't work without some sort of coordination between clients. – pilcrow Nov 12 '21 at 18:43
  • 1
    Does this answer your question? [How can you send a string given has argument to a program to another program using UNIX signals in C?](https://stackoverflow.com/questions/67985972/how-can-you-send-a-string-given-has-argument-to-a-program-to-another-program-usi) – Shawn Nov 12 '21 at 20:29
  • @Shawn Thanks for taking the time to dig up the link. But, [as I'm sure you already know] it's full of race conditions. The sender `usleep` can race against receiver. There is no guarantee that the sender won't send (e.g.) _two_ `SIGUSR1` that are seen as a _single_ `SIGUSR1` by the receiver. Or, that the two signals are delivered in order. In the receiver, it needs `volatile` at a minimum and/or atomics for handler/main sync. Re: https://man7.org/linux/man-pages/man7/signal.7.html Ironically, _if_ Posix/RT signals are used, they are guaranteed queued and delivered in order. – Craig Estey Nov 12 '21 at 20:53
  • @CraigEstey Yeah, it's terrible. There is no good approach within the problem's constraints. – Shawn Nov 12 '21 at 21:17
  • @pilcrow Yeah, sorry for my English. I meant i call client with server's PID, sending str, then i quit it and recall the same client with same server's PID. After a few calls client and/or server stops or server shows weird symbols. – Makar Nov 13 '21 at 11:55
  • @Shawn thanks, that's literally my task, but the problem remains. – Makar Nov 13 '21 at 11:59
  • Please add as answer if it solved. Dont edit solution into the question – Suraj Rao Nov 19 '21 at 13:54
  • This is impossible to do robustly without client and servers that don't have a parent child relationship because of how pids are racy in such cases. With a parent/child client-servers, I would require that each signal be acknowledged by the receiver before a next signal is sent (the sender can wait for the acknowledgement in sigsuspend). That should take care of the otherwise possible potential signal merging/reordering and eliminate the need for arbitrarily chosen sleep periods. – Petr Skocik Nov 19 '21 at 15:31

1 Answers1

0

Problem solved using sleep(5) instead of pause() in client and increasing usleep() in client up to 1000.

ouflak
  • 2,458
  • 10
  • 44
  • 49
Makar
  • 21
  • 4