Undefined reference to Class::Object - c++

I have a class that handles the serial comms for my program called "serial.h and serial.cpp". It has the following constructor:
#include "serial.h"
serialib LS;
serial::serial(void)
{
int Ret;
Ret = LS.Open(DEVICE_PORT, BAUD_RATE);
if (Ret != 1)
{
printf("Serial port open FAILED!\n");
}
else
{
printf("Serial port successfully opened...");
}
}
I want to call this class in another and use its methods, so I do the following in a class called dataHandler.cpp:
#include "dataHandler.h"
#include "serial.h"
using namespace opendnp3;
serial ser;
dataHandler::dataHandler(void)
{
}
dataHandler::~dataHandler(void)
{
}
int dataHandler::sendRestartCommand()
{
int Ret;
char buffer[128];
RestartInfo ri;
std::string strW = "GetRestartInfo\r\n";
std::string strR;
Ret = ser.Write(strW);
int bytes;
Ret = ser.Read(strR);
if ((strR.compare("201-OK [GetRestartInfo]\r\n")) != 0)
{
printf ("Wrong response from device to restart message.\n");
return 0;
}
Ret = ser.Read(strR);
std::string s_bytes = strR.substr(4,3);
std::stringstream ss(s_bytes);
if (!(ss >> bytes))
bytes = 0;
Ret = ser.Read(buffer);
writeSettings(ri);
return 1;
}
However, when I do this, I get the following error:
dataHandler.o: In function `dataHandler::sendRestartCommand()':
dataHandler.cpp:(.text+0x31c): undefined reference to `dataHandler::ser'
collect2: error: ld returned 1 exit status
My original plan was to create a serial object in my .h file like:
public:
serial ser;
But that did not work either...
I'm a bit stumped as to how to do this, I know I'm probably missing something small.
Any advice?

What I ended up doing is creating an constructor with arguments:
serial::serial(std::string devPort, int baud)
{
int Ret;
const char * devP = devPort.c_str();
Ret = LS.Open(devP, baud);
if (Ret != 1)
{
printf("Serial port open FAILED!\n");
}
else
{
printf("Serial port successfully opened...");
}
}
Then I called it like so:
static serial ser(DEVICE_PORT, BAUD_RATE);
Works fine now. Thus, I am calling the serial object as a global variable!

Related

Communicate with Advantech ADAM-6050 through a c++ program

