IRC ChatClient mit Sockets. Threadabsturz



  • Hallo,

    ich verusche gerade einen ingame Chatclient zu machen mit D3D9 Hooking. Dazu injecte ich eine dll an den Prozess eines Spiels. Das funktioniert einwandfrei, doch der IRC Client funktioniert nicht so ganz.

    Der void IRC::ChatListener() Thread müsste jede Nachricht vom Server in die logDatei schreiben und beim beenden müsste "ChatListener-Thread beendet" ausgegeben werden. Dies passiert jedoch nicht. Ich vermute der Thread stürzt irgendwo ab.
    Vielleicht sieht einer den Fehler:

    // dllmain.h
    
    #include <windows.h>
    #include <cstdio>
    #include <d3d9.h>
    #include <d3dx9.h>
    #include <list>
    #include <string>
    
    void StartChatClient();
    void InitHook();
    void add_log(char* string);
    
    // dllmain.cpp : Definiert den Einstiegspunkt für die DLL-Anwendung.
    #pragma once
    #pragma comment(lib, "d3d9.lib")
    #pragma comment(lib, "d3dx9.lib")
    
    #include <stdlib.h>
    #include <iostream>
    #include <fstream>
    #include <string>
    #include "dllmain.h"
    #include "irc.h"
    #include <list>
    using namespace std;
    
    list<string> chatList;
    IRC irc_client;
    
    int WINAPI DllMain(HINSTANCE hInst, DWORD dwreason, LPVOID reserved)
    {
    	switch(dwreason)
    	{
    		case DLL_PROCESS_ATTACH:
    		    add_log("\n---------------------\n...Started...\n---------------------");
                chatList.push_back("1");
                chatList.push_back("2asdas");
                chatList.push_back("3");
                chatList.push_back("4sadassdasdaasddasdasdasdasdssssssssssssssssssssssssssssssssssssssssssssss");
                chatList.push_back("5");
    
    			CreateThread(0, 0, (LPTHREAD_START_ROUTINE) StartChatClient, 0, 0, 0);
    			CreateThread(0, 0, (LPTHREAD_START_ROUTINE) InitHook, 0, 0, 0);
    			break;
            case DLL_PROCESS_DETACH:
                irc_client.close();
    		    add_log("---------------------\n...Exiting...\n---------------------\n");
                break;
    	}
    
    	return true;
    }
    
    void StartChatClient()
    {
        if(irc_client.create( "username" ))
            irc_client.startChatListener(chatList);
    
        irc_client.login( "username", "password", "Full Name", "channelnameToJoin" );
    }
    
    void InitHook()
    {
    	//unwichtig
    }
    
    void add_log(char* string)
    {
    	HANDLE filehandle;
    	DWORD dwReadBytes;
    	char buffer[2048];
    
    	filehandle = CreateFileA("C:\\Users\\Zack\\Desktop\\Log.txt", GENERIC_WRITE, 0, 0, OPEN_ALWAYS, 0, 0);
    	SetFilePointer(filehandle, 0, 0, FILE_END);
    	sprintf_s(buffer, 1024, "Added Log: %s\r\n", string);
    	WriteFile(filehandle, buffer, strlen(buffer), &dwReadBytes, 0);
    	CloseHandle(filehandle);
    }
    
    // irc.h
    
    #include <string>
    #include "socket.h"
    #include <string>
    #include <list>
    
    // Die Klasse IRC
    class IRC {
    private:
        Socket m_socket;
    	HANDLE m_hThread;
        bool m_listenChat;
    
        // IRC Listener
        void ChatListener();
    	static DWORD WINAPI ThreadProc(LPVOID pparam);
    
        std::list<std::string>* m_chatList;
    
    public:
        // IRC Client erstellen
        bool create( std::string username );
        // Twitch login
        bool login( std::string username, std::string password, std::string fullname,  std::string channel );
        // IRC Listener starten
        void startChatListener( std::list<std::string>& chatList );
        // IRC verbindung Trennen und CharListener anhalten
        bool close();
    };
    
    // irc.cpp
    
    #include <cstdlib>
    #include <winsock.h>
    #include <io.h>
    #include <iostream>
    #include "socket.h"
    #include "IRC.h"
    #include "dllmain.h"
    #include <algorithm>
    #include <list>
    #include <string>
    #include <tchar.h>
    using namespace std;
    
    // Erzeugt den IRC-Client
    bool IRC::create( string username ) {
        add_log("IRC::create");
        if (!m_socket.create())
            return false;
    
        add_log("Socket created");
    
        string mychannel = username;
        transform(mychannel.begin(), mychannel.end(), mychannel.begin(), ::tolower);
        string serv_addr = mychannel + ".jtvirc.com";
    
        if( !m_socket.connect( serv_addr, 6667 ) )
        {
            m_socket.close();
    		add_log("Failed to connect to host!");
            return false;
        }
        serv_addr = "Socket connected on " + serv_addr + ":6667";
        const char* p =serv_addr.c_str();
        char* str = const_cast<char*>(p);
        add_log(str);
        return true;
    }
    
    // Twitch login
    bool IRC::login( string username, string password, string fullname, string channel ) {
        add_log("IRC::login");
        string tmp = "PASS " + password;
        const char* p =tmp.c_str();
        char* str = const_cast<char*>(p);
        add_log(str);
        m_socket.send("PASS " + password + "\r\n");
    
        tmp = "NICK " + username;
        p =tmp.c_str();
        str = const_cast<char*>(p);
        add_log(str);
        m_socket.send("NICK " + username + "\r\n");
    
    	TCHAR szHostName[MAX_PATH];
    	DWORD cbHostName = sizeof(szHostName);
    	GetComputerName(szHostName, &cbHostName);
    
        wstring arr_w( szHostName );
        string arr_s( arr_w.begin(), arr_w.end() );
        tmp = "USER " + username + " " + arr_s + " server :" + fullname;
        p =tmp.c_str();
        str = const_cast<char*>(p);
        add_log(str);
    	m_socket.send("USER " + username + " " + arr_s + " server :" + fullname + "\r\n");
    
        tmp = "JOIN " + channel;
        p =tmp.c_str();
        str = const_cast<char*>(p);
        add_log(str);
        m_socket.send("JOIN " + channel + "\r\n");
        return true;
    }
    
    // Startet den Chat Listener
    void IRC::startChatListener( list<string>& chatList ) {
        add_log("IRC::startChatListener");
        m_listenChat = true;
    
        m_chatList = &chatList;
    
        m_hThread = CreateThread( 0, 0, ThreadProc, this, 0, 0);
        Sleep(100);
    }
    
    DWORD WINAPI IRC::ThreadProc(LPVOID pparam)
    {
    	IRC* pThis = (IRC*)pparam;
    	try { pThis->ChatListener(); } catch( ... ) {}
    	return 0;
    }
    
    void IRC::ChatListener()
    {   
        add_log("ChatListener-Thread gestartet");
        //(*m_chatList).push_front("Juhu");
        string message;
        const char* p;
        char* str;
        while(m_listenChat)
        {
            m_socket.recv(message);
    
            message = "Recv: " + message;
            p = message.c_str();
            str = const_cast<char*>(p);
            add_log(str);
        }
        add_log("ChatListener-Thread beendet");
    }
    
    // IRC verbindung Trennen und CharListener anhalten
    bool IRC::close() {
        add_log("IRC::close");
        static const DWORD dwServerTimeout = 5 * 1000;
    
    	if( !m_hThread )
    		return true;
    
        add_log("QUIT :Bye!");
    	m_socket.send("QUIT :Bye!\r\n");
        m_listenChat = false;
    
    	if( m_hThread && WaitForSingleObject(m_hThread, dwServerTimeout) != WAIT_OBJECT_0 )
    	{
    		m_socket.close();
    		Sleep(100);
    		if( m_hThread && WaitForSingleObject(m_hThread, dwServerTimeout) != WAIT_OBJECT_0 )
    		{
    			TerminateThread(m_hThread, 1);
    			CloseHandle(m_hThread);
    			m_hThread = NULL;
    		}
    	}
    
        return true;
    }
    

    Die Ausgabe des Logs ergibt folgendes:

    Added Log: 
    ---------------------
    ...Started...
    ---------------------
    Added Log: IRC::create
    Added Log: Socket created
    Added Log: Socket connected on username.jtvirc.com:6667
    Added Log: IRC::startChatListener
    Added Log: ChatListener-Thread gestartet
    Added Log: IRC::login
    Added Log: PASS password
    Added Log: NICK username
    Added Log: USER username hostname server :Full Name
    Added Log: JOIN channelnameToJoin
    Added Log: Recv: :tmi.twitch.tv 001 username :connected to TMI
    
    Added Log: Recv: :tmi.twitch.tv 002 username :your host is TMI
    :tmi.twitch.tv 003 username :this server is pretty new
    :tmi.twitch.tv 004 username tmi.twitch.tv 0.0.1 w n
    :tmi.twitch.tv 375 username :- tmi.twitch.tv Message of the day - 
    :tmi.twitch.tv 372 username :- not much to say here
    :tmi.twitch.tv 376 username :End of /MOTD command
    :username!username@username.tmi.twitch.tv JOIN channelnameToJoin
    :username.tmi.twitch.tv 353 username = channelnameToJoin :username_
    :username.tmi.twitch.tv 366 username channelnameToJoin :End of /NAMES list
    :jtv!jtv@jtv.tmi.twitch.tv PRIVMSG username :USERCOLOR username #1E90FF
    :jtv!jtv@jtv.tmi.twitch.tv PRIVMSG username :HISTORYEND channelnameToJoin
    
    Added Log: IRC::close
    Added Log: QUIT :Bye!
    Added Log: ---------------------
    ...Exiting...
    ---------------------
    
    /* socket.h für MS Windows */
    
    #ifndef SOCKET_H_
    #define SOCKET_H_
    #include <string>
    #include <winsock.h>
    #include <io.h>
    using namespace std;
    
    // MAX. Anzahl Verbindungen
    const int MAXCONNECTIONS = 5;
    // Max. Anzahl an Daten, die auf einmal empfangen werden
    const int MAXRECV = 1024*4;
    
    // Die Klasse Socket
    class Socket {
    private:
        // Socketnummer (Socket-Deskriptor)
        int m_sock;
        // Struktur sockaddr_in
        sockaddr_in m_addr;
    
    public:
        // Konstruktor
        Socket();
        // virtueller Destruktor
        virtual ~Socket();
    
        // Socket erstellen - TCP
        bool create();
        bool connect ( const string host, const int port );
        // Datenübertragung - TCP
        bool send ( const string ) const;
        int recv ( string& ) const;
        bool is_valid() const { return m_sock != -1; }
    };
    #endif
    
    // socket.cpp
    #include <cstdlib>
    #include <WinSock.h>
    #include <io.h>
    #include <iostream>
    #include "socket.h"
    #include "dllmain.h"
    using namespace std;
    
    #pragma comment(lib, "ws2_32.lib")
    
    // Konstruktor
    Socket::Socket() : m_sock(0) {
        // Wisock.DLL Initialisieren
        WORD wVersionRequested;
        WSADATA wsaData;
        wVersionRequested = MAKEWORD (1, 1);
        if (WSAStartup (wVersionRequested, &wsaData) != 0) {
            add_log("Fehler beim Initialisieren von Winsock");
            exit(1);
        }
    }
    
    // Destruktor
    Socket::~Socket() {
        if ( is_valid() )
            ::closesocket ( m_sock );
    }
    
    // Erzeugt das Socket - TCP
    bool Socket::create() {
        m_sock = ::socket(AF_INET,SOCK_STREAM,0);
        if (m_sock < 0) {
            add_log("Fehler beim Anlegen eines Socket");
            exit(1);
        }
        return true;
    }
    
    // Baut die Verbindung zum Server auf
    bool Socket::connect ( const string host, const int port ) {
        if ( ! is_valid() )
            return false;
        struct hostent *host_info;
        unsigned long addr;
        memset( &m_addr, 0, sizeof (m_addr));
        if ((addr = inet_addr( host.c_str() )) != INADDR_NONE) {
            /* argv[1] ist eine numerische IP-Adresse */
            memcpy( (char *)&m_addr.sin_addr,
                    &addr, sizeof(addr));
        }
        else {
            /* Für den Fall der Fälle: Wandle den Servernamen   *
             * bspw. "localhost" in eine IP-Adresse um          */
            host_info = gethostbyname( host.c_str() );
            if (NULL == host_info) {
                add_log("Unbekannter Server");
                exit(1);
            }
            memcpy( (char *)&m_addr.sin_addr, host_info->h_addr,
                     host_info->h_length);
        }
        m_addr.sin_family = AF_INET;
        m_addr.sin_port = htons( port );
    
        int status = ::connect ( m_sock,
           ( sockaddr * ) &m_addr, sizeof ( m_addr ) );
    
        if ( status == 0 )
            return true;
        else
            return false;
    }
    
    // Daten versenden via TCP
    bool Socket::send( const string s ) const {
        int status = ::send ( m_sock, s.c_str(), s.size(), 0 );
        if ( status == -1 ) {
            return false;
        }
        else {
            return true;
        }
    }
    
    // Daten empfangen via TCP
    int Socket::recv ( string& s ) const {
        char buf [ MAXRECV + 1 ];
        s = "";
        memset ( buf, 0, MAXRECV + 1 );
    
        int status = ::recv (m_sock, buf, MAXRECV, 0 );
        if ( status > 0 || status != SOCKET_ERROR ) {
            s = buf;
            return status;
        }
        else {
            add_log("Fehler in Socket::recv");
            exit(1);
            return 0;
        }
    }
    

    Hoffe jemand kann helfen, vielen dank schonmal

    Viele Grüße
    Zack



  • Vermute nicht, benutze einen Debugger.





  • der Code ist schon reduziert, und die Socket.cpp und Socket.h hab ich nur angehängt, damit es noch compilebar ist. ich werd aber noch ein paar Sachen die unnötig sind entfernen

    Mit Debugger werd ich nur ein wenig schlauer:
    Hab ich das richtig verstanden, dass er wenn ich das Spiel schließe von sich aus schon alle Threads, die dazugehören beendet und deshalb bekomm ich keine "Thread zuende" ausgabe? Dann würde ich nämlich vermuten, dass etwas an meinem IRC Protokoll nicht stimmt und der Thread ansich würde dann ja laufen

    //Zeug vom Spiel selbst
    
    IRC::create
    Socket created
    Der Thread 'Win32-Thread' (0x2e14) hat mit Code 0 (0x0) geendet.
    Der Thread 'Win32-Thread' (0x2e1c) hat mit Code 0 (0x0) geendet.
    Socket connected on zackfair_.jtvirc.com:6667
    IRC::startChatListener
    ChatListener-Thread gestartet
    IRC::login
    PASS password
    NICK username
    USER usaername hostname server :My Name
    JOIN channelname
    Der Thread 'Win32-Thread' (0x26cc) hat mit Code 86507009 (0x527fe01) geendet.
    Recv: :tmi.twitch.tv 001 username :connected to TMI
    
    League of Legends.exe(8496): ALWAYS| PlayGame Entered
    League of Legends.exe(8496): ALWAYS| CurRenderPipeline
    League of Legends.exe(8496): ALWAYS| CreateParticleSystemManager
    
    Recv: blabla
    
    //Zeug vom Spiel selbst
    
    League of Legends.exe(8496): ALWAYS| PKT_S2C_EndSpawn
    League of Legends.exe(8496): ALWAYS| PKT_StartGame
    League of Legends.exe(8496):  ERROR| Failed to load VO for shop ""
    League of Legends.exe(8496): ALWAYS| PKT_StartGame Finished proccessing
    League of Legends.exe(8496): ALWAYS| GAMESTATE_GAMELOOP Begin
    League of Legends.exe(8496): ALWAYS| GAMESTATE_GAMELOOP Update World
    League of Legends.exe(8496): ALWAYS| GAMESTATE_GAMELOOP GUIMenuProcess
    League of Legends.exe(8496): ALWAYS| GAMESTATE_GAMELOOP HUDProcess
    League of Legends.exe(8496): ALWAYS| GAMESTATE_GAMELOOP Particle Simulation
    League of Legends.exe(8496): ALWAYS| GAMESTATE_GAMELOOP FOWUpdate
    League of Legends.exe(8496): ALWAYS| GAMESTATE_GAMELOOP UpdateVis
    League of Legends.exe(8496): ALWAYS| GAMESTATE_GAMELOOP PreRender
    League of Legends.exe(8496): ALWAYS| GAMESTATE_GAMELOOP Render
    League of Legends.exe(8496): ALWAYS| GAMESTATE_GAMELOOP PostProcess
    League of Legends.exe(8496): ALWAYS| GAMESTATE_GAMELOOP ApplyGamma
    League of Legends.exe(8496): ALWAYS| GAMESTATE_GAMELOOP HUDDraw
    League of Legends.exe(8496): ALWAYS| GAMESTATE_GAMELOOP GUIMenuDraw
    League of Legends.exe(8496): ALWAYS| GAMESTATE_GAMELOOP DrawSysInfo
    League of Legends.exe(8496): ALWAYS| GAMESTATE_GAMELOOP MCommandDraw
    League of Legends.exe(8496): ALWAYS| GAMESTATE_GAMELOOP FlushText
    League of Legends.exe(8496): ALWAYS| GAMESTATE_GAMELOOP AudioUpdate
    League of Legends.exe(8496): ALWAYS| GAMESTATE_GAMELOOP EndRender & EndFrame
    League of Legends.exe(8496): ALWAYS| GAMESTATE_GAMELOOP End
    
    //hier hab ich das Spiel beendet
    
    Der Thread 'Win32-Thread' (0x1c48) hat mit Code 0 (0x0) geendet.
    Der Thread 'Win32-Thread' (0x1658) hat mit Code 0 (0x0) geendet.
    Der Thread 'Win32-Thread' (0x2f1c) hat mit Code 0 (0x0) geendet.
    Der Thread 'Win32-Thread' (0x2bd0) hat mit Code 0 (0x0) geendet.
    League of Legends.exe(8496): ALWAYS| Finished Main Loop
    Der Thread 'Win32-Thread' (0x2550) hat mit Code 0 (0x0) geendet.
    Der Thread 'Win32-Thread' (0x2b68) hat mit Code 0 (0x0) geendet.
    Der Thread 'Win32-Thread' (0x2ad4) hat mit Code 0 (0x0) geendet.
    Der Thread 'Win32-Thread' (0x2d30) hat mit Code 0 (0x0) geendet.
    League of Legends.exe(8496): ALWAYS| Finished Play game
    League of Legends.exe(8496): ALWAYS| Game exited
    "League of Legends.exe": "C:\Spiele\Riot Games\League of Legends\RADS\solutions\lol_game_client_sln\releases\0.0.0.232\deploy\LogitechLed.dll" entladen.
    Der Thread 'Win32-Thread' (0x2f10) hat mit Code 0 (0x0) geendet.
    "League of Legends.exe": "C:\Spiele\Riot Games\League of Legends\RADS\solutions\lol_game_client_sln\releases\0.0.0.232\deploy\LogitechGkey.dll" entladen.
    Der Thread 'Win32-Thread' (0x2540) hat mit Code 1 (0x1) geendet.
    Der Thread 'Win32-Thread' (0x214c) hat mit Code 1 (0x1) geendet.
    Der Thread 'Win32-Thread' (0x2b98) hat mit Code 0 (0x0) geendet.
    League of Legends.exe(8496): ALWAYS| r3dRenderLayer::Close() enter
    
    //Zeug vom Spiel selbst
    
    League of Legends.exe(8496): ALWAYS| r3dRenderLayer::Close() exit
    League of Legends.exe(8496): ALWAYS| Destroying the Renderer (1)
    League of Legends.exe(8496): ALWAYS| game::Shutdown
    League of Legends.exe(8496): ALWAYS| ClientFacade::Stop
    League of Legends.exe(8496): ALWAYS| Pre ::R3D::Perf::DinitPerfLists
    League of Legends.exe(8496): ALWAYS| Post ::R3D::Perf::DinitPerfLists
    League of Legends.exe(8496): ALWAYS| Exiting WinMain
    Der Thread 'Win32-Thread' (0x257c) hat mit Code 0 (0x0) geendet.
    Der Thread 'Win32-Thread' (0x2e88) hat mit Code 0 (0x0) geendet.
    Der Thread 'Win32-Thread' (0x1fdc) hat mit Code 0 (0x0) geendet.
    Der Thread 'Win32-Thread' (0x2c80) hat mit Code 0 (0x0) geendet.
    Der Thread 'Win32-Thread' (0x2d48) hat mit Code 0 (0x0) geendet.
    Der Thread 'Win32-Thread' (0x2cd4) hat mit Code 0 (0x0) geendet.
    Der Thread 'Win32-Thread' (0x28d8) hat mit Code 0 (0x0) geendet.
    Der Thread 'Win32-Thread' (0x2ad0) hat mit Code 0 (0x0) geendet.
    Der Thread 'Win32-Thread' (0x2cc8) hat mit Code 0 (0x0) geendet.
    Der Thread 'Win32-Thread' (0x2994) hat mit Code 0 (0x0) geendet.
    Der Thread 'Win32-Thread' (0x2c24) hat mit Code 0 (0x0) geendet.
    Der Thread 'Win32-Thread' (0x283c) hat mit Code 0 (0x0) geendet.
    Der Thread 'Win32-Thread' (0x2408) hat mit Code 0 (0x0) geendet.
    Der Thread 'Win32-Thread' (0x2d6c) hat mit Code 0 (0x0) geendet.
    Der Thread 'UMDShimPresentThread' (0x2328) hat mit Code 0 (0x0) geendet.
    Der Thread 'Win32-Thread' (0x2608) hat mit Code 0 (0x0) geendet.
    Der Thread 'Win32-Thread' (0x2b24) hat mit Code 0 (0x0) geendet.
    Der Thread 'Win32-Thread' (0x2fd4) hat mit Code 0 (0x0) geendet.
    Der Thread 'Win32-Thread' (0x2c54) hat mit Code 0 (0x0) geendet.
    Der Thread 'Win32-Thread' (0x1dd4) hat mit Code 0 (0x0) geendet.
    Der Thread 'Win32-Thread' (0x2ffc) hat mit Code 0 (0x0) geendet.
    Der Thread 'Win32-Thread' (0x2c40) hat mit Code 0 (0x0) geendet.
    Der Thread 'Win32-Thread' (0x2fd0) hat mit Code 0 (0x0) geendet.
    Der Thread 'Win32-Thread' (0x280c) hat mit Code 0 (0x0) geendet.
    Der Thread 'Win32-Thread' (0x2f5c) hat mit Code 0 (0x0) geendet.
    Der Thread 'Win32-Thread' (0x2f18) hat mit Code 0 (0x0) geendet.
    IRC::close
    QUIT :Bye!
    ---------------------
    TatniumD3D Exiting...
    ---------------------
    
    Das Programm "[8620] League of Legends.exe: Systemeigen" wurde mit Code 0 (0x0) beendet.
    

Anmelden zum Antworten