Skip to content
/ 42_irc Public

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

License

Notifications You must be signed in to change notification settings

faleite/42_irc

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

 ██╗  ██████╗    ██████╗
 ██║  ██╔══██╗  ██╔════╝
 ██║  ██████╔╝  ██║
 ██║  ██╔══██╗  ██║
 ██║  ██║  ██║  ╚██████╗
 ╚═╝  ╚═╝  ╚═╝   ╚═════╝
    Internet Relay Chat

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

Skills Grade
[Network & system administration] [Object-oriented programming] [Unix] [Rigor] ✅ 125%

Mandatory part

External functs.

Essas funções são todas utilizadas para manipulação de sockets e operações
de entrada/saída no ambiente Unix, com compatibilidade com C++ 98.

Funcoes externas Header Brief
socket <sys/socket.h> Cria um ponto de comunicação, usado para comunicação de rede.
close <unistd.h> Fecha um descritor de arquivo, incluindo sockets.
setsockopt <sys/socket.h> Configura opções de um socket, como tempo de espera ou buffer.
getsockname <sys/socket.h> Recupera o endereço associado a um socket.
getprotobyname <netdb.h> Recupera informações sobre protocolos a partir de um nome.
gethostbyname <netdb.h> Recupera o endereço IP de um host dado o nome de domínio.
getaddrinfo <netdb.h> Resolve hostnames para endereços IP, substituto moderno de gethostbyname.
freeaddrinfo <netdb.h> Libera a estrutura alocada pela função getaddrinfo.
bind <sys/socket.h> Associa um endereço ao socket.
connect <sys/socket.h> Conecta um socket a um endereço remoto.
listen <sys/socket.h> Marca um socket para aceitar conexões de entrada.
accept <sys/socket.h> Aceita uma conexão de entrada em um socket.
htons <arpa/inet.h> Converte números de porta de host para rede em ordem de bytes.
htonl <arpa/inet.h> Converte um inteiro de 32 bits de host para rede em ordem de bytes.
ntohs <arpa/inet.h> Converte números de porta de rede para host em ordem de bytes.
ntohl <arpa/inet.h> Converte um inteiro de 32 bits de rede para host em ordem de bytes.
inet_addr <arpa/inet.h> Converte um endereço IP no formato string para um valor numérico.
inet_ntoa <arpa/inet.h> Converte um valor numérico de IP para uma string legível.
send <sys/socket.h> Envia dados através de um socket.
recv <sys/socket.h> Recebe dados de um socket.
signal <signal.h> Configura manipuladores de sinais de sistema.
sigaction <signal.h> Define ações personalizadas para sinais.
lseek <unistd.h> Move o ponteiro de leitura/escrita de um arquivo para uma nova posição.
fstat <sys/stat.h> Obtém informações sobre um arquivo aberto.
fcntl <fcntl.h> Manipula descritores de arquivos, como bloquear ou configurar flags.
poll <poll.h> Monitora múltiplos descritores de arquivo para verificar eventos.
IRC server in C++ 98.
  • Você não deve desenvolver um cliente.
  • Você não deve lidar com a comunicação de servidor para servidor.
  • ./ircserv <port> <password>
    • port: O número da porta na qual seu servidor IRC estará ouvindo as conexões de IRC de entrada.
    • password: A senha da conexão. Será necessário para qualquer cliente de IRC que tente se conectar ao seu servidor.
Requirements
  • O servidor deve ser capaz de lidar com vários clientes ao mesmo tempo e nunca travar.
  • Forking não é permitido. Todas as operações de I/O devem não bloquear.
  • Apenas 1 poll() (ou equivalente) pode ser usado para lidar com todas essas operações
    (ler, escrever, mas também ouvir e assim por diante).

