0

I have been working on a project and boy oh boy does my head hurt on this one. I am using a networking library called "enet" and I am trying to assign the client who connects information. Using the tutorial on the site, I use: server.event.packet->data = "client info"; However, enet complains that the string is not an "unsigned char *". Here is the build log (using clang++ to compile):

./network.h:9:14: warning: in-class initialization of non-static data member accepted as a C++11 extension [-Wc++11-extensions] int clients = 0; ^ main.cpp:142:28: error: assigning to 'enet_uint8 *' (aka 'unsigned char *') from incompatible type 'const char [12]'; server.event.packet->data = "client info"; ^ ~~~~~~~~~~~~~

I have tried every type of casting I can think of and that I have searched for, but nothing seems to work. I can't make the darn thing happy.

Main.cpp:

#include <iostream>
#include <string>
#include <sstream>
#include <istream>
#include <cstring>
#include <cstdio>
#include <unistd.h>
#include <stdio.h>
#include "network.h"
#include "clients.h"
#include "config.h"

void runCommand(std::string command);
int startNetwork();
void shutdownNetwork();
void addClientRecord();
std::string getUsername();

std::string username;

bool manualInput = false;
bool debug = true;

int iPeerCount = 0;

Server server;

int main(int argc, char ** argv){
    std::string currentCommand;

    if(manualInput==true){
        std::cout << "Please type a command: ";
        std::getline(std::cin,currentCommand);
        if(debug == true){
            std::cout << currentCommand << std::endl;
        }
        runCommand(currentCommand);
    }

    startNetwork();

    atexit(shutdownNetwork);

    return 0;
}

int startNetwork(){
    if (enet_initialize () != 0){
        std::cout << "\nAn error has occured while initializing ENet.\n";
        return EXIT_FAILURE;
    }
    server.startServer();
    return 1;
}

void shutdownNetwork(){
    enet_deinitialize();
}

int Server::startServer(){

//  server.serverOne = enet_host_create (& server.address, 32, 2, 0, 0);

//  if(CUSTOM_HOST == true){
//      enet_address_set_host(&address, HOST);
//  } else {
    server.address.host = ENET_HOST_ANY;
//  }
    server.address.port = PORT;

    server.serverOne = enet_host_create( & server.address, 32, 2, 0, 0);

        if(debug==true){
                printf("[NETWORK] Host: %x \n[NETWORK] Port: %u\n", server.address.host, address.port);
        }

    if(server.serverOne==NULL){
        std::cout << "\nAn error has occured while starting the ENet server.\n";
        exit (EXIT_FAILURE);
    }

    monitor();
    return 1;
}


void Server::monitor(){
    int clients = 0;
    if(debug==true){
        printf( "[NETWORK] Waiting for commands...\n" );
    }
    printf("[NETWORK] Server online, awaiting commands and/or connections...\n");
    scan_network:
    while(enet_host_service (serverOne, & event, 1000) > 0){
        switch(event.type){
            case ENET_EVENT_TYPE_CONNECT:
                clients++;
                printf("[INFO] New connection from: %x:%u.\n", event.peer -> address.host, event.peer -> address.port);
                addClientRecord();
    /*          for(int x=0;x<32;x++){
                    if(clients[x].name != ""){ }
                    else{
                        clients[x].name = "full";
                    }
                }*/
                break;
            case ENET_EVENT_TYPE_RECEIVE:
                if(debug==true){ printf("A packet of length %lu containing %s was received from %s on channel %u.\n", event.packet -> dataLength, event.packet -> data, event.peer -> data, event.channelID); }
                runCommand(reinterpret_cast<const char*>(event.packet -> data));
                enet_packet_destroy(event.packet);
/*              printf("Disconnect client %s ? ", event.peer -> data);
                gets(buffer);
                std::cout<<buffer<<std::endl;
                if(buffer=="yes"){
                    enet_peer_disconnect(event.peer, 0);
                }*/   //Do not use until fixed or spam!
                break;
            case ENET_EVENT_TYPE_DISCONNECT:
                clients--;
                printf("%s disconnected.\n", event.peer -> data);
                event.peer -> data = NULL;
            case ENET_EVENT_TYPE_NONE:
                break;
        }
    }
    goto scan_network;
}

void runCommand(std::string command){
    if((command == "disconnect") || (command == "Disconnect") || (command=="DISCONNECT")){
        enet_peer_disconnect(server.event.peer,0);
        printf("[INFO] Client %s issued the disconnect command.\n", server.event.peer -> data);
    }
}

std::string getUsername(){
    return username;
}

void addClientRecord(){
    std::string bufferName = ("client " + server.clients);
    server.event.packet->data = "client info";
}

Network.h:

#include <enet/enet.h>

class Server {
    public:
    ENetAddress address;
    ENetHost * serverOne;
    ENetEvent event;

    int clients = 0;

    int startServer();
    void monitor();
};

Any ideas and help is appreciated greatly. Cheers!

Jacob Hartmann
  • 115
  • 1
  • 1
  • 10

1 Answers1

0

As far as I can see server is a struct of type Server, its field event is ENetEvent, and its field packet is of type _ENetPacket* and its field data is a unsigned char*. So now what is hapening: you create a сstring on the stack, then assign address of the first element to the data field of global object, then you leave the function and pointer is still alive while data stored there is no longer avaliable. That is why you get segfault when using correct typecast to unsigned char*. So you should do the following:

void addClientRecord()
{
  std::string bufferName = ("client " + server.clients);
  char* clientName = "client info";
  // Allocate mem
  char* data = new unsigned char[strlen(clientName)];
  // Copy string there
  strcpy(data, clientName);
  // Store pointer
  server.event.packet->data = (unsigned char*)data;
}

and do no not forget to clear that allocated mem. That is for you should always check if server.event.packet->data contains non-nullptr value and if it does - delete and only then assign. And you should provide a destructor for Server where it will delete that string if any present and constructor to write there a nullptr on start so you won't delete some trash address, which most certainly will lead to crash. But first of all you need to figure out whether _ENetPacket or ENetEvent classes provide any functionality for data mentioned above. This is how cstrings work.

P.S. There should be a compiler flag that will toggle char to be unsigned by default.

Teivaz
  • 5,462
  • 4
  • 37
  • 75