Completely Stumped (odd bug)

basically, this is an IRC bot, it only PONGS on pings sometimes, and it takes someone typing commands multiple times for the bot to reconize it.

http://bazaar.launchpad.net/~hippos/chippo/cHippo/revision/27
^ all the code is there

basically, the check for commands is in checkServerInput, and check for a server ping is in,. checkServerPing, and its called in main like this.
1
2
3
4
5
6
7
8
9
10
    while (1) {
        hippoClient.checkServerPing( );
        hippoClient.checkServerInput( );

        if ( firstConnect == true ) {
            hippoClient.joinChannel("*****");
            hippoClient.identify("******"); 
            firstConnect = false;
        }
    }


then its passed to both methods in the IRCClient class

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
int IRCClient::checkServerPing( ) {
    char recvBuff[4096];
    char *recvNewline=NULL;
    int len = recv(servSock, recvBuff, sizeof(recvBuff) - 1, 0);
    recvBuff[len] = '\0';
    while( (recvNewline=IRCClient::newline(recvBuff))!=NULL ) {
        serverRegex.sortSock(recvNewline); //sends server input to regex class
        cout << recvNewline << endl; // Output

        if ( strcmp(serverRegex.returnPong(recvBuff), "failed") == -1 ) {
            const char* pong = serverRegex.returnPong(recvBuff);
            char sndBuffer[256];
            memset(sndBuffer, '\0', 256);
            //fill out sndBuffer with command + ping number
            sprintf(sndBuffer, "PONG :%s\r\n", pong);
            send(servSock, sndBuffer, strlen(sndBuffer), 0);
            cout << sndBuffer << endl;
        }
    }

    return 0;
}

//extreamly important function
int IRCClient::checkServerInput( ) {
    char recvBuff[4096];
    char *recvNewline=NULL;
    int len = recv(servSock, recvBuff, sizeof(recvBuff) - 1, 0);
    recvBuff[len] = '\0';
    while( (recvNewline=IRCClient::newline(recvBuff))!=NULL ) {
        serverRegex.sortSock(recvNewline); //sends server input to regex class
        cout << recvNewline << endl; // Output

        if ( serverRegex.checkCommand( serverRegex.getData("message") ) ) {
            char sndBuffer[256];
            memset(sndBuffer, '\0', 256);
            sprintf(sndBuffer, serverRegex.sortCommand( serverRegex.getData("message") ));
            send(servSock, sndBuffer, strlen(sndBuffer), 0);
            cout << sndBuffer << endl;
        }

    }
	return 0;
}


Im not sure what would be wrong with it :/, the function that splits all the input by newlines seems fine,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
char *IRCClient::newline(char *buff) {
    char *t1=IRCClient::newline_temp, *t2=IRCClient::newline_temp;
    int len, x=0;
    if( IRCClient::newline_temp == NULL) {
        IRCClient::newline_temp=buff; t1=buff; t2=buff;
    }
    len=strlen(t1);
    while(x <= len ) {
        if(*t1 == '\0') {
            break;
        }
        else if(*t1 == NEWLINE) {
            break;
        }
        else {
            *t1++; x++;
        }
    }
    if( (*t1) == NEWLINE ) {
        *t1='\0'; *t1++; //CR
        *t1='\0'; *t1++; //LF
    }
    else if ( (*t1) == '\0' ) {
        IRCClient::newline_temp=NULL;
        return NULL;
    }
    IRCClient::newline_temp=t1;
    return t2;
}


my regex works, and im sure boost.regex isn't the problem.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//pong functions
const char* IRCRegex::returnPong( const char* recvBuff ) {
    if ( regex_match( recvBuff, pongMatches, regexPong ) ) {
        string m1(pongMatches[1]);
        //have to reassign
        pong = m1.c_str();
        return pong;
    }
    else {
        return "failed";
    }
}

IRCRegex::IRCRegex( ) {
        regexSort = "^:(.*)!.*@(.*) (.*?) (.*?) :(.*?)$";
        regexPong = "PING :(.*?)$";
        regexCommand = "^!(.*?) (.*?)$";
}


I'm not even sure how i would testcase this xD

thanks for taking the time to help <3.
Last edited on
No, no, no.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
char *IRCClient::newline(const char *buff) {
	const char *t1=IRCClient::newline_temp,
		*t2=IRCClient::newline_temp;
	if( IRCClient::newline_temp == NULL) {
		//no multiple statements per line kthnx
		IRCClient::newline_temp=buff;
		t1=buff;
		t2=buff;
	}

	const char *nl=strchr(buff,NEWLINE);
	if (nl==NULL){
		IRCClient::newline_temp=NULL;
		return NULL;
	}
	//Is CRLF standard for the IRC protocol?
	//If not, no check for the newline type?
	*nl=nl[1]=0; //CRLF
	nl+=2;
	IRCClient::newline_temp=t1;
	return t2;
}


Even if it's not recognized as a command, is the transmission being received by the bot?


Even if it's not recognized as a command, is the transmission being received by the bot?


