Skip to content

iurilandolt/ft_irc

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

46 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

IRC Server

This is an IRC server, serving as an introduction to socket programming in C and C++. It is compatible with most IRC clients but was specifically designed to integrate with HexChat. The server complies with standard IRC protocols described in IRC v3.

1. Server Socket Creation

_fd = socket(AF_INET, SOCK_STREAM, 0)
  • IPv4, TCP, IPPROTO_TCP

    We use AF_INET as the first argument to specify that we want to create a socket that uses the IPv4 protocol for communication over the internet. Here's a breakdown of why each argument is used:

Arguments of socket()

Domain (AF_INET):

  • AF_INET stands for "Address Family: Internet".
  • It specifies that the socket will use the IPv4 protocol, which is the most common protocol for internet communication.
  • This tells the system that we want to create a socket that can communicate over the internet using IPv4 addresses.

Type (SOCK_STREAM):

  • SOCK_STREAM specifies that the socket will use a reliable, connection-oriented communication method.
  • This means we want to use TCP (Transmission Control Protocol), which ensures that data is delivered in the same order it was sent and without errors.

Protocol (0):

  • 0 means we want to use the default protocol for the specified type.
  • For SOCK_STREAM, the default protocol is TCP.

Example

  • AF_INET: Use the IPv4 protocol for internet communication.
  • SOCK_STREAM: Use a reliable, connection-oriented communication method (TCP).
  • 0: Use the default protocol for SOCK_STREAM, which is TCP.

Visual Representation

_fd = socket(AF_INET, SOCK_STREAM, 0)
   |       |      |
   |       |      |
   |       |      +--- Protocol: Default protocol (0 for TCP)
   |       +---------- Type: Communication style (SOCK_STREAM for TCP)
   +------------------ Domain: Network type (AF_INET for IPv4)

So, by using AF_INET as the first argument, we are specifying that we want to create a socket that can communicate over the internet using IPv4 addresses.

2. Server Socket Configuration

struct sockaddr_in addr;
addr.sin_family = AF_INET;         // IPv4
addr.sin_port = htons(port);       // Port number
addr.sin_addr.s_addr = INADDR_ANY; // Accept connections from any IP
  • bind(): Associates socket with specific address and port
  • listen(): Marks socket as passive to accept incoming connections
  • fcntl(): Sets socket to non-blocking mode
    • Socket operations return immediately
    • If operation can't be completed, returns error (usually EAGAIN/EWOULDBLOCK)
    • Program can continue executing other tasks
    • Typically used with poll() or select() to check when socket is ready
    • Server needs to handle multiple clients simultaneously
    • Can't afford to wait/block on any single client
    • poll() is used to monitor multiple sockets for activity
    • More efficient use of resources than creating thread per client
  • setsockopt(): Sets socket options (here enables address reuse, allowing multiple clients with the same network address)

Active vs Passive Sockets

A passive socket is used by a server to listen for incoming connection requests from clients. It passively waits for connections.

Application Kernel

|--- socket() ---------->|
|                        |
|--- bind() ------------>|
|                        |--- associate socket with address/port
|<--- bind complete -----|
|                        |
|--- listen() ---------->|
|                        |--- mark socket as passive
|<--- ready to accept ---|
|                        |
|--- accept() ---------->|
|                        |--- wait for connection request
|<--- connection request-|
|                        |--- establish connection
|<--- new socket --------|
|                        |
|--- handle client ------|                       

An active socket is used by a client to initiate a connection to a server. It actively seeks to establish a connection.

Application Kernel

|--- socket() ---------->|
|                        |
|--- connect() --------->|
|                        |--- establish connection
|<--- connection ready --|
|                        |
|--- send/receive data -->|
|                        |--- handle data transfer
|<--- data received -----|

Blcoking vs Non-Blcoking I/O

In blocking I/O, the application waits for the kernel to copy the data before continuing. In non-blocking I/O, the application can continue executing other tasks if the data is not immediately available

Blcoking I/O

Application                Kernel
  |                        |
  |--- read data --------->|
  |                        |--- wait for data
  |                        |--- copy data
  |<--- return data -------|
  |                        |

Non-Blocking I/O

Application                Kernel
  |                        |
  |--- read data --------->|
  |                        |--- check if data is available
  |                        |--- if no data, return immediately with error (EAGAIN/EWOULDBLOCK)
  |<--- return error ------|
  |                        |
  |--- continue other tasks|
  |                        |
  |--- poll/select --------|
  |                        |--- wait for data to be ready
  |                        |--- data ready
  |<--- data ready --------|
  |                        |
  |--- read data again --->|
  |                        |--- copy data
  |<--- return data -------|

3. Client Socket Creation

int new_fd = accept(_fd, NULL, NULL);

  • sockfd: The listening socket file descriptor (passive socket)
  • addr: Pointer to a sockaddr structure where client address info will be stored
  • addrlen: Pointer to length of the addr structure

4. Client Socket Configuration

int new_fd = accept(_fd, NULL, NULL);
if (fcntl(new_fd, F_SETFL, O_NONBLOCK) == -1)
  • IRC protocol identifies users by nickname/username, not IP address, there is no need to save the client's network address unless we are planning on:
    • Access control based on IP
    • Logging/analytics
    • Geographic features
    • Security features like banning IPs

5. Key Aspects of poll()

The poll() function is used for monitoring multiple file descriptors to see if I/O is possible. Here's how it works:

int poll(struct pollfd *fds, nfds_t nfds, int timeout);

struct pollfd {
    int   fd;      // file descriptor
    short events;  // events to look for
    short revents; // events that occurred
};

Events Commonly Monitored

  • POLLIN: Data available to read
  • POLLOUT: Writing now possible
  • POLLERR: Error condition
  • POLLHUP: Hangup (client disconnected)

Event Bitmasks

  • POLLIN = 0x0001 // 0000 0000 0000 0001
  • POLLOUT = 0x0004 // 0000 0000 0000 0100
  • POLLERR = 0x0008 // 0000 0000 0000 1000

Multiple Events

  • Example: both read and error
    revents = POLLIN | POLLERR  // 0000 0000 0000 1001

Efficient Event Checking

  • Bitwise AND (&) efficiently checks for specific events:
    if (it->revents & POLLIN)
  • This is more efficient than:
    • Using multiple variables for each event type
    • Using regular boolean operations
    • Checking each event separately
  • The bitmask approach allows for compact storage and fast checking of multiple event flags in a single integer.

About

Internet Relay Chat - Socket Programming

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 2

  •  
  •