[!NOTE] Como você precisa usar descritores de arquivo sem bloqueio, é possível usar funções de read/recv ou write/send sem poll()
(ou equivalente), e seu servidor não estaria bloqueando. Mas consumiria mais recursos do sistema.
Assim, se você tentar read/recv ou write/send em qualquer descritor de arquivo sem usar poll() (ou equivalente), sua nota será 0.

  • Existem vários clientes de IRC. Você tem que escolher um deles como referência.
    Seu cliente de referência será usado durante o processo de avaliação.
  • Seu cliente de referência deve ser capaz de se conectar ao seu servidor sem encontrar nenhum erro.
  • A comunicação entre cliente e servidor deve ser feita via TCP/IP (v4 ou v6).
  • Usar seu cliente de referência com seu servidor deve ser semelhante a usá-lo com qualquer servidor IRC oficial.
    No entanto, você só precisa implementar os seguintes recursos:
    • Você deve ser capaz de autenticar, definir um apelido, um nome de usuário, ingressar em um canal,
      enviar e receber mensagens privadas usando seu cliente de referência.
    • Todas as mensagens enviadas de um cliente para um canal precisam ser encaminhadas para todos os
      outros clientes que se juntaram ao canal.
    • Você deve ter operadores e usuários regulares.
    • Então, você tem que implementar os comandos que são específicos para os operadores de canal:
      • KICK - Ejetar um cliente do canal
      • INVITE - Convidar um cliente para um canal
      • TOPIC - Alterar ou visualizar o canal
      • MODE - Alterar o modo do canal:
        • i: Definir/remover o canal somente para convite
        • t: Definir/remover as restrições dos operadores topo o comando TOPIC para canal
        • k: Definir/remover a chave do canal (senha)
        • o: Dar/retirar privilégio do operador de canal
        • l: Defina/remova o limite do usuário para o canal
  • Claro, espera-se que você escreva um código limpo.
For MacOS only

Como o MacOS não implementa write() da mesma maneira que outros sistemas operacionais Unix,
você tem permissão para usar fcntl(). Você deve usar descritores de arquivo no modo sem bloqueio
para obter um comportamento semelhante ao de outros sistemas operacionais Unix.

No entanto, você tem permissão para usar fcntl() apenas da seguinte forma:
fcntl(fd, F_SETFL, O_NONBLOCK); Qualquer outro sinalizador é proibido.

Test Example
  • Verifique absolutamente todos os erros e problemas possíveis (receber dados parciais,
    baixa largura de banda e assim por diante).
  • Para garantir que seu servidor processe corretamente
    tudo o que você envia para ele, o seguinte teste simples usando nc pode ser feito:
\$> nc 127.0.0.1 6667
com^Dman^Dd
\$>
  • Use ctrl+D para enviar o comando em várias partes: 'com', depois 'man' e depois 'd\n'.
  • Para processar um comando, você deve primeiro agregar os pacotes recebidos para reconstruí-lo.

Workflow

Timeline

Project Management

Estrutura do projeto: image

Diagrama do Algoritimo: image

Take a look
  • <cstring> (c++) vs <string.h> (c)
  • Boost libraries (are forbidden).
  • file type *.ipp
  • optional configuration file
  • relacao e uso de: select(), kqueue() ou epoll().
  • Use o wireshark/um proxy personalizado etc. para inspecionar a
    comunicação entre seu servidor de referência (ou seu servidor) e você, seu cliente
  • Project reference
  • Servidores
