Отслеживание переполнения в Socket Server - PullRequest
0 голосов
/ 31 марта 2012

У меня много проблем с отслеживанием того, где я получаю BufferOverrun в приведенном ниже коде, когда отправляю данные сокета из моего клиента telnet flash / as3. В основном я ищу новые утечки памяти и тому подобное, поэтому в дополнение к этой проблеме, есть ли более простой способ проверки переполнения / переполнения буфера, чем ручная отладка?

    /*
        MTSocketServer
        --------------
        The purpose of this application is to have a client application that can connect to this server.
        This server should be able to parse messages from connected users and to send them to other users.
    */

    // Headers and Namespace
    #include "stdafx.h"
    #include "MTSocketServer.h"
    using namespace std;

    // Constants
    #define BUFFERSIZE 1000
    #define PORT 20248

    // Global Variables
    SOCKET server;
    struct Client_Data
    {
        SOCKET client_socket;
        string user_id;
    };
    list<Client_Data> clients;

    // Method Prototypes
    UINT Server_Thread(LPVOID pParams);
    UINT Client_Thread(LPVOID pParams);
    string Recv_String(SOCKET listener);
    void Send_String(const char* message, SOCKET sender);
    bool Identity_Exists(string id);

    int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
    {
        AfxBeginThread(Server_Thread, NULL);
        while(_getch() != 27);

        closesocket(server);
        WSACleanup();

        return 0;
    }

    UINT Server_Thread(LPVOID pParams)
    {
        // Spawn Server Thread
        cout << "Main thread spawned, press ESC at any time to exit.\r\n";
        WSADATA wsa_data;
        SOCKADDR_IN server_location;

        if (int wsa_return_val = WSAStartup(0x101, &wsa_data) != 0)
        {
            cout << "Incorrect version of 'Ws2_32.dll'.\r\n";
            cout << "Client thread de-initialized.\r\n";
            AfxEndThread(0, true);
            return 1;
        }

        server_location.sin_family = AF_INET;
        server_location.sin_addr.s_addr = INADDR_ANY;
        server_location.sin_port = htons(20248);

        server = socket(AF_INET, SOCK_STREAM, NULL);
        if (server == INVALID_SOCKET)
        {
            cout << "Socket creation error.\r\n";
            cout << "Client thread de-initialized.\r\n";
            AfxEndThread(0, true);
            return 1;
        }

        if (bind(server, (SOCKADDR*)&server_location, sizeof(server_location)) != 0)
        {
            cout << "Socket binding error.\r\n";
            cout << "Client thread de-initialized.\r\n";
            AfxEndThread(0, true);
            return 1;
        }

        if (listen(server, 10) != 0)
        {
            cout << "Socket listening error.\r\n";
            cout << "Client thread de-initialized.\r\n";
            AfxEndThread(0, true);
            return 1;
        }

        SOCKET client;
        SOCKADDR_IN client_location;
        int len_of_client = sizeof(client_location);
        bool abort = false;

        while(abort == false)
        {
            client = accept(server, (SOCKADDR*)&client_location, &len_of_client);

            // Spawn Client Thread
            cout << "Connection from " << inet_ntoa(client_location.sin_addr) << ". Client thread spawned.\r\n";
            AfxBeginThread(Client_Thread, (LPVOID)client);
        }

        // De-Initialize Server Thread
        cout << "Server thread de-initialized.\r\n";
        AfxEndThread(0, true);
        return 0;
    }

    UINT Client_Thread(LPVOID pParams)
    {
        SOCKET client = (SOCKET)pParams;
        string client_id = "";

        // Check if a client with the same ID is on already
        send(client, "ID_ME", 6, 0);
        client_id = Recv_String(client);

        if (Identity_Exists(client_id))
        {
            Send_String("That ID is already taken. Please try another.", client);
        } else
        {
            cout << "Created ID " << client_id << " successfully\r\n";

            Send_String("Type 'send' to send a message, 'quit' to exit.", client);

            Client_Data this_client;
            this_client.user_id = client_id;
            this_client.client_socket = client;

            clients.push_back(this_client);

            bool is_con = true;
            while(is_con)
            {
                string response = Recv_String(client);
                if (response == "send")
                {
                    Send_String("What username to send to?", client);
                    string to_id = Recv_String(client);

                    if (Identity_Exists(to_id))
                    {
                        Send_String("Type your message below: ", client);
                        string temp = Recv_String(client) + "\n\0";
                        const char* message = temp.c_str();

                        for (list<Client_Data>::iterator iterator = clients.begin(), end = clients.end(); iterator != end; ++iterator)
                        {
                            if (to_id == iterator->user_id)
                            {
                                SOCKET temp = iterator->client_socket;
                                cout << temp;
                                Send_String(message, temp);
                            }
                        }
                    } else
                    {
                        Send_String("Invalid username specified", client); 
                    }   
                }
                else if (response == "quit")
                {
                    Send_String("Quit Command Issued", client);
                    break;
                }
                else
                {
                    Send_String("Invalid Command Issued", client);
                }
            }
        }

        // De-Initialize Client Thread
        closesocket(client);
        cout << "Client thread de-initialized.\r\n";
        AfxEndThread(0, true);
        return 0;
    }

    // Function to parse full string values since they are often recieved one at a time
    string Recv_String(SOCKET listener)
    {
        char buffer[BUFFERSIZE];
        string temp;
        int numofbytes = 0;

        while (true)
        {
            int num = recv(listener, buffer, BUFFERSIZE, 0);
            numofbytes++;

            buffer[num] = '\0';
            if (buffer[num-1] == '\n')
                break;

            if(numofbytes >= BUFFERSIZE-1)
                break;

            temp += buffer;
            strcpy(buffer, "");
       }

        return temp;
    }

    void Send_String(const char* message, SOCKET sender)
    {
        char buffer[BUFFERSIZE];
        strcpy(buffer, message);
        size_t size = strlen(message);

        int sendtest = send(sender, buffer, size, 0);
        strcpy(buffer, "");
    }

    bool Identity_Exists(string id)
    {
        for (list<Client_Data>::iterator iterator = clients.begin(), end = clients.end(); iterator != end; ++iterator)
        {
            if (id == iterator->user_id)
            {
                return true;
            }
        }

        return false;
    }

1 Ответ

0 голосов
/ 31 марта 2012

buffer[num] = '\0'; записывает один за пределы буфера, если num оказывается равным BUFFERSIZE. Он записывает один ниже буфера, если num равен -1.

if (buffer[num-1] == '\n') хотя и не переполнение буфера, это тоже неправильно. \ N может быть в любом месте (от 0 до n-1) в буфере.

...