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!
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.
Related
I am trying to fire a function every time an ESP32 node receives a certain char. I can receive the data and parse the char out of a packet structure I have made. I register all my actions in a map of type <char,callback_function>, where
typedef void (*callback_function)(void);
The idea being that I link all the chars to their respective functions. I can then parse a char out and find the pointer to the function I want to fire easily. The only downside is I have to keep a reference to a global object to access this map from within the bluetooth_callback. I've been testing this for almost 2 days now, and I've written some example code without the espressif APIs. On its own, my code seems to work fine and it runs on the ESP32 aswell. But if I let the bluetooth_callback get called after registering it with the espressif API (ie. let a real bluetooth event to fire the callback), the behavior becomes undefined. The size of the map is still correct with the number of pairs I have added to it, but all of the values and keys are null or undefined, and if I try to access them I get a Guru Meditation Error. I have been trying to solve this problem a lot, and the behaviour is very strange to me. If I call the callback manually then everything seems to work, but if I let it get called by a bluetooth event, I get undefined behavior and crashes. I'm not sure if I am doing something wrong c++ wise or if I this is an issue specific to the esp32. I could be making a dumb mistake. I have attached my Arduino script, the header and cpp files of the library I was working on, and a sample application that should show what I am trying to do. Thank you for your help.
Hardware:
Board: ESP32 Dev Module (Sparkfun ESP32 thing)
Core Installation version: 1.0.3
IDE name: Arduino IDE
Flash Frequency: 40Mhz
PSRAM enabled: no
Upload Speed: 115200
Computer OS: Windows 10
Backtrace
Guru Meditation Error: Core 0 panic'ed (LoadProhibited). Exception was unhandled.
Core 0 register dump:
PC : 0x400014e8 PS : 0x00060430 A0 : 0x800d2410 A1 : 0x3ffcf1a0
A2 : 0x000000fe A3 : 0x000000fc A4 : 0x000000ff A5 : 0x0000ff00
A6 : 0x00ff0000 A7 : 0xff000000 A8 : 0x800d2228 A9 : 0x3ffcf170
A10 : 0x3ffbed90 A11 : 0x3f40148b A12 : 0x3f40148b A13 : 0x0000ff00
A14 : 0x00ff0000 A15 : 0xff000000 SAR : 0x00000010 EXCCAUSE: 0x0000001c
EXCVADDR: 0x000000fc LBEG : 0x400014fd LEND : 0x4000150d LCOUNT : 0xfffffffb
Backtrace: 0x400014e8:0x3ffcf1a0 0x400d240d:0x3ffcf1b0 0x400d242d:0x3ffcf1d0 0x400d14a2:0x3ffcf1f0 0x400d1501:0x3ffcf210 0x400df881:0x3ffcf230 0x400d8362:0x3ffcf280 0x4008d83d:0x3ffcf2b0
Decoded:
PC: 0x400014e8
EXCVADDR: 0x000000fc
Decoding stack results
0x400d240d: Print::write(char const*) at C:\Users\Jake Booth\Documents\ArduinoData\packages\esp32\hardware\esp32\1.0.3\cores\esp32/Print.h line 66
0x400d242d: Print::print(char const*) at C:\Users\Jake Booth\Documents\ArduinoData\packages\esp32\hardware\esp32\1.0.3\cores\esp32\Print.cpp line 89
0x400d14a2: NodeESP::act_message(char*) at C:\Users\Jake Booth\Documents\Arduino\libraries\NodeESP\NodeESP.cpp line 336
0x400d1501: NodeESP::bluetooth_callback(esp_spp_cb_event_t, esp_spp_cb_param_t*) at C:\Users\Jake Booth\Documents\Arduino\libraries\NodeESP\NodeESP.cpp line 176
0x400df881: btc_spp_cb_handler at /Users/ficeto/Desktop/ESP32/ESP32/esp-idf-public/components/bt/bluedroid/btc/profile/std/spp/btc_spp.c line 152
0x400d8362: btc_task at /Users/ficeto/Desktop/ESP32/ESP32/esp-idf-public/components/bt/bluedroid/btc/core/btc_task.c line 110
0x4008d83d: vPortTaskWrapper at /Users/ficeto/Desktop/ESP32/ESP32/esp-idf-public/components/freertos/port.c line 143
I've highlighted line 336 below to show you easily which one it is.
Arduino Sketch
#include "NodeESP.h"
#define LED_PIN 5
#define TOGGLE_LED_CHAR 'l'
#define TURN_ON_LED_CHAR 'p'
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
pinMode(LED_PIN,OUTPUT);
char l = TOGGLE_LED_CHAR;
char p = TURN_ON_LED_CHAR;
esp_spp_cb_param_t ex_param;
ex_param.data_ind.data = (uint8_t*)l;
ex_param.data_ind.len = 1;
//ex_param_ptr = *ex_param;
NodeESP node_esp;
node_esp.add_func(&p, toggle_LED);
node_esp.add_func(&l, turn_on_LED);
node_esp.begin("TEST_1");
//Just calling it manually works, but when the espressif API calls it I get undefined behaviour.
// NodeESP::bluetooth_callback(ESP_SPP_DATA_IND_EVT,&ex_param);
}
void toggle_LED()
{
Serial.println("toggle_LED()");
}
void turn_on_LED()
{
Serial.println("turn_on_LED()");
}
void loop() {
// put your main code here, to run repeatedly:
while(1)
{
vTaskDelay(100 / portTICK_PERIOD_MS);
}
}
NodeESP.h
/*
NodeESP.cpp - Library for automatically connecting to and using esp32 microcontrollers
Created by Jacob Booth 11/9/2020
*/
#ifndef NodeESP_h
#define NodeESP_h
#include "Arduino.h"
#include <ESPmDNS.h>
#include <WiFi.h>
#include <map>
#include "esp_bt_main.h"
#include "esp_bt_device.h"
#include "esp_spp_api.h"
#include "esp_gap_bt_api.h"
//---Define buffer constants--------------------------
#define RCV_BUF_SIZE 128
#define TX_BUF_SIZE 256
//---Define communication constants-------------------
#define RFCOMM_CHANNEL 1
#define RFCOMM_MAX_FRAME_SIZE 0xffff
#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED)
#error Bluetooth is not enabled! please run 'make menuconfig' to enable it
#endif
class NodeESP
{
public:
//Constructor
NodeESP();
//Begin
bool begin(const char *_name);
//Typedef
typedef void (*callback_function)(void);
//Variables
uint32_t bt_handle;
const char *_name;
std::map<char*, callback_function> funcs;
char rx_buf[RCV_BUF_SIZE];
char tx_buf[RCV_BUF_SIZE];
WiFiServer server;
WiFiClient client;
//Generic
void add_func(char* command, callback_function func);
void act_message(char* trigger);
//Bluetooth
void bluetooth_write(char *buf, int len);
bool bluetooth_spp_init();
bool bluetooth_init(const char *deviceName);
static char parse_data(uint8_t *rcvd, uint16_t len);
static void bluetooth_callback(esp_spp_cb_event_t event, esp_spp_cb_param_t *param);
String toString(const IPAddress & address);
private:
};
#endif
NodeESP.cpp
/*
NodeESP.cpp - Library for automatically connecting to and using esp32 microcontrollers
Created by Jacob Booth 11/9/2020
*/
#include "Arduino.h"
#include <ESPmDNS.h>
#include <WiFi.h>
#include <map>
#include "esp_bt_main.h"
#include "esp_bt_device.h"
#include "esp_spp_api.h"
#include "esp_gap_bt_api.h"
#include "NodeESP.h"
using namespace std;
//---State Machine Variables---
//State enum that helps the state machine track its way through
//connecting to wifi.
enum state_t {
UNDEFINED,
DISCONNECTED,
WIFI_CON,
SERVER_CON
};
enum comm_t {
s,
NONE,
WIFI,
BLUETOOTH,
q
};
//The current communication protocol we are using
comm_t cur_comm = s;
//The current state
state_t cur_state = UNDEFINED;
char tx_buf[TX_BUF_SIZE];
char rx_buf[RCV_BUF_SIZE];
//---Wifi
WiFiServer server(0);
WiFiClient client;
//---Bluetooth
uint32_t bt_handle;
void* example_obj;
//---Main Init--------------------------------------------------------
NodeESP::NodeESP()
{
this->_name = "default";
example_obj = (void*)this;
}
bool NodeESP::begin(const char *_name)
{
this->_name = _name;
//For testing set the current communication method to bluetooth
cur_comm = BLUETOOTH;
switch (cur_comm)
{
case UNDEFINED:
return false;
break;
case NONE:
return false;
break;
case WIFI:
return true;
break;
case BLUETOOTH:
if (!this->bluetooth_init(_name))
{
return false;
}
break;
}
return true;
}
//---Bluetooth Functions--------------------------------
bool NodeESP::bluetooth_init(const char *deviceName)
{
//Start Bluetooth
if (!btStart())
{
return false;
}
//Start BlueDroid (bluetooth stack)
if (esp_bluedroid_init()!= ESP_OK)
{
return false;
}
//Enable BlueDroid
if (esp_bluedroid_enable()!= ESP_OK)
{
return false;
}
//Set device name
esp_bt_dev_set_device_name(deviceName);
//Set sannable and discoverable
esp_bt_gap_set_scan_mode(ESP_BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE);
//Init spp server
if (!this->bluetooth_spp_init())
{
return false;
}
//Set send bytes to the correct callback
//send_bytes = write_bluetooth;
return true;
}
bool NodeESP::bluetooth_spp_init()
{
if (esp_spp_register_callback(&bluetooth_callback) != ESP_OK)
{
return false;
}
if (esp_spp_init(ESP_SPP_MODE_CB) != ESP_OK)
{
return false;
}
if (esp_spp_start_srv(ESP_SPP_SEC_NONE, ESP_SPP_ROLE_SLAVE, 1, "") != ESP_OK)
{
return false;
}
return true;
}
void NodeESP::bluetooth_write(char *buf, int len)
{
esp_spp_write(bt_handle, len, (uint8_t*)buf);
}
void NodeESP::bluetooth_callback(esp_spp_cb_event_t event, esp_spp_cb_param_t *param)
{
switch (event)
{
case ESP_SPP_SRV_OPEN_EVT:
{
NodeESP* self = (NodeESP*) example_obj;
self->bt_handle = param->srv_open.handle;
break;
}
case ESP_SPP_CL_INIT_EVT:
esp_bt_gap_set_scan_mode(ESP_BT_SCAN_MODE_NONE);
break;
case ESP_SPP_OPEN_EVT:
break;
case ESP_SPP_DATA_IND_EVT:
{
NodeESP* self = (NodeESP*) example_obj;
//char trig = self->parse_data(param->data_ind.data, param->data_ind.len);
self->act_message((char*)param->data_ind.data);
break;
}
case ESP_SPP_CLOSE_EVT:
esp_bt_gap_set_scan_mode(ESP_BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE);
case ESP_SPP_WRITE_EVT:
break;
case ESP_SPP_CONG_EVT:
break;
}
return;
}
//---Parsing functions-------------------------------
//TODO: Add circular buffer
char NodeESP::parse_data(uint8_t *rcvd, uint16_t len)
{
char body_buf[RCV_BUF_SIZE];
uint8_t len_buf[2];
uint8_t rcvd_bytes = 0;
uint8_t recive_stage = 0;
uint16_t calc_len = 0;
//Loop through each char recieved
for (uint16_t i = 0; i < len; i++)
{
uint8_t cur_char = rcvd[i];
rcvd_bytes++;
//If we haven't recieved the length or body
//And we recieve a start delim
if (recive_stage == 0 && cur_char == 0x7E)
{
//We are ready to read the length of the message (next 2 bytes)
recive_stage = 1;
rcvd_bytes = 0;
}
else if (recive_stage == 1)//If we are recieving the length
{
//Next two bytes get stored in the length buffer
len_buf[rcvd_bytes - 1] = cur_char;
//If we have recieved the 2 length bytes
if (rcvd_bytes == 2)
{
//Decode the length
calc_len = ((uint16_t)len_buf[0]) << 8 | (uint16_t)len_buf[1];
//Ready to recieve the body
recive_stage = 2;
rcvd_bytes = 0;
}
}
else if (recive_stage == 2)//If we are recieving the body
{
//Store the recieved bytes
body_buf[rcvd_bytes - 1] = cur_char;
if (rcvd_bytes == calc_len)
{
//Reset
rcvd_bytes = 0;
recive_stage = 0;
return(cur_char);
}
}
}
return '/';
}
void NodeESP::add_func(char* command, callback_function func)
{
Serial.println("Added new callback...");
std::pair<char*, callback_function>* new_pair = new std::pair<char*, callback_function>(command,func);
this->funcs.insert(*new_pair);
}
void NodeESP::act_message(char* trigger)
{
Serial.println("[act message]");
Serial.print("funcs.size() = ");
Serial.print(this->funcs.size()); //Always returns the correct size all of the time
Serial.println("");
for (std::map<char*, callback_function>::iterator it = this->funcs.begin();
it != this->funcs.end();
++it)
{
Serial.print("funcs[i].first = ");
Serial.print(it->first); //Line 336, accessing the first element of the iterator
Serial.println(""); //This works properly when I don't call the function through the callback.
if (trigger == it->first)
{
(it->second)();
}
}
}
String NodeESP::toString(const IPAddress & address)
{
return String(address[0]) + "." + address[1] + "." + address[2] + "." + address[3];
}
Example Program
Here is an example program that shows what I want to happen and that it works correctly.
// Example program
#include <iostream>
#include <string>
#include <map>
//Global object to access the instance from within static function
using namespace std;
class example
{
public:
example();
void begin();
typedef void (*callback_function)(void);
std::map<char, callback_function> funcs;
void add_func(char command, callback_function func);
void do_something(char trigger);
static void example_callback(char cb);
};
void* example_obj;
example::example()
{
example_obj = (void*)this;
}
void example::begin()
{
//Set up everything to do with external library, peripherals, ect...
//Register the callback with the library
//register_callback(&example_callback);
}
//Static func that does something
void example::example_callback(char cb)
{
//Have to do this because the args need to match the library's requirements
example* self = (example*) example_obj;
//Do some processing...
self->do_something(cb);
}
//Add a function pointer and its command char to the vector
void example::add_func(char command, callback_function func)
{
std::pair<char, callback_function>* new_pair = new std::pair<char, callback_function>(command,func);
this->funcs.insert(*new_pair);
}
//This function is called from the callback
void example::do_something(char trigger)
{
cout << "funcs.size() = "<< (this->funcs.size())<<"\n"; //Always returns the correct size all of the time
for (std::map<char, callback_function>::iterator it = this->funcs.begin();
it != this->funcs.end();
++it)
{
cout << "funcs[i].first = "<< (it->first)<<"\n";
if (trigger == it->first)
{
(it->second)();
}
}
}
void callback()
{
cout << "Callback Called!";
}
int main()
{
cout << "Starting program...\n";
cout << "Creating example object...\n";
example ex;
cout << "Adding some callbacks...\n";
ex.add_func('x',callback);
ex.add_func('y',callback);
ex.add_func('z',callback);
cout << "Firing callback...\n";
example::example_callback('z');
}
I'm attempting to build a simple interface to use shm ipc in c++. For that, I've written the following code:
sharedmem.h:
#pragma once
#include <iostream>
#include <sstream>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
using namespace std;
namespace IPC
{
void Send(const string filename, std::string msg,int size=1024 )
{
key_t key = ftok(filename.c_str(),65);
std::stringstream ss;
ss << msg.c_str();
int shmid = shmget(key,size,0666|IPC_CREAT);
char *str = (char*) shmat(shmid,(void*)0,0);
ss >> str;
shmdt(str);
}
string Receive(const string filename, int size=1024 )
{
key_t key = ftok(filename.c_str(),65);
int shmid = shmget(key,size,0666|IPC_CREAT);
char *str = (char*) shmat(shmid,(void*)0,0);
string ret(str);
shmdt(str);
shmctl(shmid,IPC_RMID,NULL);
return ret;
}
};
Outside, I use it like:
sender.cpp
#include "sharedmem.h"
int main()
{
IPC::Send("fila1", "hello ipc");
return 0;
}
receiver.cpp
#include "sharedmem.h"
int main()
{
std::string ret = IPC::Receive("fila1");
cout << "Recebi na fila: " << ret;
return 0;
}
CMakeLists.txt:
set (CMAKE_CXX_STANDARD 17)
add_executable(sender sender.cpp)
add_executable(receiver receiver.cpp)
and built with cmake . && make
In this example I write "hello ipc" but the other process reads only "hello". What could be wrong here? Thanks in advance.
In your send function:
void Send(const string filename, std::string msg,int size=1024 )
{
key_t key = ftok(filename.c_str(),65);
std::stringstream ss;
ss << msg.c_str();
int shmid = shmget(key,size,0666|IPC_CREAT); // this call could fail, what happens next is
// a likely a segmentation error.
// ... or worse.
char *str = (char*) shmat(shmid,(void*)0,0);
ss >> str; // <-- error is here. You extract from ss until the first whitespace character.
// what happens if input string is larger than the size of the allocated block?
shmdt(str);
}
The stringstream ss has no functional use in your function, except for adding a bug. I suggest you try this instead:
int Send(const string& filename, const std::string& msg) noexcept // if you have no return value,
// you should throw on error,
// let's avoid that
{
key_t key = ftok(filename.c_str(), 65); // you should maybe consider using a named constant
// for your project ID
if (key == -1)
return errno;
int shmid = shmget(key, msg.length() + 1, 0666 | IPC_CREAT); // allocate enough memory for the
// message, plus its NULL terminator
if (shmid == -1)
return errno;
void *shared_mem = shmat(shmid, nullptr, 0);
if (shared_mem == (void*)-1)
{
// the systeml failed to lock the allocated memory.
// do some cleanup by de-allocating the shared memory block.
int ret = errno; // keep original error for return.
shmctl(shmid , IPC_RMID, nullptr);
return ret;
}
// copy message string with its NULL terminator to shared memory
memcpy(shared_mem, msg.c_str(), msg.length() + 1); // using length() + 1 is ok here, result of
// c_str() always has a NULL terminator.
shmdt(shared_mem);
return 0;
}
Your receive function also lacks in error checking. That should be very similar to the Send() function.
Note that the strings are passed by const reference, that's to avoid copying them (and the potential errors associated with those unneeded memory allocations)
In my assignment I have to fork processes to simulate a distributed operating system with process allocating using Heuristic Algorithm On Linux using IPC.
Now I fork n children and then make them simulate the algorithm, that's not the problem though the problem is in the message queue connections between all of them
There is 2 message queues UP and DOWN they are both not working atm.
Every time I try to send something over any of these queues they are received at the other side as garbage.
So, I use this struct and those methods for dealing with message queue
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/shm.h>
struct msgbuff
{
long mtype;
char mtext[70];
};
void Send(key_t msgqid,char* S,long pid)
{
int send_val;
struct msgbuff message;
message.mtype = pid; /* arbitrary value */
strcpy(message.mtext,S);
cout<<"Message is "<<message.mtext<<endl;
//strcpy(message.mtext, str);
cout<<getpid()<<" Entering Send process"<<endl;
send_val = msgsnd (msgqid, &message, sizeof(message), IPC_NOWAIT);
if(send_val == -1)
perror("Error in send");
}
char* Recieve(key_t msgqid,bool nowait)
{
int rec_val;
struct msgbuff message;
cout<<getpid()<<" Entering Receive process"<<endl;
/* receive all types of messages */
if(nowait)
rec_val = msgrcv(msgqid, &message, sizeof(message), getpid(), IPC_NOWAIT);
else rec_val = msgrcv(msgqid, &message, sizeof(message), getpid(), !IPC_NOWAIT);
if(rec_val == -1){
// perror("Error in receive");
return "none";
}
return message.mtext;
}
Then I use them at every child like so
DOWN = msgget(200, IPC_CREAT|0644);
UP = msgget(201,IPC_CREAT|0644);
And
while(1)
{
int countfail =0;
char* ask =Recieve(DOWN,true); //nowait
string asks(ask);
cout<<getpid()<<" ask= "<<asks<<endl; //This here prints either garbage (symbols and other random characters) or "none"
if(strcmp(ask,"none")!=0)
{
///////Logic for the algorithm
cout<<"*********"<<getpid()<<" In ASK "<<endl;
stringstream ss1;
ss1.str(ask);
int senderpid=0,processSize=0;
ss1>>processSize>>senderpid;
char* processRecMessage = new char[70];
///setting up what will be sent to other process
if(count+ processSize <= load)
{
count+=processSize;
strcpy(processRecMessage,"Taken");
}
else
{
strcpy(processRecMessage,"Not Taken");
}
//Another Garbage here
Send(UP,processRecMessage,senderpid);
}
else{
int nextProcess = (rand()%3) +1;
if(count + nextProcess <=load)
{
count +=nextProcess;
}
else{
for(int k = 0;k<3;k++)
{
int selectedChild = rand()%n;
cout<<getpid()<<" Selected Child no "<<selectedChild+1<<" PID="<<children[selectedChild]<<endl;
char* x = new char[70];
stringstream ss;
ss<<nextProcess;
ss<<" "<<getpid();
strcpy(x,ss.str().c_str());// x= "nextProcess pid"
cout<<x<<endl;
//// sending here also recieves garbage
Send (DOWN , x,children[selectedChild]);
//// receiving garbage
x= Recieve(UP,false);
cout<<getpid()<<" UP Value = "<<x<<endl;
if (strcmp(x,"Taken")==0){
cout<<"Process sent from "<<getpid()<<" to "<<children[selectedChild]<<endl;
break;
}
else
{
countfail++;
printf("TRAIL #%d failed\n",countfail);
}
}
if(countfail==3)
{
cout<<"Algorithm failed to allocate process.\n";
cout<<"Terminating Process "<<getpid()<<endl;
break;
}
}
}
}
So If anyone could help me with this I would be grateful
p.s.:
I delete all message queues after each fail run of the program so each time they start anew but still no use.
edit:
Adding the full code
#include <iostream>
#include <fstream>
#include <string>
#include <algorithm>
#include <math.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <string.h>
#include <map>
#include <sstream>
#include <ctime>
using namespace std;
struct msgbuff
{
long mtype;
char mtext[70];
};
void Send(key_t msgqid,char* S,long pid)
{
int send_val;
struct msgbuff message;
message.mtype = pid; /* arbitrary value */
strcpy(message.mtext,S);
cout<<"Message is "<<message.mtext<<endl;
//strcpy(message.mtext, str);
cout<<getpid()<<" Entering Send process"<<endl;
send_val = msgsnd (msgqid, &message, sizeof(message), IPC_NOWAIT);
if(send_val == -1)
perror("Errror in send");
}
char* Recieve(key_t msgqid,bool nowait)
{
int rec_val;
struct msgbuff message;
cout<<getpid()<<" Entering Receive process"<<endl;
/* receive all types of messages */
if(nowait)
rec_val = msgrcv(msgqid, &message, sizeof(message), getpid(), IPC_NOWAIT);
else rec_val = msgrcv(msgqid, &message, sizeof(message), getpid(), !IPC_NOWAIT);
if(rec_val == -1){
// perror("Error in receive");
return "none";
}
return message.mtext;
}
int main()
{
int n ;
pid_t pid;
key_t DOWN,UP;
DOWN = msgget(200, IPC_CREAT|0644);//Creates new identifier
UP = msgget(201,IPC_CREAT|0644);
int shmid;
shmid = shmget(50, 393216, IPC_CREAT|0644);
void *shmaddr;
shmaddr = shmat(shmid, (void *)0, 0);
printf("DOWN = %d\n", DOWN);
printf("UP = %d\n", UP);
cout<<"Please enter the number of machines "<<endl;
cin>>n;
int* children = new int[n];
string pids;
stringstream ss4;
ss4<<n;
string number = ss4.str();
pids+=number;
pids+=" ";
for (int i=0;i<n;i++)
{
pid = fork();
children[i]=pid;
stringstream ss3;
ss3<<pid;
string pidstr=ss3.str();
pids+=pidstr;
pids+=" ";
if (pid==0)
break;
}
if (pid==-1)
cout<<"Error in fork" <<endl;
else if (pid==0) // child
{
sleep(1);
DOWN = msgget(200, IPC_CREAT|0644);
UP = msgget(201,IPC_CREAT|0644);
//cout<<"Entering child process"<<endl;
shmid = shmget(50, 393216, IPC_CREAT|0644);
shmaddr = shmat(shmid, (void *)0, 0);
char* pidsrec = new char[100];
strcpy(pidsrec,(char*) shmaddr);
stringstream sss;
string spid(pidsrec);
sss.str(spid);
sss>>n;
children = new int[n];
for(int i =0;i<n;i++)
{
sss>>children[i];
//cout<<getpid()<<"Child #"<<i<<" = "<<children[i]<<endl;
}
srand(getpid());
int load = (rand()%10) +1; // load of operating on this system from 1-10
int count=0;
while(1)
{
int countfail =0;
char* ask =Recieve(DOWN,true); //nowait
string asks(ask);
cout<<getpid()<<" ask= "<<asks<<endl;
if(strcmp(ask,"none")!=0)
{
cout<<"*********"<<getpid()<<" In ASK "<<endl;
stringstream ss1;
ss1.str(ask);
int senderpid=0,processSize=0;
ss1>>processSize>>senderpid;
char* processRecMessage = new char[70];
if(count+ processSize <= load)
{
count+=processSize;
strcpy(processRecMessage,"Taken");
}
else
{
strcpy(processRecMessage,"Not Taken");
}
Send(UP,processRecMessage,senderpid);
}
else{
int nextProcess = (rand()%3) +1;
if(count + nextProcess <=load)
{
count +=nextProcess;
}
else{
for(int k = 0;k<3;k++)
{
int selectedChild = rand()%n;
cout<<getpid()<<" Selected Child no "<<selectedChild+1<<" PID="<<children[selectedChild]<<endl;
char* x = new char[70];
stringstream ss;
ss<<nextProcess;
ss<<" "<<getpid();
strcpy(x,ss.str().c_str());// x= "nextProcess pid"
cout<<x<<endl;
Send (DOWN , x,children[selectedChild]);
x= Recieve(UP,false);
cout<<getpid()<<" UP Value = "<<x<<endl;
if (strcmp(x,"Taken")==0){
cout<<"Process sent from "<<getpid()<<" to "<<children[selectedChild]<<endl;
break;
}
else
{
countfail++;
printf("TRAIL #%d failed\n",countfail);
}
}
if(countfail==3)
{
cout<<"Algorithm failed to allocate process.\n";
cout<<"Terminating Process "<<getpid()<<endl;
break;
}
}
}
}
}
else //parent
{
strcpy((char*) shmaddr,pids.c_str());
}
cout<<getpid()<<" GOODBYE"<<endl;
return 0;
}
I try it with any number of processes and there is always garbage received at the receive end of the message queue
In your Receive function, when you do
return message.mtext;
you are returning a pointer to data allocated locally on the stack. This area of the stack will not be valid after the function returns, and hence the dereferencing the pointer will cause undefined behavior. Also, if you use this pointer after calling another function, that area of the stack will most likely have been overwritten by the other function.
Since you're using C++, why not return std::string? It will solve this problem.
This question already has answers here:
Default constructor with empty brackets
(9 answers)
Closed 4 years ago.
I'm new to C++ and this is my first time with its classes and I was wondering, how do I call a constructor? I've read some documentation on classes in C++ and that's how I came up with what I have. The constructor calls private methods to setup the server.
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sstream>
#include <string>
#include "SimpleIni.h"
#include "MySQL.cpp"
#include <thread>
class LoginServer {
int resSocket;
MySQL mysql;
struct sockaddr_in strctAddr;
private:
void log(std::string strText, std::string strType = "INFO"){
time_t rawtime;
struct tm * timeinfo;
char buffer[50];
time(&rawtime);
timeinfo = localtime(&rawtime);
strftime(buffer, 50, "%c",timeinfo);
std::cout << "[" << buffer << "][" << strType << "] > " << strText << std::endl;
}
void error(std::string strError){
log(strError, "ERROR");
exit(1);
}
int setup(int intPort){
std::stringstream objStringStream;
objStringStream << intPort;
log("Initializing socket server");
resSocket = socket(AF_INET, SOCK_STREAM, 0);
if(resSocket < 0) error("Could not create socket.");
bzero((char *) &strctAddr, sizeof(strctAddr));
strctAddr.sin_family = AF_INET;
strctAddr.sin_addr.s_addr = INADDR_ANY;
strctAddr.sin_port = htons(intPort);
setsockopt(resSocket, SOL_SOCKET, SO_REUSEADDR, (struct sockaddr *) &strctAddr, sizeof(strctAddr));
if(bind(resSocket, (struct sockaddr *) &strctAddr, sizeof(strctAddr)) < 0)
error("Could not bind");
listen(resSocket, 5);
log("Listening for clients on " + objStringStream.str(), "FINE");
return 1;
}
int sendPacket(int resSock, std::string strData){
int intWrite;
char chBuffer[8192];
strcpy(chBuffer, strData.c_str());
log("Sending packet: " + strData, "SEND");
intWrite = write(resSock, chBuffer, strlen(chBuffer) + 1);
return intWrite;
}
std::string RandomString(int len){
srand(time(0));
std::string str = "`~!##$%^&*()-=_+[]\{]|;:'\",<.>/?0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
int pos;
int size = str.size();
while(size != len) {
pos = ((rand() % (str.size() - 1)));
str.erase (pos, 1);
}
return str;
}
void handleData(int resSock, char* strData){
char * chData;
chData = strtok(strData, "\0");
while(chData != NULL){
std::string strPacket = chData;
log("Received data: " + std::string(strPacket), "RECV");
if(strPacket.compare("<policy-file-request/>") == 0){
log("Policy request received");
sendPacket(resSock, "<cross-domain-policy><allow-access-from domain='*' to-ports='6112'/></cross-domain-policy>");
} else if(strPacket.compare("<msg t='sys'><body action='verChk' r='0'><ver v='153' /></body></msg>") == 0){
log("Version check received");
sendPacket(resSock, "<msg t='sys'><body action='apiOK' r='0'></body></msg>");
}
chData = strtok(NULL, "\0");
}
}
void handleClient(int resSock){
char chBuffer[6486];
int intRead;
for(;;){
bzero(chBuffer, 6486);
intRead = read(resSock, chBuffer, 6486);
if(chBuffer == NULL) continue;
if(intRead <= 0){
log("Client disconnected");
close(resSock);
break;
} else {
handleData(resSock, chBuffer);
}
}
}
void listenToClients(){
for(;;){
std::stringstream objStringStream;
struct sockaddr_in clntAddr;
socklen_t intClients = sizeof(clntAddr);
int resClient = accept(resSocket, (struct sockaddr *) &clntAddr, &intClients);
if(resClient < 0) log("Failed to accept client", "ERROR");
setsockopt(resClient, SOL_SOCKET, SO_REUSEADDR, (struct sockaddr *) &clntAddr, sizeof(clntAddr));
char floatIP[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &clntAddr.sin_addr, floatIP, sizeof floatIP);
objStringStream << floatIP;
log("New client connected (IP: " + objStringStream.str() + ")");
std::thread objThread(&LoginServer::handleClient, this, resClient);
objThread.detach();
}
}
public:
LoginServer();
};
LoginServer::LoginServer(){
CSimpleIniA objIniParser;
objIniParser.LoadFile("Settings.conf");
#define Host objIniParser.GetValue("Database", "Host", NULL)
#define User objIniParser.GetValue("Database", "User", NULL)
#define Pass objIniParser.GetValue("Database", "Pass", NULL)
#define Name objIniParser.GetValue("Database", "Name", NULL)
if(!mysql.connect(Host, User, Pass, Name)) error("Could not establish database connection.");
setup(6112);
listenToClients();
}
int main(){
LoginServer objLoginServer();
return 0;
}
Due to the rules of parsing in C++:
LoginServer objLoginServer();
doesn't declare an object of type LoginServer. In fact is declares a function that takes no parameters and returns a LoginServer object by value.
Instead you want to say:
LoginServer objLoginServer;
Try removing the parentheses:
LoginServer objLoginServer;
If you are curious of what's going on, search for the "most vexing parse".
The constructor should be called everytime you instantiate an object, such as the line LoginServer objLoginServer; (hint: try w/o the parenthesis) or LoginServer *objLoginServer = new LoginServer();, of course remember to call delete objLoginServer; when done with it.
There are multiple ways of calling the constructor, but I guess your specific problem is that your put brackets when calling default constructor, you need to omit them: LoginServer objLoginServer;
Such problem happens because compiler isn't able to distingush between declaring function prototype and calling default constructor. Look at A B(), out of context it may be creating object with name B of type A using default constructor, or function B returning an instance of type A.
http://www.cplusplus.com/doc/tutorial/classes/
Reading this is good start. Best of luck.
Important: Notice how if we declare a new object and we want to use its default constructor (the one without parameters), we do not include parentheses ():
CRectangle rectb; // right
CRectangle rectb(); // wrong!
I am building a client that:
Should be able to recieve information from both the server and the standart input
Should be able to recieve information from the server without asking, for example when another client sends a message.
To do so I tried using select to monitor both possible inputs.
What happens is that when a keyboard input is monitored I send a message to the client and I expect one back, so there's no problem. But when the server sends an unexpected message nothing happens, and I don't know why. Is using select() the proper way to do so? Is it even possible to use select() without listen()ing?
Here's my code (compileable):
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <cstring>
#include <arpa/inet.h>
#include <iostream>
#include <fstream>
#define MAX_CLIENT_NAME 30
#define MAX_TWIT_SIZE 140
#define NUM_OF_ARG 4
#define ERROR -1
#define GREAT_SUCCESS 0
#define OK "OK"
#define EXIT "EXIT"
using std::string;
using std::cerr;
using std::endl;
using std::cout;
string clientName;
int srverfd, numbytes, status, maxSock ;
fd_set inputFdSet; /* Socket file descriptors we want to wake
up for, using select() */
int establishConnection(char * serverAddress,char * port){
if ((srverfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket");
return ERROR;
}
struct sockaddr_in server;
server.sin_family = AF_INET;
inet_aton(serverAddress, &server.sin_addr);
server.sin_port = htons(atoi(port));
memset(&(server.sin_zero), '\0', 8);
if (connect(srverfd,(const struct sockaddr *)&server,sizeof(struct sockaddr)) == -1) {
perror("connect");
close(srverfd);
return ERROR;
}
maxSock = srverfd;
return GREAT_SUCCESS;
}
const char * getUserTweet(){
string temp;
getline(std::cin,temp);
return temp.c_str();
}
void sendMessage(string message){
if ((numbytes = send(srverfd, message.c_str(), message.length(), 0)) == -1) {
perror("sendMessage");
close(srverfd);
}
cout<<"Message sent: "<< message << endl;
return;
}
const char * getMessage(){
char buf[MAX_TWIT_SIZE];
memset(buf,'\0',MAX_TWIT_SIZE);
if ((numbytes = recv(srverfd, buf, 140, 0)) == -1) {
perror("getMessage");
close(srverfd);
}
string temp = buf;
return temp.c_str();
}
void build_select_list() {
FD_ZERO(&inputFdSet);
FD_SET(srverfd,&inputFdSet);
FD_SET(STDIN_FILENO,&inputFdSet);
if (STDIN_FILENO > maxSock)
maxSock = STDIN_FILENO;
return;
}
void readSocket(fd_set tempfd) {
const char * tweet, * inMessage;
if (FD_ISSET(srverfd,&tempfd)) {
inMessage = getMessage();
cout << inMessage << endl;
}
if (FD_ISSET(STDIN_FILENO,&tempfd)) {
tweet = getUserTweet();
sendMessage(tweet);
inMessage = getMessage();
if (strcmp(inMessage,OK) != 0) {
cout << inMessage << endl;
}
if (strcmp(inMessage,EXIT) == 0) {
return;
}
}
return;
}
int main (int argc, char *argv[] ){
int value;
bool clientON = false;
if(establishConnection(argv[2],argv[3])){
cerr << "usage: failed to make connection" << endl << "exiting..." << endl;
exit(EXIT_FAILURE);
}
cout << "Connected successfully" << endl;
sendMessage("CONNECT "+clientName); //Connect
if(strcmp(getMessage(),OK) == 0){
clientON = true;
}
while(clientON){
build_select_list();
value = select(maxSock, &inputFdSet, NULL, NULL, NULL);
if (value < 0) {
perror("select");
exit(EXIT_FAILURE);
}
if (value == 0) {
continue;
}
else {
readSocket(inputFdSet);
}
}
sendMessage("DISCONNECT");
if(strcmp(getMessage(),OK) == 0){
// do nothing
}
close(srverfd);
return 0;
}
Your select call is invalid. The first parameter must be the highest file descriptor in any of the sets, plus one.
As you have it, an event on srverfd will not "wake up" the select call (unless STDIN_FILENO was somehow less than srverfd, in which case stdin events wouldn't unlock select - but that won't happen in practice).
There are quite a few other problems with your code. (It doesn't really look like C++.)
getUserTweet is unreliable (undefined behavior - temp is destroyed as soon as the function returns, so the char* you return has disappeared by the time its caller will try to use it). Same for getMessage. To remedy that, use std::string everywhere, and only extract the char* when you call into C library functions).
readSocket needlessly copies the FD set (can be expensive).
You should really get rid of all those globals - build one or two classes to encapsulate that state and the networking functions, or something like that.