RFC
  • Servidores são identificados exclusivamente pelo seu nome, que tem um comprimento máximo de 63 caracteres.
  • Usuários são identificados exclusivamente por um nickname, com um comprimento máximo de 9 caracteres. (os clientes DEVE aceitar strings mais longas, evoluções futuras do protocolo)
  • Mensagens Cada mensagem IRC pode consistir em até três partes principais: o prefixo (OPCIONAL), o comando e os parâmetros do comando (máximo 15). O prefixo, o comando e todos os parâmetros são separados por um caractere de espaço ASCII (0x20) cada.
  • Canais os nomes dos canais são strings (começando com '&', '#', '+' ou '!' caractere) de comprimento de até cinquenta (50) caracteres. Além deste requisito, a única restrição para um nome de canal é que ele NÃO DEVE conter quaisquer espaços (' '), um controle G (^G ou ASCII 7), uma vírgula (','). Espaço é usado como separador de parâmetros e o comando é usado como um item de lista. Dois pontos (':') também podem ser usados ​​como delimitador para a máscara do canal. Os nomes dos canais não diferenciam maiúsculas de minúsculas. Cada prefixo caracteriza um tipo de canal diferente.
  • Devido à origem escandinava do IRC, os caracteres {}|^ são considerados os equivalentes minúsculos dos caracteres []\~, respectivamente. Esta é uma questão crítica ao determinar o equivalência de dois apelidos ou nomes de canais.
  • Mensagens Servidores e clientes enviam mensagens uns aos outros, que podem ou não gerar uma resposta. Se a mensagem contiver um comando válido, como descrito em seções posteriores, o cliente deve esperar uma resposta como especificado, mas não é aconselhável esperar para sempre pela resposta;
    • Cada mensagem IRC pode consistir em até três partes principais: o prefixo (OPCIONAL), o comando e os parâmetros do comando (máximo de quinze (15)). O prefixo, o comando e todos os parâmetros são separados por um caractere de espaço ASCII (0x20) cada. O prefixo é usado pelos servidores para indicar o verdadeiro origem da mensagem. Se o prefixo estiver faltando na mensagem, ele presume-se que tenha se originado da conexão da qual foi recebido de. Os clientes NÃO DEVEM usar um prefixo ao enviar um mensagem; se eles usarem um, o único prefixo válido é o registrado apelido associado ao cliente. O prefixo é (':', 0x3b) O comando DEVE ser um comando IRC válido ou um comando de três (3) dígitos número representado em texto ASCII.
    • As mensagens IRC são sempre linhas de caracteres terminadas com CR-LF (Retorno de carro - Alimentação de linha) par, e essas mensagens NÃO DEVEM exceder 512 caracteres de comprimento, contando todos os caracteres, incluindo o CR-LF final.
    • Mensagens vazias são silenciosamente ignoradas
  • Formato de mensagem em BNF Aumentado.
    • A mensagem extraída é analisada nos componentes <prefixo>, <comando> e lista de parâmetros (<params>).
      message    =  [ ":" prefix SPACE ] command [ params ] crlf
      prefix     =  servername / ( nickname [ [ "!" user ] "@" host ] )
      command    =  1*letter / 3digit
      params     =  *14( SPACE middle ) [ SPACE ":" trailing ]
                 =/ 14( SPACE middle ) [ SPACE [ ":" ] trailing ]
    
      nospcrlfcl =  %x01-09 / %x0B-0C / %x0E-1F / %x21-39 / %x3B-FF
                      ; any octet except NUL, CR, LF, " " and ":"
      middle     =  nospcrlfcl *( ":" / nospcrlfcl )
      trailing   =  *( ":" / " " / nospcrlfcl )
    
      SPACE      =  %x20        ; space character
      crlf       =  %x0D %x0A   ; "carriage return" "linefeed"
    
  • Registro de conexão Um comando "PASS" não é necessário para que uma conexão de cliente seja registrado, mas DEVE preceder o último do NICK/USER
    1. Pass message
    2. Nick message / 2. Service message
    3. User message
    
  • Respsotas de comando
Run Program

Compilator

c++ -Wall -Wextra -Werror -std=c++98 ./server/Server.cpp ./client/Client.cpp main.cpp

Compilator and Run

alias crun='c++ -Wall -Wextra -Werror -std=c++98 ./server/Server.cpp ./client/Client.cpp main.cpp && ./a.out'

Valgrind Test

valgrind --leak-check=full --show-leak-kinds=all --fds=yes ./a.out

Study resources

Article / Forum Tutorial Video Documentation
irc - wikipedia ircgod Creating TCP server RFC1459
ircdocs ft_irc guide User guide IRC RFC2812
Using Internet Sockets irc - broly More links
IRC specifications Network - broly irc numerics
Modern IRC irc -Talha Demir
ircv3 irc - afatir

About

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

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published