For school, I have to create a server-client communication through Unix signals and only with SIGUSR1 and SIGUSR2.
Client program
#include "common.h"
int s_received = 0;
int ft_atoi(const char *nptr)
{
int i;
int sign;
int res;
i = 0;
sign = 1;
res = 0;
while (nptr[i] == ' ' || (nptr[i] >= 9 && nptr[i] <= 13))
i++;
if (nptr[i] == '+' || nptr[i] == '-')
{
if (nptr[i] == '-')
sign = -1;
i++;
}
while (nptr[i] >= '0' && nptr[i] <= '9')
{
res = res * 10 + (nptr[i] - '0');
i++;
}
return (res * sign);
}
Then in handle_char, I do a binary operation on every bit to send either a 1 or a 0 to the server, using kill function with SIGUSR1 and SIGUSR2. After each signal is sent, the process waits for a server response before it continues:
void handle_char(int pid, unsigned char c)
{
int i;
unsigned char mask;
i = 7;
mask = 1u << i;
while (mask)
{
s_received = 0;
if (mask & c)
kill(pid, SIGUSR1);
else
kill(pid, SIGUSR2);
if (!s_received)
pause();
i--;
mask >>= 1;
}
}
Then I handle my string to process each char of my string, through the handle_char function.
void handle_string(int pid, char *msg)
{
int i;
i = -1;
while (msg[++i])
handle_char(pid, msg[i]);
handle_char(pid, 0);
}
When a signal is received from the server, this function is called either to put my global variable to 1, so I can send the next bit, or sending me the final signal meaning I have sent all of my chars to the server and the server has received them.
void handler(int signal, siginfo_t *client, void *ucontext)
{
(void)ucontext;
if (signal == SIGUSR1)
s_received = 1;
else if (signal == SIGUSR2)
{
ft_putstr_fd("Message succesfully sent to the server, Congrats !", 1);
exit(EXIT_SUCCESS);
}
}
First I take user input string and server PID:
int main(int argc, char *argv[])
{
pid_t pid;
struct sigaction sig;
if (argc != 3)
{
ft_putstr_fd("Usage : ./client <pid> <message_to_send>\n", 1);
exit(EXIT_FAILURE);
}
sig.sa_flags = SA_SIGINFO | SA_RESTART;
sig.sa_sigaction = handler;
sigemptyset(&(sig.sa_mask));
sigaction(SIGUSR2, &sig, NULL);
sigaction(SIGUSR1, &sig, NULL);
pid = ft_atoi(argv[1]);
if (!pid)
{
ft_putstr_fd("PID of , is not possible..., please stop joking enter the real value!\n", 1);
exit(EXIT_FAILURE);
}
handle_string(pid, argv[2]);
}
Server program
#include "common.h"
//int f_msg = 1;
Only checking if the sender process is still ongoing:
void is_process_running(pid_t pid)
{
if (kill(pid, 0) < 0)
{
ft_putstr_fd(("An error occured during the process, exiting...\n"), 1);
exit(EXIT_FAILURE);
}
}
Here each time a signal is received from a client, I stack into my unsigned char variable, when my shift value is negative it means that I received a full char so now I can print it and reset the shift value. Each time a signal is received a signal is sent back to confirm this.
void handler(int signal, siginfo_t *client, void *ucontext)
{
(void)ucontext;
static int shift = -1;
static unsigned char c;
is_process_running(client->si_pid);
/*if (f_msg)
{
ft_putstr_fd("\nMessage from process ", 1);
ft_putnbr_fd((int)client->si_pid, 1);
ft_putstr_fd(": ", 1);
f_msg = 0;
}*/
if (shift < 0)
shift = 7;
if (signal == SIGUSR1)
c |= (1 << shift);
shift--;
if (shift < 0 && c)
{
ft_putchar_fd(c, 1);
c = 0;
}
else if (shift < 0 && !c)
kill(client->si_pid, SIGUSR2);
//f_msg = 1;
kill(client->si_pid, SIGUSR1);
}
Printing sever pid and initializing signal handler:
int main(int argc, char *argv[])
{
int i;
pid_t pid;
SA sig;
sig.sa_flags = SA_SIGINFO | SA_RESTART;
sig.sa_sigaction = handler;
sigemptyset(&(sig.sa_mask));
pid = getpid();
ft_putstr_fd("Server PID is : ", 1);
ft_putnbr_fd(pid, 1);
ft_putchar_fd('\n', 1);
sigaction(SIGUSR2, &sig, NULL);
sigaction(SIGUSR1, &sig, NULL);
while (1)
sleep(1);
}
and here is my header:
#ifndef COMMON_H
#define COMMON_H
#define SA struct sigaction
#include <stdlib.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
void ft_putchar_fd(char c, int fd);
void ft_putnbr_fd(int n, int fd);
void ft_putstr_fd(char *s, int fd);
#endif
ft_putchar :
void ft_putchar_fd(char c, int fd)
{
write(fd, &c, 1);
}
My code works well. So I'd like some review of improvement that could be made.
I'm actually surprised that code supports Unicode characters as I have not made any changes to make that happen. For example, when sending "hello 😃" from client, the server is able to print the "😃".