winsock2 / netcat / tcp problem?



  • tag,

    ich hab jetzt stunden damit verbracht mich durch verschiedene socket dokumentationen zu wühlen aber finde partout keine lösung hierfür.
    Das Problem ist folgendes:

    Ich habe mit WPEpro, einem sehr simplen packetsniffer, die basis verbindungssequenz zwischen einem spielclienten und einem server geloggt.

    Die Sequenz ist sehr simpel:

    client->server: LOGIN_REQUEST "version" "username" "passwort"
    server->client: LOGIN_RESPONSE ok.

    Nach dieser Sequenz müsste man im Spiel eingeloggt sein und der Gameclient ins Hauptmenü springen.

    Nun nahm ich netcat her und startete mit

    nc.exe -L -p 33333

    eine netcat instanz die auf port 33333 lief.
    Ich connectete mit dem Gameclient auf diesen NCServer und sah in Netcat
    erwartungsgemäß den gleichen Plaintext den ich auch gesnifft habe:

    client->(netcat)server: LOGIN_REQUEST "version" "username" "passwort"

    Jetzt konnte ich im Netcat server fenster eingeben:

    LOGIN_RESPONSE ok.

    und tadaaa: Der Game Client wechselt erfolgreich ins Hauptmenü. Ganz so, als ob ich mich auf den funktionierenden Server verbunden hätte.

    Jetzt mein Problem:

    Ich wollte nun mit c++ einen kleinen server emulator schreiben.
    Nach etwas googlen war ich dann soweit eine Verbindung mit winsock2 herzustellen.
    Auch der Transfer klappt eigentlich aber obwohl ich in meinem c++ Programm
    exakt den gleichen string versende:

    "LOGIN_RESPONSE ok."

    bleibt der game client einfach "stehen". Wohlgemerkt, er freezt nicht, ich kann andere buttons nutzen und das LOGIN_REQUEST nochmal senden.
    Es kommt auch nochmal an, und es wird auch "LOGIN_RESPONSE ok." von meinem c++ server geantwortet, aber dann passiert einfach nichts.

    Ich habe jetzt kreuz und quer verbindungen zwischen netcat, game client und c++ server erstellt und versucht mit WPE genaueres rauszufinden.

    Dabei bin ich darauf gestoßen dass die "LOGIN_RESPONSE ok." verschiedene Längen zu haben scheint, aber ich komme nicht drauf wo das problem liegt.
    Um das mit der Länge zu testen habe ich einfach mal statt dem LOGIN_REQUEST
    ein LOGIN_RESPONSE ok. als Anfrage verschickt und den C++ Server den gleichen Buffer der recv() bedient wieder per send() verschicken lassen, und merkwürdig:

    Verbindung C++-Server <-> Netcat als Client.

    NCClient -> C++-Server: LOGIN_RESPONSE ok. <--- 19 bytes
    und als der C++ Server _eigentlich_ das gleiche zurückschicken soll:

    C++-Server -> NCClient: LOGIN_RESPONSE ok. <-- 18 bytes

    Mein Verdacht liegt auf nicht ordnungsgemäß verarbeiteten strings da ich mir alles in c++ erst zusammen googlen muss.
    Vielleicht liegt das Problem aber auch an meiner dilettantisch zusammenkopierten socket implementierung.
    Aber was kann ich außer
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;

    falsch einstellen wenn es sich um ein TCP packet handelt?
    Der client (und auch der offizielle server) sind in Java geschrieben.
    Beide sind open source. Mein gepfrickel damit dient der c++ education.
    Ich hoffe ich konnte halbwegs präzise das Problem beschreiben.

    Hier noch der Code, und vielen Dank für jede Idee:

    P.S.: Jaja ich weiß, ich glaube ich hab einige includes dadrin die ich nicht bräuchte... das liegt schlicht daran dass zig verschiedene tuts mit c oder c++ arbeiten und jedesmal stehen andere header drin.

    #define _WIN32_WINNT 0x501
    
    #include <winsock2.h>
    #include <windows.h>
    #include <iostream>
    #include <ws2tcpip.h>
    #include <iphlpapi.h>
    #include <stdio.h>
    #include <string.h>
    
    #pragma comment(lib, "ws2_32.lib")
    
    using namespace std;
    
    int main()
    {
        // read config
        #define DEFAULT_PORT "33333"
    
        // prepare system - winsock, etc
        WSADATA wsaData;
    
        cout << "WSAStartup..." << endl;
        int iResult;
        iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
        if (iResult != 0) {
            cout <<"WSAStartup failed: "<< iResult << endl;
            return 1;
        }
    
        cout << "Preparing listen socket..." << endl;
        struct addrinfo *result = NULL, *ptr = NULL, hints;
    
        ZeroMemory(&hints, sizeof (hints));
        hints.ai_family = AF_INET;
        hints.ai_socktype = SOCK_STREAM;
        hints.ai_protocol = IPPROTO_TCP;
        hints.ai_flags = AI_PASSIVE;
    
        // Resolve the local address and port to be used by the server
        iResult = getaddrinfo(NULL, DEFAULT_PORT, &hints, &result);
        if (iResult != 0) {
            cout << "getaddrinfo failed: " << iResult << endl;
            WSACleanup();
            return 1;
        }
    
        SOCKET ListenSocket = INVALID_SOCKET;
    
        // Create a SOCKET for the server to listen for client connections
    
        ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
    
        if (ListenSocket == INVALID_SOCKET) {
            cout << "Error at socket(): " << WSAGetLastError();
            freeaddrinfo(result);
            WSACleanup();
            return 1;
        }
    
         // Setup the TCP listening socket
        iResult = bind( ListenSocket, result->ai_addr, (int)result->ai_addrlen);
        if (iResult == SOCKET_ERROR) {
            printf("bind failed with error: %d\n", WSAGetLastError());
            freeaddrinfo(result);
            closesocket(ListenSocket);
            WSACleanup();
            return 1;
        }
    
        cout << "Awaiting connection..." << endl;
        if ( listen( ListenSocket, SOMAXCONN ) == SOCKET_ERROR ) {
            printf( "Listen failed with error: %ld\n", WSAGetLastError() );
            closesocket(ListenSocket);
            WSACleanup();
            return 1;
        }
    
        SOCKET ClientSocket;
    
        ClientSocket = INVALID_SOCKET;
    
        // Accept a client socket
        ClientSocket = accept(ListenSocket, NULL, NULL);
        if (ClientSocket == INVALID_SOCKET) {
            printf("accept failed: %d\n", WSAGetLastError());
            closesocket(ListenSocket);
            WSACleanup();
            return 1;
        }
    
        u_long iMode=1;
        ioctlsocket(ClientSocket,FIONBIO,&iMode);
        #define DEFAULT_BUFLEN 512
    
        char recvbuf[DEFAULT_BUFLEN];
        int iSendResult;
        int recvbuflen = DEFAULT_BUFLEN;
    
        // Receive until the peer shuts down the connection
        // Ich habe schon auf alle erdenklichen Arten versucht den String in den Buf zu bekommen, strcpy, strcat, was weiß ich, in jedem tutorial stets anders drin.
    
        const char *sendbuf = "LOGIN_RESPONSE ok.";
        cout << sendbuf << endl;
        int i = 0;
        do {
            cout << "Loop: " << i << endl;
            iResult = recv(ClientSocket, recvbuf, recvbuflen, 0);
            if (iResult > 0) {
                cout << "RECV "<< iResult << " bytes: ";
                cout << recvbuf << endl;
                cout << strlen(recvbuf);
                iSendResult = send(ClientSocket, sendbuf, (int)strlen(sendbuf), 0);
                cout << "SEND " << iSendResult << " bytes: " << sendbuf << endl;
            } else if (iResult == 0)
                printf("Connection closing...\n");
            Sleep(1000);
            i++;
        } while (1);
    
        WSACleanup();
        return 0;
    }
    


  • Das gehört ins WinAPI-Forum. Jemand wird dich bald dorthin verschieben.

    #include <stdio.h> 
    #include <string.h>
    

    gibt es in C++ nicht. Wenn doch, dann hast du Glück. Es sollte so aussehen:

    #include <cstdio> 
    #include <string>
    


  • Wenn du die Zeichen von "LOGIN_RESPONSE ok." durchzählst, kommst du auf 18. Wenn der "echte" server 19 verschickt, wird da wohl noch ein nicht lesbares Zeichen hinter hängen. Welches das ist, musst du wohl selbst rausfinden 🙂



  • EOutOfResources schrieb:

    Das gehört ins WinAPI-Forum. Jemand wird dich bald dorthin verschieben.

    #include <stdio.h> 
    #include <string.h>
    

    gibt es in C++ nicht. Wenn doch, dann hast du Glück. Es sollte so aussehen:

    #include <cstdio> 
    #include <string>
    

    Die alten Header der C-Standardbibliothek existieren auch noch in C++, auch wenn dort ihre C++-Version genutzt werden sollte. Und außerdem ist <string> nicht die Entsprechung zu <string.h> 😉



  • pumuckl schrieb:

    Wenn du die Zeichen von "LOGIN_RESPONSE ok." durchzählst, kommst du auf 18. Wenn der "echte" server 19 verschickt, wird da wohl noch ein nicht lesbares Zeichen hinter hängen. Welches das ist, musst du wohl selbst rausfinden 🙂

    ja dass dachte ich mir auch. Aber es muss sich um ein "allgemeines" Zeichen handeln (nicht eines vom "echten" Server), da ein mit netcat versandtes "LOGIN_RESPONSE ok." ja funktioniert.
    Deshalb war meine Überlegung dass mein C++ Server den send() Vorgang vielleicht nicht richtig "abschließt" oder etwas ähnliches.



  • Vielleicht ist das fehlende Zeichen ja der Zeilenumbruch. Hast du mal die Länge des manuell gesendeten Response mit deiner Programm-Ausgabe verglichen?
    (und mitunter hilft es auch, die Daten nicht nur in Textform anzusehen, sondern binär)



  • CStoll schrieb:

    Vielleicht ist das fehlende Zeichen ja der Zeilenumbruch. Hast du mal die Länge des manuell gesendeten Response mit deiner Programm-Ausgabe verglichen?
    (und mitunter hilft es auch, die Daten nicht nur in Textform anzusehen, sondern binär)

    genau das wars. ich habe im plaintext des sniffers immer lediglich einen Punkt am ende gesehen, ohne zu merken dass in der hex schreibweise dieser punkt aus 0D 0A bestand, und google meinte das könnte doch der zeilenumbruch sein.

    Es funktioniert jetzt, danke für alle hinweise


Anmelden zum Antworten