I'm trying to develop a program in c++ that allows reading and setting the logical value of the input and output of the adam 6050.
A practical example: I want the code to read the logical value of DI4 and if it is 1, it sets the logical value of DO4 to 1.
What library do I need to include?
What code do I have to write?
I tried to compile this example code from Adam .net class library samples:
// Adam50XXDIO.cpp : Defines the entry point for the application.
//
#include "stdafx.h"
#include <windows.h>
#include <stdio.h>
#include "ADSDIO.h"
#include <string.h>
//////////////////////////////////////////////
//Take ADAM-5056 for example
//Slot : 0
//Reverse channel 0 value
USHORT iSlot = 0;
USHORT iChannel = 0;
//////////////////////////////////////////////
int ADV_SUCCESS = 0;
LONG myprocHandle;
int OpenLib()
{
myprocHandle = NULL;
//OpenDeviceLib
if(ADAMDrvOpen(&myprocHandle) == ADV_SUCCESS)
return ADV_SUCCESS;
else
return -99;
}
void CloseLib()
{
//Close device library
if(myprocHandle!=NULL)
ADAMDrvClose(&myprocHandle);
}
int main(int argc, char* argv[])
{
int iRet;
ULONG dVal;
bool bValue = false;
bool setValue = true;
printf("/*** Adam50XXDIO Sample ***/ \n");
iRet = OpenLib();
if(iRet == ADV_SUCCESS)
{
//Get dio module values
if((DI_GetValues(myprocHandle, iSlot, &dVal)) == ADV_SUCCESS)
{
printf("GetValues: %lx\n", dVal);
bValue = ((dVal & (0x00000001<<iChannel)) > 0);
if(bValue)
{
printf("Ch%d:True\n", iChannel);
setValue = false;
}
else
{
printf("Ch%d:False\n", iChannel);
setValue = true;
}
//Set DO value
if((DO_SetValue(myprocHandle, iSlot, iChannel, setValue) == ADV_SUCCESS))
{
printf("SetValue done.\n", dVal);
//Check value
if((DI_GetValues(myprocHandle, iSlot, &dVal)) == ADV_SUCCESS)
{
printf("GetValues: %lx\n", dVal);
bValue = ((dVal & (0x00000001<<iChannel)) > 0);
if(bValue)
printf("Ch%d:True\n", iChannel);
else
printf("Ch%d:False\n", iChannel);
}
}
else
printf("SetValue() failed.");
}
else
printf("GetValues() failed.");
}
else
printf("OpenLib(%d) failed.\n", iRet);
CloseLib();
printf("/*** END ***/ \n");
getchar();
return 0;
}
But I get this message:
C:\Program Files (x86)\Dev-Cpp\MinGW64\x86_64-w64-mingw32\bin\ld.exe
cannot open output file C:\Program Files (x86)\Advantech\AdamApax.NET Class Library\Sample Code\ADAM\Win32\CPlusPlus\ADAM-PAC-Sample\Adam50XX_DIO\Adam50XX_DIO.exe: Permission denied
Then I changed the path, and now pop these messages:
C:\Users\JOOLOP~1\AppData\Local\Temp\cc5WBolj.o Adam50XX_DIO.cpp:(.text+0x18): undefined reference to `ADAMDrvOpen'
C:\Users\JOOLOP~1\AppData\Local\Temp\cc5WBolj.o Adam50XX_DIO.cpp:(.text+0x51): undefined reference to `ADAMDrvClose'
C:\Users\JOOLOP~1\AppData\Local\Temp\cc5WBolj.o Adam50XX_DIO.cpp:(.text+0xb3): undefined reference to `DI_GetValues'
C:\Users\JOOLOP~1\AppData\Local\Temp\cc5WBolj.o Adam50XX_DIO.cpp:(.text+0x17a): undefined reference to `DO_SetValue'
C:\Users\JOOLOP~1\AppData\Local\Temp\cc5WBolj.o Adam50XX_DIO.cpp:(.text+0x1c5): undefined reference to `DI_GetValues'
C:\practice\Adam50XX_DIO\collect2.exe [Error] ld returned 1 exit status
What I can do now?

Trying to create a Gatt Client application for Windows C++ that doesn't fail when connection established

I am using the Windows api Gatt Client BLE for C++, my goal is to connect two devices (but in this case I will try just one) and keep reading and writing data constantly without closing the device at any time. All my devices have one specific service that contains a read characteristic and a write one.
HOW TO TEST:
Use Visual studio 2017 (v141) with Windows SDK Version: 10.0.18362.0, create a new console (.exe) solution, change the Platform in Project -> Properties to Win32 and go to Project -> Properties -> C/C++ -> Command Line and add these options:
/std:c++17 /await
Then copy the following code in a file (you can copy all in the same .cpp file):
#pragma once
#include <SDKDDKVer.h>
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <iostream>
#include <queue>
#include <map>
#include <mutex>
#include <condition_variable>
#include <string>
#include <winrt/Windows.Foundation.Collections.h>
#include <winrt/Windows.Web.Syndication.h>
#include "winrt/Windows.Devices.Bluetooth.h"
#include "winrt/Windows.Devices.Bluetooth.GenericAttributeProfile.h"
#include "winrt/Windows.Devices.Enumeration.h"
#include "winrt/Windows.Storage.Streams.h"
#pragma comment(lib, "windowsapp")
using namespace std;
using namespace winrt;
using namespace Windows::Foundation;
using namespace Windows::Foundation::Collections;
using namespace Windows::Web::Syndication;
using namespace Windows::Devices::Bluetooth;
using namespace Windows::Devices::Bluetooth::GenericAttributeProfile;
using namespace Windows::Devices::Enumeration;
using namespace Windows::Storage::Streams;
#pragma region STRUCS AND ENUMS
#define LOG_ERROR(e) cout << e << endl;
union to_guid
{
uint8_t buf[16];
guid guid;
};
const uint8_t BYTE_ORDER[] = { 3, 2, 1, 0, 5, 4, 7, 6, 8, 9, 10, 11, 12, 13, 14, 15 };
guid make_guid(const wchar_t* value)
{
to_guid to_guid;
memset(&to_guid, 0, sizeof(to_guid));
int offset = 0;
for (unsigned int i = 0; i < wcslen(value); i++) {
if (value[i] >= '0' && value[i] <= '9')
{
uint8_t digit = value[i] - '0';
to_guid.buf[BYTE_ORDER[offset / 2]] += offset % 2 == 0 ? digit << 4 : digit;
offset++;
}
else if (value[i] >= 'A' && value[i] <= 'F')
{
uint8_t digit = 10 + value[i] - 'A';
to_guid.buf[BYTE_ORDER[offset / 2]] += offset % 2 == 0 ? digit << 4 : digit;
offset++;
}
else if (value[i] >= 'a' && value[i] <= 'f')
{
uint8_t digit = 10 + value[i] - 'a';
to_guid.buf[BYTE_ORDER[offset / 2]] += offset % 2 == 0 ? digit << 4 : digit;
offset++;
}
else
{
// skip char
}
}
return to_guid.guid;
}
mutex subscribeLock;
condition_variable subscribeSignal;
mutex _mutexWrite;
condition_variable signalWrite;
struct DeviceCacheEntry {
BluetoothLEDevice device = nullptr;
GattDeviceService service = nullptr;
GattCharacteristic characteristic = nullptr;
};
map<wstring, DeviceCacheEntry> cache;
struct Subscription {
GattCharacteristic::ValueChanged_revoker revoker;
};
struct BLEDeviceData {
wstring id;
wstring name;
bool isConnectable = false;
Subscription* subscription = NULL;
};
vector<BLEDeviceData> deviceList{};
mutex deviceListLock;
condition_variable deviceListSignal;
#pragma endregion
#pragma region CACHE FUNCTIONS
//Call this function to get a device from cache or async if it wasn't found
IAsyncOperation<BluetoothLEDevice> getDevice(wchar_t* deviceId) {
if (cache.count(wstring(deviceId)) && cache[wstring(deviceId)].device)
co_return cache[wstring(deviceId)].device;
BluetoothLEDevice result = co_await BluetoothLEDevice::FromIdAsync(deviceId);
if (result == nullptr) {
LOG_ERROR("Failed to connect to device.")
co_return nullptr;
}
else {
DeviceCacheEntry d;
d.device = result;
if (!cache.count(wstring(deviceId))) {
cache.insert({ wstring(deviceId), d });
}
else {
cache[wstring(deviceId)] = d;
}
co_return cache[wstring(deviceId)].device;
}
}
//Call this function to get a service from cache or async if it wasn't found
IAsyncOperation<GattDeviceService> getService(wchar_t* deviceId, wchar_t* serviceId) {
if (cache.count(wstring(deviceId)) && cache[wstring(deviceId)].service)
co_return cache[wstring(deviceId)].service;
auto device = co_await getDevice(deviceId);
if (device == nullptr)
co_return nullptr;
GattDeviceServicesResult result = co_await device.GetGattServicesForUuidAsync(make_guid(serviceId), BluetoothCacheMode::Cached);
if (result.Status() != GattCommunicationStatus::Success) {
LOG_ERROR("Failed getting services. Status: " << (int)result.Status())
co_return nullptr;
}
else if (result.Services().Size() == 0) {
LOG_ERROR("No service found with uuid")
co_return nullptr;
}
else {
if (cache.count(wstring(deviceId))) {
cache[wstring(deviceId)].service = result.Services().GetAt(0);
}
co_return cache[wstring(deviceId)].service;
}
}
//Call this function to get a characteristic from cache or async if it wasn't found
IAsyncOperation<GattCharacteristic> getCharacteristic(wchar_t* deviceId, wchar_t* serviceId, wchar_t* characteristicId) {
try {
if (cache.count(wstring(deviceId)) && cache[wstring(deviceId)].characteristic)
co_return cache[wstring(deviceId)].characteristic;
auto service = co_await getService(deviceId, serviceId);
if (service == nullptr)
co_return nullptr;
GattCharacteristicsResult result = co_await service.GetCharacteristicsForUuidAsync(make_guid(characteristicId), BluetoothCacheMode::Cached);
if (result.Status() != GattCommunicationStatus::Success) {
LOG_ERROR("Error scanning characteristics from service. Status: " << (int)result.Status())
co_return nullptr;
}
else if (result.Characteristics().Size() == 0) {
LOG_ERROR("No characteristic found with uuid")
co_return nullptr;
}
else {
if (cache.count(wstring(deviceId))) {
cache[wstring(deviceId)].characteristic = result.Characteristics().GetAt(0);
}
co_return cache[wstring(deviceId)].characteristic;
}
}
catch (...) {
LOG_ERROR("Exception while trying to get characteristic")
}
}
#pragma endregion
#pragma region SCAN DEVICES FUNCTIONS
DeviceWatcher deviceWatcher{ nullptr };
mutex deviceWatcherLock;
DeviceWatcher::Added_revoker deviceWatcherAddedRevoker;
DeviceWatcher::Updated_revoker deviceWatcherUpdatedRevoker;
DeviceWatcher::Removed_revoker deviceWatcherRemovedRevoker;
DeviceWatcher::EnumerationCompleted_revoker deviceWatcherCompletedRevoker;
struct TestBLE {
static void ScanDevices();
static void StopDeviceScan();
};
//This function would be called when a new BLE device is detected
void DeviceWatcher_Added(DeviceWatcher sender, DeviceInformation deviceInfo) {
BLEDeviceData deviceData;
deviceData.id = wstring(deviceInfo.Id().c_str());
deviceData.name = wstring(deviceInfo.Name().c_str());
if (deviceInfo.Properties().HasKey(L"System.Devices.Aep.Bluetooth.Le.IsConnectable")) {
deviceData.isConnectable = unbox_value<bool>(deviceInfo.Properties().Lookup(L"System.Devices.Aep.Bluetooth.Le.IsConnectable"));
}
deviceList.push_back(deviceData);
}
//This function would be called when an existing BLE device is updated
void DeviceWatcher_Updated(DeviceWatcher sender, DeviceInformationUpdate deviceInfoUpdate) {
wstring deviceData = wstring(deviceInfoUpdate.Id().c_str());
for (int i = 0; i < deviceList.size(); i++) {
if (deviceList[i].id == deviceData) {
if (deviceInfoUpdate.Properties().HasKey(L"System.Devices.Aep.Bluetooth.Le.IsConnectable")) {
deviceList[i].isConnectable = unbox_value<bool>(deviceInfoUpdate.Properties().Lookup(L"System.Devices.Aep.Bluetooth.Le.IsConnectable"));
}
break;
}
}
}
void DeviceWatcher_Removed(DeviceWatcher sender, DeviceInformationUpdate deviceInfoUpdate) {
}
void DeviceWatcher_EnumerationCompleted(DeviceWatcher sender, IInspectable const&) {
TestBLE::StopDeviceScan();
TestBLE::ScanDevices();
}
//Call this function to scan async all BLE devices
void TestBLE::ScanDevices() {
try {
lock_guard lock(deviceWatcherLock);
IVector<hstring> requestedProperties = single_threaded_vector<hstring>({ L"System.Devices.Aep.DeviceAddress", L"System.Devices.Aep.IsConnected", L"System.Devices.Aep.Bluetooth.Le.IsConnectable" });
hstring aqsFilter = L"(System.Devices.Aep.ProtocolId:=\"{bb7bb05e-5972-42b5-94fc-76eaa7084d49}\")"; // list Bluetooth LE devices
deviceWatcher = DeviceInformation::CreateWatcher(aqsFilter, requestedProperties, DeviceInformationKind::AssociationEndpoint);
deviceWatcherAddedRevoker = deviceWatcher.Added(auto_revoke, &DeviceWatcher_Added);
deviceWatcherUpdatedRevoker = deviceWatcher.Updated(auto_revoke, &DeviceWatcher_Updated);
deviceWatcherRemovedRevoker = deviceWatcher.Removed(auto_revoke, &DeviceWatcher_Removed);
deviceWatcherCompletedRevoker = deviceWatcher.EnumerationCompleted(auto_revoke, &DeviceWatcher_EnumerationCompleted);
deviceWatcher.Start();
}
catch (exception e) {
LOG_ERROR(e.what())
}
}
void TestBLE::StopDeviceScan() {
scoped_lock lock(deviceListLock, deviceWatcherLock);
if (deviceWatcher != nullptr) {
deviceWatcherAddedRevoker.revoke();
deviceWatcherUpdatedRevoker.revoke();
deviceWatcherRemovedRevoker.revoke();
deviceWatcherCompletedRevoker.revoke();
deviceWatcher.Stop();
deviceWatcher = nullptr;
}
deviceListSignal.notify_one();
}
#pragma endregion
#pragma region SUBSCRIBE/READ FUNCTIONS
//On this function you can read all data from the specified characteristic
void Characteristic_ValueChanged(GattCharacteristic const& characteristic, GattValueChangedEventArgs args)
{
LOG_ERROR("Read data from device: " << to_string(characteristic.Service().Device().DeviceId()) << ", data size: " << args.CharacteristicValue().Length())
}
//Function used to subscribe async to the specific device
fire_and_forget SubscribeCharacteristicAsync(wstring deviceId, wstring serviceId, wstring characteristicId, bool* result) {
try {
auto characteristic = co_await getCharacteristic(&deviceId[0], &serviceId[0], &characteristicId[0]);
if (characteristic != nullptr) {
auto status = co_await characteristic.WriteClientCharacteristicConfigurationDescriptorAsync(GattClientCharacteristicConfigurationDescriptorValue::Notify);
if (status != GattCommunicationStatus::Success) {
LOG_ERROR("Error subscribing to characteristic. Status: " << (int)status)
}
else {
for (int i = 0; i < deviceList.size(); i++) {
if (deviceList[i].id == deviceId) {
deviceList[i].subscription = new Subscription();
deviceList[i].subscription->revoker = characteristic.ValueChanged(auto_revoke, &Characteristic_ValueChanged);
break;
}
}
if (result != 0)
*result = true;
}
}
}
catch (hresult_error& ex)
{
LOG_ERROR("SubscribeCharacteristicAsync error: " << to_string(ex.message().c_str()))
for (int i = 0; i < deviceList.size(); i++) {
if (deviceList[i].id == deviceId && deviceList[i].subscription) {
delete deviceList[i].subscription;
deviceList[i].subscription = NULL;
break;
}
}
}
subscribeSignal.notify_one();
}
//Call this function to subscribe to the specific device so you can read data from it
bool SubscribeCharacteristic(wstring deviceId, wstring serviceId, wstring characteristicId) {
unique_lock<mutex> lock(subscribeLock);
bool result = false;
SubscribeCharacteristicAsync(deviceId, serviceId, characteristicId, &result);
subscribeSignal.wait(lock);
return result;
}
#pragma endregion
#pragma region WRITE FUNCTIONS
//Function used to send data async to the specific device
fire_and_forget SendDataAsync(wchar_t* deviceId, wchar_t* serviceId, wchar_t* characteristicId, uint8_t * data, uint16_t size, bool* result) {
try {
auto characteristic = co_await getCharacteristic(deviceId, serviceId, characteristicId);
if (characteristic != nullptr) {
DataWriter writer;
writer.WriteBytes(array_view<uint8_t const>(data, data + size));
IBuffer buffer = writer.DetachBuffer();
auto status = co_await characteristic.WriteValueAsync(buffer, GattWriteOption::WriteWithoutResponse);
if (status != GattCommunicationStatus::Success) {
LOG_ERROR("Error writing value to characteristic. Status: " << (int)status)
}
else if (result != 0) {
LOG_ERROR("Data written succesfully")
*result = true;
}
}
}
catch (hresult_error& ex)
{
LOG_ERROR("SendDataAsync error: " << to_string(ex.message().c_str()))
for (int i = 0; i < deviceList.size(); i++) {
if (deviceList[i].id == deviceId && deviceList[i].subscription) {
delete deviceList[i].subscription;
deviceList[i].subscription = NULL;
break;
}
}
}
signalWrite.notify_one();
}
//Call this function to write data on the device
bool SendData(wchar_t* deviceId, wchar_t* serviceId, wchar_t* characteristicId, uint8_t * data, uint16_t size) {
bool result = false;
unique_lock<mutex> lock(_mutexWrite);
// copy data to stack so that caller can free its memory in non-blocking mode
SendDataAsync(deviceId, serviceId, characteristicId, data, size, &result);
signalWrite.wait(lock);
return result;
}
#pragma endregion
Finally copy this main function (it can be copied at the end of the same file):
int main() {
//The mac of the device that will be tested
wstring deviceMac = L"00:11:22:33:44:55";
//These are the serviceUUID, readCharacteristicUUID and writeCharacteristicUUID as I said previously
wstring serviceUUID = L"{47918888-5555-2222-1111-000000000000}";
wstring readUUID = L"{31a28888-5555-2222-1111-00000000cede}";
wstring writeUUID = L"{f55a8888-5555-222-1111-00000000957a}";
//I think it is the mac of the BLE USB Dongle because it is in all device id when they are enumerated
wstring otherMac = L"24:4b:fe:3a:1a:ba";
//The device Id that we are looking for
wstring deviceId = L"BluetoothLE#BluetoothLE" + otherMac;
deviceId += L"-";
deviceId += deviceMac;
//To start scanning just call this function
TestBLE::ScanDevices();
//Data to be written all the time
const uint16_t dataSize = 3;
uint8_t data [dataSize]= { 0x0, 0xff, 0xff };
//Wait time in miliseconds between each write
chrono::milliseconds waitTime = 100ms;
//It will be executed always
while (true) {
//Then every device and their info updated would be in this vector
for (int i = 0; i < deviceList.size(); i++) {
//If the device is connectable we will try to connect if we aren't subscribed yet or send information
if (deviceList[i].isConnectable) {
//We can do here the following code to know the structure of the device id (if otherMac variable is the BLE USB dongle mac or not)
//cout << to_string(deviceList[i].id) << endl;
if (!deviceList[i].subscription && deviceList[i].id == deviceId) {
SubscribeCharacteristic(deviceList[i].id, serviceUUID, readUUID);
}
else if (deviceList[i].subscription) {
SendData(&deviceId[0], &serviceUUID[0], &writeUUID[0], data, dataSize);
}
}
}
this_thread::sleep_for(waitTime);
}
}
You will need a BLE device with a service that contains a reading and a writing characteristic, set the corresponding values ​​in the deviceMac, serviceUUID, readUUID and writeUUID variables, you can also modify the bytes that are going to be written in data and dataSize, and the time between writes in waitTime. The otherMac variable should be the mac of the BLE USB dongle device but I recommend that you check it by getting the id of the devices from deviceList inside the for loop.
When you run this code on some rare times you will get the error "Failed getting services. Status:" with result 1 (unreachable) or 3 (access denied) and in the rest of the cases it will be reading the device data correctly and after a while it will give the error "SendDataAsync error: Object has been disposed" and from there it will continue giving "SubscribeCharacteristicAsync error: Object has been disposed", so at some point it will stop being able to read data of the device. What could be the reason?
EDIT 1:
It is quite strange because with this code the data is never written correctly (the "Data written succesfully" message is not displayed) but in my completed code I have always been able to write the data, maybe the problem is still the same and it is related to the characteristic stored in the "map <wstring, DeviceCacheEntry> cache" since perhaps it is stored as a copy and when trying to access it at some point it is disposed by Windows (since it is a copy of the original that is stored in the cache) and gives the error as described in the answer to this post in the point named "UPDATE 2 - SOME WEIRDNESS"

Attempting to read from a file descriptor into a buffer fails when accessed outside the object

I've never worked with file descriptors and I'm a bit confused about some of this behavior. I'm also fairly new to concurrency and the documentation for these functions is fairly lacking.
My MessageReciever constructor opens a pty. Upon calling the Receive message, as I understand it, the code forks. The master should hit the next conditional and return from the function. I know this is happening because the code in main doesn't block. The child reads in the file descriptor, converts it to a string and saves it in a vector. Currently I'm printing the buffer directly but I also can print the last element in the vector and it acts basically the same. However, when I attempt to access this outside the class, in main, I get nothing. I thought this might be some type of concurrency problem, but I'm not really sure how to address.
CODE
#include <sys/time.h>
#include <sys/types.h>
#include <sys/select.h>
#include <stdio.h>
#include <util.h>
#include <unistd.h>
#include <sys/wait.h>
#include <string>
#include <vector>
class MessageReceiver
{
public:
MessageReceiver()
{
openpty(&master, &slave, NULL, NULL, NULL);
}
~MessageReceiver()
{
close(master);
close(slave);
}
void receiveMessage()
{
pid_t pid = fork();
printf("PID = %d\n",pid);
if(pid > 0)
{
fd_set rfds;
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 0;
char buf[4097];
ssize_t size;
size_t count = 0;
while (1)
{
if (waitpid(pid, NULL, WNOHANG) == pid)
{
break;
}
FD_ZERO(&rfds);
FD_SET(master, &rfds);
if (select(master + 1, &rfds, NULL, NULL, &tv))
{
size = read(master, buf, 4096);
printf("Buffer = %s", buf);
messageBuffer.push_back(std::string(buf));
buf[size] = '\0';
count += size;
}
}
}
}
std::string getLastMessage()
{
std::string s;
if(messageBuffer.size() > 0)
{
s = messageBuffer.back();
}
else
{
s = "NULL";
}
return s;
}
private:
int master, slave;
std::vector<std::string> messageBuffer;
};
int main()
{
MessageReceiver m;
m.receiveMessage();
std::string lastMessage = m.getLastMessage();
printf("Printing message buffer:\n");
for(;;)
{
if(m.getLastMessage() != lastMessage)
{
printf("Message: %s\n", m.getLastMessage().c_str());
}
}
return 0;
}
Initial output
PID = 8170
PID = 0
Printing message buffer:
Additional output when hello is echoed to the pty
Buffer = hello

Issues with converting a constant char array to an unsigned char pointer

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.

how to get int value for pointer

I have a socket wraper and it has the RecvData that returns an int:
int RecvData(void* buff, int bufferSize){
return recv(hSocket, reinterpret_cast<char*>(buff), bufferSize, 0);
}
also I have this WebServer function ReceiveLine to get an HTTP request:
static string ReceiveLine()
{
Socket* sock;
std::string ret;
while (1) {
char r;
switch(sock->SendData(&r,sizeof(r))) {
case 0: // not connected anymore;
return "";
case -1:
if (errno == EAGAIN) {
return ret;
} else {
// not connected anymore
return "";
}
}
ret += r;
if (r == '\n') return ret;
}
return ret;
}
The problem is that in the switch statement I have this error:
Socket* sock; pointer to incomplete class type is not allowed
An incomplete class means you have declared the Socket class but not defined it. Maybe it's been forward declared but you never included the .h file containing the definition.