Skip to main content

Overview

The server is the receiving end of the Minitalk communication system. It listens for UNIX signals (SIGUSR1 and SIGUSR2) and reconstructs the original message by interpreting each signal as a bit value.

Source Code Location

server.c - Lines 1-46

Architecture

The server uses a signal-driven architecture:
  1. Displays its Process ID (PID) on startup
  2. Registers signal handlers for SIGUSR1 and SIGUSR2
  3. Enters an infinite loop waiting for signals
  4. Reconstructs characters bit-by-bit through the signal handler
  5. Outputs completed characters using ft_printf

Signal Handler Function

handle_sigusr()

void	handle_sigusr(int sigsent)
{
	static size_t	c = 0;
	static size_t	i = 0;

	if (sigsent == SIGUSR1)
		c = c << 1;
	else if (sigsent == SIGUSR2)
		c = (c << 1) | 1;
	i++;
	if (i == 8)
	{
		ft_printf("%c", c);
		i = 0;
		c = 0;
	}
}
Lines: 16-32 This is the core signal handler that receives individual bits and reconstructs characters.
sigsent
int
required
The signal received: SIGUSR1 (representing bit 0) or SIGUSR2 (representing bit 1)

Static Variables

The function maintains state across invocations using static variables:
c
size_t
default:"0"
Character accumulator - Stores the character being built bit by bit. Resets to 0 after each complete character (8 bits).
i
size_t
default:"0"
Bit counter - Tracks how many bits have been received for the current character (0-7). Resets to 0 after reaching 8.

Bit Shifting Logic

The handler uses left-shift operations to build characters from individual bits:

SIGUSR1 Handler (Bit = 0)

c = c << 1;
  • Shifts all existing bits in c one position to the left
  • The rightmost bit becomes 0
  • Example: 0b00000101 becomes 0b00001010

SIGUSR2 Handler (Bit = 1)

c = (c << 1) | 1;
  • Shifts all existing bits in c one position to the left
  • Uses bitwise OR with 1 to set the rightmost bit to 1
  • Example: 0b00000101 becomes 0b00001011

Complete Example

To receive the character ‘A’ (ASCII 65 = 0b01000001):
SignalOperationResult (binary)Result (decimal)
SIGUSR1c << 10b000000000
SIGUSR2(c << 1) | 10b000000011
SIGUSR1c << 10b000000102
SIGUSR1c << 10b000001004
SIGUSR1c << 10b000010008
SIGUSR1c << 10b0001000016
SIGUSR1c << 10b0010000032
SIGUSR2(c << 1) | 10b0100000165 (‘A’)
After 8 bits, i == 8 triggers output and reset.

Character Output

if (i == 8)
{
	ft_printf("%c", c);
	i = 0;
	c = 0;
}
When 8 bits have been received:
  1. The accumulated character c is printed using ft_printf
  2. Both counters are reset for the next character
  3. The process repeats for subsequent characters

Main Function

main()

int	main(void)
{
	ft_printf("SUCCESS!, Server is ready :D! The PID: %d\n", getpid());
	ft_printf("Waiting fot the string...\n");
	signal(SIGUSR1, handle_sigusr);
	signal(SIGUSR2, handle_sigusr);
	while (1)
	{
		pause();
	}
	return (0);
}
Lines: 34-45

Initialization Sequence

1

Display PID

Uses getpid() to retrieve the server’s process ID and displays it. The client needs this PID to send signals.
ft_printf("SUCCESS!, Server is ready :D! The PID: %d\n", getpid());
2

Display Ready Message

Informs the user that the server is waiting for incoming messages.
ft_printf("Waiting fot the string...\n");
3

Register Signal Handlers

Both SIGUSR1 and SIGUSR2 are registered to call handle_sigusr.
signal(SIGUSR1, handle_sigusr);
signal(SIGUSR2, handle_sigusr);
The signal() function signature:
void (*signal(int sig, void (*func)(int)))(int);
4

Enter Wait Loop

The infinite loop with pause() suspends the process until a signal is received.
while (1)
{
    pause();
}
pause() blocks execution until any signal is received, then returns control to the loop.

Signal Registration Details

SIGUSR1
int
User-defined signal 1. In Minitalk, this represents a 0 bit.
SIGUSR2
int
User-defined signal 2. In Minitalk, this represents a 1 bit.
handle_sigusr
void (*)(int)
Function pointer to the signal handler. Called automatically when the signal is received.

Dependencies

Included Headers

#include "../libft/ft_printf.h"
#include <signal.h>

ft_printf.h

Custom printf implementation for formatted output

signal.h

POSIX signal handling functions and constants

System Calls Used

getpid
pid_t (void)
Returns the process ID of the calling process. Used to display the server’s PID for client connection.
signal
void (*)(int, void (*)(int))
Registers a signal handler function. Maps SIGUSR1 and SIGUSR2 to handle_sigusr.
pause
int (void)
Suspends the calling process until a signal is received. Returns -1 when interrupted by a signal handler.

Execution Flow


Key Features

Stateful Reception

Uses static variables to maintain state across signal handler invocations

Bit-by-Bit Assembly

Reconstructs characters from 8 individual signal transmissions

Non-Blocking

Uses pause() for efficient CPU usage while waiting for signals

Binary Encoding

Maps SIGUSR1 to 0 and SIGUSR2 to 1 for binary data transmission

Limitations and Considerations

Signal Reliability: Signals can be lost if multiple signals arrive before the handler completes. This implementation assumes signals are processed sequentially.
The server has no built-in timeout or termination mechanism. It must be manually terminated (e.g., with SIGINT/Ctrl+C).
Performance: The pause() system call is CPU-efficient, suspending the process completely until a signal arrives.

Build docs developers (and LLMs) love