/ft_irc

Yet Another Internet Relay Chat

Primary LanguageC++GNU General Public License v2.0GPL-2.0

Yet Another Internet Relay Chat

FT_IRC

Description

Create your own IRC server in C++, fully compatible with an official client.

The keyword in IRC is "Relay." While "Internet" and "Chat" have obvious
meanings, "Relay" sounds a bit more mysterious. Let's have a look at the
basic concept of IRC in order to discover the meaning behind the term.
IRC, in its simplest form, is made up of two programs—a server
program that accepts connections and a client program that connects
to the server.
Of course, it isn't absolutely necessary to use a special program—
the server would view a simple network connection between you and
the server as a client. However, a client program handles some necessary
procedures automatically and provides a better and simpler user interface
than the more technical messages the client and server exchange.
IRC servers connect to each other via an IRC network of servers. Let's
use a very simple model of an IRC network for our example: two servers
and two clients. The servers are connected to each other, and each has a
client (a user) connected to it. The structure would look like this:
Screen Shot 2024-02-29 at 11 21 02 AM Screen Shot 2024-02-29 at 11 26 58 AM

Networking API

All networking API function are considered equivalent to system calls such as read{.verbatim} or write{.verbatim}, they lay in man(2).

#define INADDR_ANY              (u_int32_t)0x00000000

in_addr_t inet_addr(const char *cp);

uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);

int socket(int domain, int type, int protocol);
int bind(int sock_fd, struct sockaddr *addr, socklen_t addr_size);

int listen(int socket, int backlog);
int connect(int socket, const struct sockaddr *address, socklen_t address_len);

ssize_t send(int socket, const void *buffer, size_t length, int flags);
ssize_t recv(int socket, void *buffer, size_t length, int flags);

socket(){.verbatim} and struct sockaddr{.verbatim}

When socket(){.verbatim} is created, which is just allocating a file resource in the OS, by specifiying the protocol family and type, and which mode of transmission i.e. UDP or TCP. It requires additional information on the address itself, namelty the host and the port, which both should be in machine encoding i.e. same behaviour as hton(){.verbatim}.

  • Except that inet_addr(){.verbatim} returns the address in machine encoding already

As a legacy, there are two types struct sockaddr{.verbatim} and struct sockaddr_in{.verbatim}, they represent the same information, but the later is more convenient to work with.

At last, both the socket and the address are entangeled using bind(){.verbatim}

listen(){.verbatim}, accept(){.verbatim} and poll(){.verbatim} multiple clients

When getting a socket for the server, we may listen(){.verbatim} for incoming connections. Each new connection is a new socket(){.verbatim} associated with a client, that is created after calling accept(){.verbatim}.

However, listen(){.verbatim} runs asynchronously, accept(){.verbatim} should be called for as many clients that ahve sent the request. Yet, it blocks e.g. same as waiting for IO. Thus if no new request has been sent, accept(){.verbatim} will await and blocks the process.

This can be resolved using multitasking, by telling the OS to not block using fcntl(){.verbatim} to alter the flags of the socket file. And then use poll(){.verbatim} to fetch only the ones that are ready to be fetched. By setting event POLLIN{.verbatim} on creation, the OS would set flags in return when it is unblocking. Now instead of blocking the process, an EWOULDBLOCK{.verbatim} (or EAGAIN{.verbatim}) would be raised, resolving the block.

recv(){.verbatim} data

For each client that has sent, we may recv(){.verbatim} some data to be put in a buffer, the length of the data is returned, and a closed connection would return 0. However, the total length of the incoming data may overfit the size of the buffer, thus it may require multiple reads until it blocks by raising errno{.verbatim}.

Sending Data

Internet Relay Chat (RFC1459)

Server

Client

Commands

References

visual_reference

Stackoverflow

Screen Shot 2024-02-29 at 12 28 10 PM Screen Shot 2024-02-29 at 11 50 41 AM