IrcClient / Bot



  • Hallo, ich bin Linux User, deshalb steht es hier 😃 wusste nicht wohin sonst weil C++ ist es ja nicht pur.

    Zumindest bin ich dabei einen IrcBot zu erstellen, mein "Bot" holt sich auch die IP vom angegebenen IRC Server vom DNS, aber er schafft es nicht sich zu verbinden. Ich bin nicht so alt und weis daher noch nicht wirklich viel, also bitte nicht sauer sein wenn ich hier was falsches poste.

    Kann sich mal jemand bitte meinen Code ansehen, ich finde meinen Fehler nicht!
    !Achtung! Das sind NICHT meine Hausaufgaben. In der Schule machen wir nur Java 😋

    /*
     * IrcBot Ralphi
     *  
     * –––––––––––––––––––––––––––––
     * Notizen:
     * RFC zu IRC: http://www.ietf.org/rfc/rfc1459.txt
     * 
     * 
     * TODO:
     * Bis her connectet er nicht zum Channel, TCP geht aber bis hinter den Router, mit WShark überprüft!
     * Er holt sich auch die IP vom DNS, aber ab dann versucht er vergeblich zu verbinden. IP stimmt aber und ist online.
    */
    #include <iostream> 
    #include <string> 
    #include <cstdlib> 
    #include <cstdio> 
    #include <cstring> 
    #include <sys/socket.h>
    #include <sys/types.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <netdb.h>
    #include <unistd.h>
    const unsigned int MAX_LINE = 1024; // Groesse des Empfangspuffers - 1024 klingt gut.
    using namespace std; 
    
    int sockfd;
    
    void irc_disconnect() //IRC disconnect
    {
    	close(sockfd); 
    }
    
    // sendet an den "uplink"
    void s2u(const char *msg) 
    { 
    	send(sockfd, msg, strlen(msg), 0); //send mademoiselle
    }
    
    // Verbinden to the IRC server
    void irc_connect() 
    {
    
    	const int PORT = 6667;	//6668 bringt selbes resultat
    	const char *HOST = "irc.ipv6.quakenet.de";	
    	sockfd = socket(AF_INET, SOCK_STREAM, 0);
    
    	if(static_cast<int>(sockfd) < 0) 
    	{
    		perror("socket()");
    		irc_disconnect(); // bye bye
    		exit(1);
    	}
    
    	hostent *hp = gethostbyname(HOST); // pointer auf den Hostname
    
    	if(!hp) 
    	{
    		cerr << "gethostbyname()" << endl; 
    		irc_disconnect(); 
    		exit(1);
    	}
    
    	sockaddr_in sin;	
    	memset((char*)&sin, 0, sizeof(sin));
    	sin.sin_family = AF_INET;
    	memcpy((char*)&sin.sin_addr, hp->h_addr, hp->h_length);
    	sin.sin_port = htons(PORT);	
    	memset(&(sin.sin_zero), 0, 8*sizeof(char));
    
    	if(connect(sockfd, (sockaddr*) &sin, sizeof(sin))==-1)
    	{
    		perror("connect()");
    		irc_disconnect(); 
    		exit(1);
    	}
    }
    
    // Des Agentens Identität
    void irc_identify() 
    {
    	s2u("NICK RalphiBot - Alpha vrs. 1.0\r\n"); // Nickname
    	s2u("USER Bot356767\r\n"); // Userdaten
    
    	// TODO: fix - irgendwann hinzufügen, zum dev einfacher ohne
    
    	//s2u("PRIVMSG NickServ IDENTIFY password\r\n"); // Identifizieren
    
    	s2u("JOIN #nyan\r\n"); // Channel betreten
    	s2u("PRIVMSG #nyan :Hello!\r\n"); // Begruessungsnachricht
    
    	// TODO: add Channeluser liste runterladen
    }
    
    // Ping Pong
    void ping_parse(const string &buffer) 
    {
    	size_t pingPos = buffer.find("PING"); 
    	if(pingPos!=string::npos) 
    	{
    	string pong("PONG"+buffer.substr(pingPos+4)+"\r\n"); 
    	cout << pong; 
    	s2u(pong.c_str());
    	}
    }
    void bot_functions(const string &buffer) 
    {
    	size_t pos = 0;
    	if((pos=buffer.find(":say "))!=string::npos) // finden wir "say" ?
    	{
    	s2u(("PRIVMSG #nyan :"+buffer.substr(pos+5)+"\r\n").c_str()); // repeat im channel
    	}
    	else if(buffer.find(":luca@2a01:4020:1:7::7")==0 && buffer.find("exit")!=string::npos) // nur wir können es stoppen
    	{
    		s2u("PRIVMSG #nyan :Cya\r\n");	
    		irc_disconnect(); 
    		exit(0);
    	}
    }
    
    // parsing
    void irc_parse(string buffer) 
    {
    	if(buffer.find("\r\n") == buffer.length()-2) 
    	buffer.erase(buffer.length()-2);
    	ping_parse(buffer); 
    	bot_functions(buffer);
    }
    // Main muss hier runter unter alles drunter...sonst --> declare Fehler -ô.O-
    int main() 
    {
    irc_connect(); 
    irc_identify();
    
    	for(;;) // recv
    	{
    		char buffer[MAX_LINE+1] = {0};
    		if(recv(sockfd, buffer, MAX_LINE*sizeof(char), 0)<0) 
    		{
    		perror("recv()");
    		irc_disconnect();
    		exit(1);
    		}
    		cout << buffer;
    		irc_parse(buffer);
    	}
    	irc_disconnect();
    }
    

    Grüße und Danke schon mal

    Fin



  • Hi,

    ich vermute, dass es daran liegt, dass du AF_INET nimmst, aber offenbar zu einer IPv6-Adresse verbinden willst (das lässt zumindest die Domain vermuten: irc.ipv6.quakenet.de). Probier doch mal AF_INET6 an beiden Stellen, an denen du momentan AF_INET nimmst.



  • Da scheint aber noch mehr nicht zu passen.

    Z. B. castest du hier sin.sin_addr in einen char *:

    memcpy((char*)&sin.sin_addr, hp->h_addr, hp->h_length);
    

    Das sieht für mich falsch aus. sin_addr ist vom Typ struct in_addr, was wiederum laut http://www.gta.ufrj.br/ensino/eel878/sockets/sockaddr_inman.html das hier ist:

    struct in_addr {
        unsigned long s_addr;  // load with inet_aton()
    };
    

    Du schreibst also da, wo ein Struct hin gehört, das eine unsigned long (s_addr) enthält, eine Zeichenkette (hp->h_addr) hin.

    Google mal lieber nach "c socket ipv6" und schau dir da ab, wie die das machen.

    Außerdem solltest du laut http://man7.org/linux/man-pages/man3/gethostbyname.3.html lieber eine andere Funktion als gethostbyname verwenden:

    http://man7.org/linux/man-pages/man3/gethostbyname.3.html schrieb:

    The gethostbyname*(), gethostbyaddr*(), herror(), and hstrerror()
    functions are obsolete. Applications should use getaddrinfo(3),
    getnameinfo(3), and gai_strerror(3) instead.



  • Vielen Dank, ich probier mal weiter rum, Google ist mein Freund 😃



  • struct hostent hat einen char** h_addr_list , das ist eine Liste von in_addr 's, die du eigentlich nur noch casten musst.

    Habe deinen Code mal überflogen und da fallen mir eigentlich ein paar Dinge auf, die mir nicht gefallen. Erstens, packst du in deine sockaddr_in.sin_zero ein weiteres Mal lauter Nullen rein obwohl du doch die Struktur mit lauter Nullen initialisiert hast. Hasts also einmal zu viel drin. Dann castest du auch noch einen Integer in einen Integer, obendrein ein C++-Cast. aber naja, ist wohl Geschmacksache.

    Desweiteren rate ich dir entweder eine Bibliothek zu benutzen oder das IRC Protokoll erstmal anständig zu implementieren, bevor du einen Bot baust. Gut, wenns nur mal so dahingeschissen sein soll, ok, aber wenn du einen anständigen Bot schreiben willst bräuchtest du ne Lib dafür. Schreib dir zumindest nen Parser für die Nachrichten.

    Und noch was: Ich sag ja nicht, dass du bei solchen Sachen kein C mit C++ mischen sollst, aber so wie du es machst, ist es ziemlich Kacke. Du benutzt kein OO, keine STL, keine kluken Pointer und nichts von alledem. That's not good practice in C++. Wenn du dir wirklich was von dem Programm erwartest, dann schreib es nochmal komplett um, so, dass es besser wartbar und konsistenter ist.

    Ahja, und dann noch AF_INET6, falls der Server an den du dich zu verbinden versuchst wirklich nur mit IPv6 Adressen arbeitet.

    Und da gibt es auch noch Inkonsistenzen, beim Parsen deiner Nachrichten.


Anmelden zum Antworten