2

This is my project to do list:

  • You must create a communication program in the form of a client and server.
  • The server must be launched first, and after being launched it must display its PID.
  • The client will take as parameters: The server PID and the string that should be sent.
  • The client must communicate the string passed as a parameter to the server. Once the string has been received, the server must display it.
  • Communication between your programs should ONLY be done using UNIX signals.
  • Your server should be able to receive strings from several clients in a row, without needing to be restarted.
  • You can only use the two signals SIGUSR1 and SIGUSR2.

I'm only allowed to use the following functions:

  • signal • sigemptyset • sigaddset • sigaction • kill • getpid
  • write • malloc • free • pause • sleep • usleep • exit

I've done the easy part: getting the Server PID. Now I feel completely lost since I can't find anything related to this exercise.

  • 3
    Hint: use the two singals to represent the binary values 0 and 1, then send the signals in sequence corresponding to the binary values of the string. – dbush Jun 15 '21 at 12:09
  • @dbush – Clever! I probably would have gone down a rabbit hole looking for some other solution. – Yimin Rong Jun 15 '21 at 12:15
  • @dbush I dont know if the order of signal delivery is guaranteed. (otherwise some kind of acknowledgement should be implementerd as well, including timeout/resend. Alternating bit protocol?) – wildplasser Jun 15 '21 at 12:52
  • @dbush That sounds slightly less primitive than sending smoke signals :) – Lundin Jun 15 '21 at 13:29
  • If you can use `write` then just write to a pipe or file? – Lundin Jun 15 '21 at 13:30
  • 1
    @Lundin you can't use read so... but I'm trying something now, I'll share it after! – Diogo Cavaleiro Jun 15 '21 at 13:42
  • You may find some of the information in [Exitcodes bigger than 255 — possible?](https://stackoverflow.com/q/179565/15168) useful — particularly the `SA_SIGINFO` part. That's of relevance when trying to determine which process sent the signal to the server process, which matters when you're dealing with signals from multiple clients. Note that sending one bit per call to `kill()` is not good for high bandwidth communication. – Jonathan Leffler Jun 15 '21 at 17:06
  • This project doesn't need to handle multiple clients but I also thought about it, I have a good idea of how to handle them but, since its not requested, I didn't implemented it, I might do it later just to see how far I can push it. Thank you @JonathanLeffler – Diogo Cavaleiro Jun 17 '21 at 12:31

1 Answers1

0

I've done the following:

  1. On the Client side, I've done this function to send bit by bit a char: (SIGUSR1 is 1 and SIGUSR2 is 0)

    int send_char_to_server(unsigned char c, int server_pid)
    {
        unsigned char   bit;
    
        bit = 0b10000000;
        while (bit)
        {
            if (bit & c)
            {
                if (kill(server_pid, SIGUSR1) == -1)
                    return (0);
            }
            else
            {
                if (kill(server_pid, SIGUSR2) == -1)
                    return (0);
            }
            bit >>= 1;
            usleep(100);
        }
        return (1);
    }
    

    and I've also implemented a feedback handler that simply receives SIGUSR1 and exits correctly, if it takes more than 5sec to get feedback it displays an error message.


  1. On the Server side, I've created this struct and declared it has a global variable in order to access data, since I can't pass it as an argument:

    typedef struct s_data
    {
        char            buffer[MAX_CHARS];
        unsigned char   c;
        int             index;
        int             client_pid;
    }               t_data;
    

    And I've also done 2 functions to handle both signals (SIGUSR1 and SIGUSR2):

    void    bit_on_handler(int sig, siginfo_t *info, void *ucontext)
    {
        unsigned char   bit;
    
        (void)ucontext;
        (void)sig;
        bit = 0b10000000;
        g_data.c |= bit >> g_data.index;
        g_data.index++;
        if (!g_data.client_pid)
            g_data.client_pid = info->si_pid;
    }
    void    bit_off_handler(int sig, siginfo_t *info, void *ucontext)
    {
        (void)ucontext;
        (void)sig;
        g_data.index++;
        if (!g_data.client_pid)
            g_data.client_pid = info->si_pid;
    }
    

    Since my server is not supposed to quit after receiving a message I've done the loop_handler function that adds the character received (the 8 signals sequence) to my buffer and resets the needed values back to 0.

    void    loop_handler(void)
    {
        int i;
    
        i = 0;
        while (1)
        {
            pause();
            if (g_data.index == 8)
            {
                while (g_data.buffer[i] && i < MAX_CHARS)
                    i++;
                if (i == MAX_CHARS)
                    error_handler(STR_TOO_LONG);
                if (g_data.c == 0)
                    null_handler(i);
                g_data.buffer[i] = g_data.c;
                g_data.c = 0;
                g_data.index = 0;
                i =  0;
            }
        }
    }
    

    My null_handler() simply displays the string, sends the SIGUSR1 signal to the Client, sets client_pid back to 0 and the buffer gets emptied.


(this is my 1st post, if you have any tips please feel free to send them, there's always room for improvement)