Search code examples
csocketswinsockirc

How to connect a client to an IRC server using sockets in C


I am coding an IRC client that I want to connect to irc.hackerzvoice.net. I have read RFC1459 as well as similar posts here on Stackoverflow, but still do not get what can possibly be wrong in my code. I still get the same "registration timeout" error after sending the NICK and USER messages.

La socket 280 est ouverte en TCP/IP.
Connexion a 212.83.153.145 sur le port 6667
68 octets ont ete recus
texte recu : :irc.hackerzvoice.net NOTICE Auth :*** Looking up your hostname...
16 octets envoyes au serveur
texte envoye : NICK parallel
.30 octets envoyes au serveur
texte envoye : USER parallel * * :parallel
.99 octets ont ete recus
texte recu : :irc.hackerzvoice.net NOTICE Auth :*** Found your hostname (catv-89-132-88-100.catv.broadband.hu)
92 octets ont ete recus
texte recu : ERROR :Closing link: (unknown@catv-89-132-88-100.catv.broadband.hu) [Registration timeout]
d.hu)
0 octets ont ete recus
texte recu : ERROR :Closing link: (unknown@catv-89-132-88-100.catv.broadband.hu) [Registration timeout]
d.hu)

Here is my code:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "root_me_1.h"
 
 
int main()
{
    // Si la plateforme est Windows
    #if defined (WIN32)
        WSADATA WSAData;
        WSAStartup(MAKEWORD(2,2), &WSAData); // sert à initialiser la bibliothèque WinSock
    #endif
 
    // socket et interface de connexion
    SOCKET sock;
    SOCKADDR_IN sin; // structure
 
    char buffer[TAILLE_MAX] = "";
    int nOctetsRecus = 0;
    int nOctetsEnvoyes = 0;
    int tailleBuffer = 0;
    int boucle = 1;
 
    // on crée une socket utilisant protocole TCP/IP
    sock = socket(AF_INET, SOCK_STREAM, 0);
    if(sock == INVALID_SOCKET)
        printf("Erreur, socket non valide");
    printf("La socket %d est ouverte en TCP/IP.\n", sock);
 
    // on configure l'interface de connexion
    sin.sin_addr.s_addr = inet_addr("212.83.153.145"); // adresse IP du serveur IRC
    sin.sin_family = AF_INET;
    sin.sin_port = htons(PORT); // sin_port et sin_addr doivent être en Network Byte Order // htons() convertit un entier court depuis l'ordre des octets de l'hôte vers celuidu réseau (host to network short)
 
    if(connect(sock, (SOCKADDR*)&sin, sizeof(sin)) != SOCKET_ERROR) // si le client réussit à se connecter au serveur
        printf("Connexion a %s sur le port %d\n", inet_ntoa(sin.sin_addr), htons(sin.sin_port));
    else
        printf("Erreur de connexion.");
 
 
    // on reçoit les données envoyées par le serveur
    nOctetsRecus = recv(sock, buffer, TAILLE_MAX, 0);
    if(nOctetsRecus != SOCKET_ERROR)
    {
        printf("%d octets ont ete recus\n", nOctetsRecus);
        printf("texte recu : %s", buffer);
    }
    else
        printf("Les donnees n'ont pas ete recues");
 
 
    // le client envoie des données au serveur
    sprintf(buffer, "NICK parallel\r\n");
    tailleBuffer = strlen(buffer)+1; // taille de la chaine + '\0'
 
    nOctetsEnvoyes = send(sock, buffer, tailleBuffer, 0);
    if(nOctetsEnvoyes != SOCKET_ERROR)
    {
        printf("%d octets envoyes au serveur\n", nOctetsEnvoyes);
        printf("texte envoye : %s", buffer);
    }
    else
        printf("Erreur : donnees non envoyees au serveur");
 
    // le client envoie des données au serveur
    sprintf(buffer, "USER parallel * * :parallel\r\n");
    tailleBuffer = strlen(buffer)+1; // taille de la chaine + '\0'
 
    nOctetsEnvoyes = send(sock, buffer, tailleBuffer, 0);
    if(nOctetsEnvoyes != SOCKET_ERROR)
    {
        printf("%d octets envoyes au serveur\n", nOctetsEnvoyes);
        printf("texte envoye : %s", buffer);
    }
    else
        printf("Erreur : donnees non envoyees au serveur");
 
 
    // on reçoit les données envoyées par le serveur
    nOctetsRecus = recv(sock, buffer, TAILLE_MAX, 0);
    if(nOctetsRecus != SOCKET_ERROR)
    {
        printf("%d octets ont ete recus\n", nOctetsRecus);
        printf("texte recu : %s", buffer);
    }
    else
        printf("Les donnees n'ont pas ete recues");
 
 
    // on ferme la connexion
    closesocket(sock);
 
 
    #if defined (WIN32)
        WSACleanup(); // libère les ressources allouées par la fonction WSAStartup()
    #endif
 
    getchar();
 
    return EXIT_SUCCESS;
}

Would you have an idea of the problem?

Thank you.


Solution

  • This is the problem,

    sprintf(buffer, "NICK hoeplem\r\n");
    tailleBuffer = strlen(buffer)+1;
    

    Because strlen(buffer) + 1 is one byte off (the null terminator '\0' should not be sent to the server and strlen() returns the length of the string excluding the null terminator.) the actual length of the string. If the server reads that byte it might be expecting '\r\n' to flush the buffer and process the command, so it's waiting forever after the last "command".

    It should be

    tailleBuffer = sprintf(buffer, "NICK hoeplem\r\n");
    

    and that way it would be perfect.

    You might also want to check POSIX's dprintf() and/or roll your own dprintf() to avoid sprintf()ing every time.

    Also, it would be better to have each command as a function with it's parameters and simply call command_X(sock, PARAMETERS ...) for every possible command, that way your code would be more robust.