IRC bot malfunction

126 Views Asked by At

I have attempted to make a IRC bot in C. When the bot attempts to connect to an IRC server it enters an infinite loop where it receives nothing. I am not sure if this is because my process to join the IRC server is malformed or if I am missing some data that should be sent/received.

#include<stdio.h>
#include<sys/socket.h>
#include<netdb.h>
#include<string.h>
#include<stdlib.h>
#include<time.h>


#define MAXSIZE 4096

void delay(int milliseconds)
{
    long pause;
    clock_t now;

    pause = milliseconds*(CLOCKS_PER_SEC/1000);//set delay using
    now = clock();
    while( now < pause )
        now = clock();
}

int send_data(int sockfd, char message[])
{
    send(sockfd, message, strlen(message), 0);
    printf("OUT: %s\n", message);
    return 1;
}

int recv_data(int sockfd, char *message)
{
    int n;
    n = recv(sockfd, message, MAXSIZE, 0);
    printf("IN: %s\n", message);
    return n;
}

int tcp_connect(int *sockfd, char server[], char port[])
{
    //declare variables
    struct addrinfo hints, *res;

    //zero out structures
    memset(&hints,0,sizeof(hints));
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;

    //query DNS server for IP address and port
    getaddrinfo(server,port,&hints,&res);

    //create socket for data transmission
    *sockfd = socket(res->ai_family,res->ai_socktype,0);
    if (*sockfd < 0)
    {
        printf("failure to create socket\n");
        return 0;
    }

    //connect to server side port using created socket
    if (connect(*sockfd, res->ai_addr, res->ai_addrlen)!= 0)
    {
        printf("failure to connect to port\n");
        return 0;
    }

    freeaddrinfo(res);
    return 1;
}

int irc_auth(int sockfd)
{
    //create and start clock
    clock_t start_t;
    start_t = clock();

    //seed RNG with clock output
    srand(start_t);

    //generate necessary variables
    char name[15] = "bot";
    char user[35] = "USER ";
    char nick[20] = "NICK ";
    char join[20] = "JOIN #randChat\r\n";
    int i,id;

    //generate random character for ID tag A-Z
    for(i=0; i<5; i++)
    {
        id = rand() % 91;
        if(id < 65)
        {
            while(id < 65)
            {
                id = rand() % 91;
            }
        }
        name[strlen(name)] = id;
    }
    //append return and null to string
    strcat(nick,name);
    strcat(nick,"\r\n");

    //append to finish creating USER IRC command
    strcat(user,name);
    strcat(user," 8 * :");
    strcat(user,name);
    strcat(user,"\r\n");

    //send data to server
    send_data(sockfd,user);
    delay(1000);
    send_data(sockfd,nick);
    delay(1000);
    send_data(sockfd,join);

    return 1;
}
int main (int argc, char *argv)
{
//variables
    int sockfd, n, flag;
    char *mesg_in = malloc(sizeof(char) * MAXSIZE); 
    char *pos;
    char nick[30];

    char *mesg_out = malloc(sizeof(char) * MAXSIZE);

    //connect to port 6667 of irc.freenode.org using tcp
    while(flag<1)
    {
        if(tcp_connect(&sockfd,"irc.freenode.org","6667") == 1)
        {
            flag = 1;
        }
    }   

    //IRC channel authentication
    irc_auth(sockfd);

    //command loop
    while(1)
    {
        mesg_in[0] = 0;// zero out message
        //memset(mesg_in,0,strlen(mesg_in));
        n = recv_data(sockfd,mesg_in);// pull message from channel

        if (n > 0)// check to see if it recieved a command
        {
            mesg_in[n] = 0;// set null at the end of recieved data

            //respond to ping commands from server
            if(strstr(mesg_in,"PING") != NULL)
            {
                mesg_out[0] = 0;// zero out message
                pos = strstr(mesg_in," ")+1;// point to data needed
                //append to out bound message
                sprintf(mesg_out,"PONG %s\r\n",pos);
                //send outbound message
                send_data(sockfd,mesg_out);
            }
        }
    }
}

any and all help would be greatly appreciated

2

There are 2 best solutions below

0
On

Whatever other problems there might be, delay() is one. Your function in this test program, waits two seconds and then prints 1 2 3 all at the same time, because it only considers elapsed time from the program start, and not from the current moment.

#include <stdio.h>
#include <time.h>

void delay(int milliseconds)
{
    long pause;
    clock_t now;
    pause = milliseconds*(CLOCKS_PER_SEC/1000);//set delay using
    now = clock();
    while( now < pause )
        now = clock();
}

int main (void)
{  
    delay(2000);
    printf("1\n");

    delay(2000);
    printf("2\n");

    delay(2000);
    printf("3\n");

    return 0;
}

This version prints 1 2 3 at two second intervals

#include <stdio.h>
#include <time.h>

void delay(clock_t milliseconds)
{
    clock_t elapsed, pause, stamp;
    stamp = clock();
    pause = milliseconds * CLOCKS_PER_SEC / 1000;
    while ((elapsed = clock() - stamp) < pause);
}

int main (void)
{  
    delay(2000);
    printf("1\n");

    delay(2000);
    printf("2\n");

    delay(2000);
    printf("3\n");

    return 0;
}

Please also notice, that in integer arithmetic, I do the multiplication before the division.

0
On

Rethink your client and make it a state machine instead driven by an event engine such as epoll(), kqueue(), select() or poll().

Generally, an IRC command generates a reply, but you don't know when they are going to arrive, and the protocol is designed such that you might want to send commands that aren't initiated by data coming from the server.

Using a delay to authenticate to an IRC server is a no-no because there are various other commands that can be generated as part of authentication such as PING or CTCP's etc, your nick being in use, etc.

Also, according to the RFC the NICK command must come first before user. Generally, IRC servers are forgiving, but don't take this for granted. As the adage goes, "be generous in what you accept and strict in what you send".