yes, the bot picks up and prints all the input from the server, even the PING's, it just doesn't handle them half of the time,
So it's not a problem in checkServerInput().

I just noticed this: strcmp(serverRegex.returnPong(recvBuff), "failed") == -1
I can think of quite a few better ways to do this. One of them is having returnPong() return 1 on success and 0 on failure.
Also,
1
2
3
string m1(pongMatches[1]);
//have to reassign
pong = m1.c_str();

On success, 'pong' is an invalid pointer after the function returns. I think this is your problem.

I just noticed this: strcmp(serverRegex.returnPong(recvBuff), "failed") == -1
I can think of quite a few better ways to do this. One of them is having returnPong() return 1 on success and 0 on failure.


that would be a good solution, only i need returnPong() to return the text that the server PING's it with, =(


On success, 'pong' is an invalid pointer after the function returns. I think this is your problem.


im exploring this, so far i tried
1
2
3
4
5
6
7
8
9
10
11
string IRCRegex::returnPong( const char* recvBuff ) {
    if ( regex_match( recvBuff, pongMatches, regexPong ) ) {
        //m1->assign(pongMatches[1].first, pongMatches[1].second);
        //have to reassign
        //cout << pongMatches.first;
        return pongMatches[1].first;
    }
    else {
        return "failed";
    }
}


and in IRCClient i added

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
int IRCClient::checkServerPing( ) {
    char recvBuff[4096];
    char *recvNewline=NULL;
    int len = recv(servSock, recvBuff, sizeof(recvBuff) - 1, 0);
    recvBuff[len] = '\0';
    while( (recvNewline=IRCClient::newline(recvBuff))!=NULL ) {
        serverRegex.sortSock(recvNewline); //sends server input to regex class
        cout << recvNewline << endl; // Output

        if ( serverRegex.returnPong(recvBuff).compare("failed") ) {
            return 1;
        }
        else {
            string pong = serverRegex.returnPong(recvBuff);
            char sndBuffer[256];
            memset(sndBuffer, '\0', 256);
            //fill out sndBuffer with command + ping number
            sprintf(sndBuffer, "PONG :%s\r\n", pong);
            send(servSock, sndBuffer, strlen(sndBuffer), 0);
            cout << sndBuffer << endl;
        }
    }

    return 0;
}


but now PONG is broken =( prolly has something to do with me failing with boost.regex,
i pretty much followed the example from here

http://www.boost.org/doc/libs/1_40_0/libs/regex/doc/html/boost_regex/ref/regex_match.html

See, this is what I don't understand. You have enough common sense to assign the return value of returnPong() to an std::string, but not enough to avoid calling the function twice.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//How I'd do it:
//string pong;
//if (!serverRegex.returnPong(recvBuff,pong)){
//	(...)
//}else{
//	('pong' is now assigned)
//	...
//}
string pong = serverRegex.returnPong(recvBuff);
if ( pong == "failed" ) {
	return 1;
} else {
	pong="PONG :"+pong+"\r\n";
	send(servSock, pong.c_str(), pong.size(), 0);
	cout << pong << endl;
}


As for the regex, it looks valid. I don't know about boost::regex, though. Here's something you could try:
1
2
3
4
5
6
7
string IRCRegex::returnPong( const char* recvBuff ) {
	std::string s=recvBuff;
	std::transform(s.begin(),s.end(),tolower); //you don't need to keep things in their case, right?
	if (s.substr(0,6)!="pong :")
		return "failed";
	return s.substr(6,s.find_first_of("\r\n",6));
}
Pong is working now, the boost.regex code works fine, however now theres another bug XD

1
2
3
4
5
6
7
8
9
10
bot output:
:Jew!Jew@cpe-173-173-12-189.hot.res.rr.com PRIVMSG #hippos :;P
:Jew!Jew@cpe-173-173-12-189.hot.res.rr.com PRIVMSG #hippos :gawd i hate d-journals
ERROR :Closing Link: 72.183.125.48 (Ping timeout: 180 seconds) //didn't even get the PING?

my server input:
<Jew> ;P
<Jew> gawd i hate d-journals
<tak> hah                            //didn't get this message either
* cHippo has quit (Ping timeout: 180 seconds)


after running some more test cases, PING on PONG works perfect, thank you SO much for taking all that time helping me >.<

now however it skips lines from time to time, which can be a huge issue XD, im not sure what would cause this, as i haven't made any alterations to the newline function, and it was working before just fine. what do you think the cause is?
Are you actually splitting into lines what newline() returns, or everything that's after the null character gets ignored?
For example, if I send "foo\r\nbar\r\nbaz", newline() will convert it into "foo\0\0bar\0\0baz\0\0". Will the substrings starting at positions 5 and 10 get processed? If not, you should have a queue of some sort to add them to.
Last edited on
everything after a null char gets ignored, it splits and points it to the next part after the null and the it gets called again and it parses it, eh imma go to sleep after the next post and i'll check in the morning, and hopefully get these bugs out tomorrow,
Topic archived. No new replies allowed.