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.