The ENet library has packets that can be send, and includes a callback function once it has finished sending that specific packet.
http://enet.bespin.org/structENetPacket.html#ad602d6b6b35ef88b2b2e080fa5c9dc3d
typedef struct _ENetPacket
{
size_t referenceCount; /**< internal use only */
enet_uint32 flags; /**< bitwise-or of ENetPacketFlag constants */
enet_uint8 * data; /**< allocated data for packet */
size_t dataLength; /**< length of data */
ENetPacketFreeCallback freeCallback; /**< function to be called when the packet is no longer in use */
void * userData; /**< application private data, may be freely modified */
} ENetPacket;
The callback itself:
typedef void (ENET_CALLBACK * ENetPacketFreeCallback) (struct _ENetPacket *);
Now I want to create a class that holds the host used to send those packets, and also to keep track how many packets were successfully sent.
template<typename T>
class Sender {
public:
explicit Sender() { }
void send(T* data, int32_t length)
{
ENetPacket* packet = enet_packet_create(data, length, ENET_PACKET_FLAG_RELIABLE);
packet->freeCallback = callbackPacket;
enet_host_broadcast(m_server, 0, packet);
}
void callbackPacket(ENetPacket* packet)
{
--m_counter_packets_active;
}
};
This does not compile: Error C3867 Sender<int32_t>::callbackPacket': non-standard syntax; use '&' to create a pointer to member
When I try
packet->freeCallback = &this->callbackPacket;
I get Error C2440 '=': cannot convert from 'void (Sender<int32_t>::* )(ENetPacket *)' to 'ENetPacketFreeCallback'
I just don't understand what the proper code would be for the packet calling the Sender object's method when the packet is done with.
Okay, this is pretty common. First, you can't call a non-static member method this way, not directly. Pain in the ass.
But that callback structure has a userData field. And that's what we're going to use.
void send(T* data, int32_t length) {
ENetPacket* packet = enet_packet_create(data, length, ENET_PACKET_FLAG_RELIABLE);
packet->freeCallback = &Sender::myStaticMethod;
packet->userData = this; // This is part of the magic
enet_host_broadcast(m_server, 0, packet);
}
static void myStaticMethod(ENetPacket * packet) {
Sender * sender = static_cast<Sender *>(packet->userData);
sender-> callbackPacket(packet);
}
In other words -- store this as your user data. Use a static method for the callback, and have him turn it around to call your real callback.
Related
could you please help in following.
I have callback function definition in the 3rd lib header:
#ifdef __cplusplus
extern "C" {
#endif
typedef int (*SOCK_CLBK)(int, short, unsigned char*, int, ...);
#ifdef __cplusplus
}
#endif
And I define my callback in the following way:
header file:
template<typename T>
int ReadTCP(int socket, short code, unsigned char* msg, int received, T a);
cpp file:
template<>
int ReadTCP(int socket, short code, unsigned char* msg, int received, int a)
{
return 0;
}
and register my callback in the code:
server->registerCallback(port, (SOCK_CLBK)(ReadTCP<int>),maxTCPsize);
This works fine, and the callback is triggered when needed.
The problem is, the "int a" contains random values every time.
how to register a callback and pass my own specific value for example 100000, that will occur in the callback in "a"?
Something like
server->registerCallback(port, (SOCK_CLBK)(&std::bind(ReadTCP<int>,_1,_2,_3,_4, 100000),maxTCPsize);
but this does not work (triggers runtime exception).
What I am doing wrong?
lib header:
#include "CSocket.h"
#ifndef WIN32
#include <pthread.h>
#else
#include <windows.h>
#include <WinSock.h>
#endif
#define CPP_TCP_MAX_CLIENTS 17
#define CPP_TCP_MAX_SIZE 1500 //In accordance with MTU definitoins
class DLLCPP_API CSERVER {
public:
/**
* default constructor
*/
CSERVER ();
/**
* default destructor
*/
virtual ~CSERVER ();
/**! \fn int Create(unsigned int uiPort, bool bClbk);
* \brief creates singleton socket listener
* creates singleton socket listener, which is invoked within dedicated thread
* if bClbk is true, otherwise within the main thread.
* \param uiPort socket listener port
* \param fnClbk call-back function address. if not NULL then callback mode of operation. otherwise normal.
* \return 0 on success, error id otherwise.
*/
int registerCallback(unsigned int uiPort, SOCK_CLBK fnClbk=NULL, int iMsgMaxSize=512)throw (CMException);
….
…
Send()…
….
...
protected:
#ifndef WIN32
friend void* _fnTCPClbkThread(void *); //call-back argument for pthread_create within RunClbkThread.
#else
friend DWORD WINAPI _fnTCPClbkThread( LPVOID lpParam );
#endif
/**! \fn int IsPending(int iSock, bool& bFail)
* \brief check pending connection on a non blocking socket
* actuall checks for errors and whether or not connection is ready for write operation.
* \param iSock client socket connection to check.
* \return: OK (0) if iSock ready for write operation or ERROR otherwise (still pending for instance)
*/
int IsPending(int iSock)throw (CMException);
int RunClbkThread();
int CreateClbk()throw (CMException);
void ClbkThread();
private:
typedef void (CSERVER::*PCLBKTHREAD)(void *);
PCLBKTHREAD _pThreadClbk;
int _iServerSock;
int _iSock;
SOCK_CLBK _fnClbk;
unsigned int _uiPort;
int _iAddrLen;
bool _bClbkThreadAlive;
int _iClientConnectionsArr[CPP_TCP_MAX_CLIENTS];
int _iMsgMaxSize;
struct sockaddr_in _saddConnect ;
#ifdef WIN32
WSADATA m_wsaData;
HANDLE _thread;
#else
pthread_t _thread;
#endif
};
Look at function registerCallback
From which I can deduct that the class does not store any user data to be passed later as a callback parameter... Why do they have variadic template then - no idea.
First, your code with ReadTCP function template is incorrect. SOCK_CLBK is a type of a function pointer that has an ellipsis at the end of its argument list, which is different from int (or any other type) that ReadTCP<int> has. The compiler does not fail to compile because you explicitly convert the pointer to ReadTCP<int> to SOCK_CLBK, but the call fails at runtime (you either receive a random value in the int a argument or crash).
Your second piece of code with std::bind is also wrong because std::bind returns a function object, not a pointer to function. The function object has operator(), so it can be called like a function, but it cannot be converted to a function pointer (for one, because the object also contains data, like the arguments you bound).
You must define a function that accepts a variable number of arguments (i.e. has an ellipsis at the end of its argument list) and pass that function as the callback. In that function, you can process the passed arguments and possibly invoke other specialized functions in your code, like ReadTCP.
int ReadTCPCallback(int socket, short code, unsigned char* msg, int received, ...)
{
std::va_list args;
va_start(args, received);
// Use variable arguments here, using va_arg. Consult with the API
// documentation to know what arguments are expected here. For the sake
// of this example, let's assume an int argument is passed.
int n = va_arg(args, int);
int res = ReadTCP(socket, code, msg, received, n);
// Always call va_end before returning once you're done with va_list
va_end(args);
return res;
}
If you want to use function objects with this API then you will have to find a way to pass a pointer to data through the third party library to the callback. That data will contain the bound parameters and other state pertinent to the call. Refer to the documentation of that third party library as to how to pass user's data to the callback.
If the API does not support passing user's data (which would make it a rather poorly designed API), you could associate the data with some handle returned by the API that corresponds to your state. For example, you could maintain a global std::map to map the socket file descriptor (int) to a pointer to your data related to that socket or connection.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
I don't understand why the callback lambda passed to c_style_callback does not access to the correct values of callback and key. How to get these 2 to be available from the lambda?
I tried with explicit copy [callback=callback, key=key], didn't help.
This is a C++ wrapper implementation of a C method called subscribe.
I think the following code covers my issue, let me know if anything else needed.
Wrapper, the issue is located here. Please check the comments at the end of the lines:
std::function<void()> AWS::subscribe(const std::string &topic, std::function<void(const std::string&)> callback, QoS qos) {
ESP_LOGI(TAG, "subscribe: %s", topic.c_str());
std::string key("Test...");
auto task = c_style_callback(
[=] (AWS_IoT_Client *pClient, char *topicName, uint16_t topicNameLen, IoT_Publish_Message_Params *params) {
std::string json;
json.assign((char *)params->payload, (size_t)params->payloadLen);
ESP_LOGI(TAG, "subscribe cb payload=%s", json.c_str()); // works
ESP_LOGI(TAG, "key '%s'", key.c_str()); // undefined behaviour
callback(json);// error, exit
}
);
m_error = ::aws_iot_mqtt_subscribe(
&m_client,
key.c_str(),
key.length(),
qos,
task.get_callback<AWS_IoT_Client*, char*, uint16_t, IoT_Publish_Message_Params*>(),
task.get_pvoid()
);
if (m_error != SUCCESS) {
ESP_LOGD(TAG, "subscribe: error=%d", m_error);
return nullptr;
}
return [=] () {
ESP_LOGI(TAG, "unsubscribe %s", key.c_str()); // works
callback(key); // works
};
} // subscribe
c_style_callback utility function:
template<class F>
struct c_style_callback_t {
F f;
template<class...Args>
static void(*get_callback())(Args..., void*) {
return [](Args...args, void* fptr)->void {
(*static_cast<F*>(fptr))(std::forward<Args>(args)...);
};
}
void* get_pvoid() {
return std::addressof(f);
}
};
template<class F>
c_style_callback_t< std::decay_t<F> >
c_style_callback( F&& f ) { return {std::forward<F>(f)}; }
Main task where the subscribe wrapper is being called - this is only for giving context to the example, how I try to use the C++ wrapper of subscribe:
{
...
aws->subscribe(
topic,
[] (const std::string &json) -> void {
ESP_LOGI(TAG, "got json: %s", json.c_str());
}
);
...
}
Update:
More about aws_iot_mqtt_subscribe:
/**
* #brief Subscribe to an MQTT topic.
*
* Called to send a subscribe message to the broker requesting a subscription
* to an MQTT topic.
* #note Call is blocking. The call returns after the receipt of the SUBACK control packet.
*
* #param pClient Reference to the IoT Client
* #param pTopicName Topic Name to publish to
* #param topicNameLen Length of the topic name
* #param pApplicationHandler_t Reference to the handler function for this subscription
* #param pApplicationHandlerData Data to be passed as argument to the application handler callback
*
* #return An IoT Error Type defining successful/failed subscription
*/
IoT_Error_t aws_iot_mqtt_subscribe(AWS_IoT_Client *pClient, const char *pTopicName, uint16_t topicNameLen,
QoS qos, pApplicationHandler_t pApplicationHandler, void *pApplicationHandlerData);
I assume aws_iot_mqtt_subscribe stores its arguments for latter reference - to call, in response to some event at some later point in time, the function passed as its next-to-last argument, with the pointer passed as its last argument.
The pointer obtained with task.get_pvoid() points to a data member of task. In turn, task is a local variable - it's destroyed when subscribe returns, together with its data member, whereupon that pointer becomes dangling.
Later, the function manufactured by c_style_callback_t::get_callback receives that no-longer-valid pointer and attempts to dereference it. Thereby the program exhibits undefined behavior, by way of accessing an object after its lifetime has ended.
This is my PER_IO_CONTEXT structure (i stored them in singly linked list):
typedef struct _PER_IO_CONTEXT
{
SLIST_ENTRY ItemEntry;
WSAOVERLAPPED Overlapped;
WSABUF wsabuf;
/* some other data*/
} PER_IO_CONTEXT, *PPER_IO_CONTEXT;
and below is WSAsend , that use the list for getting WSAOVERLAPPED structure:
...
PSLIST_HEADER pListHead;
...
PSLIST_ENTRY pListEntry = InterlockedPopEntrySList(pListHead);
PPER_IO_CONTEXT ovl = (PPER_IO_CONTEXT)pListEntry;
WSASend(pTmp1->Socket,..., &(ovl->Overlapped), NULL);
and the last part when GQCS gets notification:
LPWSAOVERLAPPED lpOverlapped = NULL;
PPER_IO_CONTEXT lpIOContext = NULL;
....
GetQueuedCompletionStatus(..... (LPOVERLAPPED *)&lpOverlapped, INFINITE);
lpIOContext = (PPER_IO_CONTEXT)lpOverlapped;
lpIOContext->wsabuf // this fail
As you can see following cast lpIOContext =(PPER_IO_CONTEXT)lpOverlapped doesn't work because WSAsend was provided with wsaoverlapped - the second member of PER_IO_CONTEXT structure, so dereferences such as lpIOContext-> can't be used in this case.
There is a way to deal with this situation?
To get the address of the corresponding PER_IO_CONTEXT struct you can use this:
lpIOContext = CONTAINING_RECORD(lpOverlapped, PER_IO_CONTEXT, Overlapped);
CONTAINING_RECORD is a macro defined in VC\crt\src\collections.h in such a way:
#define CONTAINING_RECORD(address, type, field) \
((type *)((char *)(address) - (ULONG_PTR)(&((type *)0)->field)))
More information: http://msdn.microsoft.com/en-us/library/windows/hardware/ff542043%28v=vs.85%29.aspx
I'm not sure whether there's a supported mechanism to convert a pointer to a member of a struct to a pointer to the struct. You could cast everything to BYTE * and do the arithmetic, which would work in practice, but depending on your needs it might be cleaner to reorganize to avoid the necessity:
typedef struct _PER_IO_CONTEXT
{
WSAOVERLAPPED Overlapped;
WSABUF wsabuf;
/* some other data*/
} PER_IO_CONTEXT, *PPER_IO_CONTEXT;
typedef struct _PER_IO_CONTEXT_LIST_ITEM
{
SLIST_ENTRY ItemEntry;
PER_IO_CONTEXT Item;
} PER_IO_CONTEXT_LIST_ITEM, *PPER_IO_CONTEXT_LIST_ITEM;
I am using libusb to interact with a usb device. I have created a Class and a member function will receive the input from the device and process it. I am using Asynchronous api. Now the libusb_fill_bulk_transfer() function call throws a compilation error:
void MyDeviceClass::on_connectButton_clicked()
{
int r; //for return values
ssize_t cnt; //holding number of devices in list
r = libusb_init(&ctx); //initialize the library for the session we just declared
if(r < 0) {
qDebug()<<"Init Error "<<r<<endl; //there was an error
return;
}
...
...
...
libusb_fill_bulk_transfer( transfer_in, dev_handle, USB_ENDPOINT_IN,
inBuffer, LEN_IN_BUFFER,readDataFromBuffer,NULL,0);
libusb_submit_transfer(transfer_in);
QtConcurrent::run (this,&MyDeviceClass::eventThread);
}
The compiler suggests using &MyDeviceClass::readDataFromBuffer as a function pointer but that still throws an error. I tried using static members, and even static non-member functions but all in vain. Please help me in passing the callback to this function. I am using Qt, and probably won't like to use boost libraries.
Please note that libusb_fill_bulk_transfer(...) is invoked inside a member function of MyDeviceClass.
I made the member function static and prototype needed to be modified:
static void LIBUSB_CALL readDataFromBuffer(struct libusb_transfer *);
what is the compile error when you use a non member function?
Edit: this should be LIBUSB_CALL:
void LIBUSB_CALL BulkTransferCallback(struct libusb_transfer *transfer) {
// This assumes that you set transfer::user_data to be a pointer to
// an instance of the MyDeviceClass class.
MyDeviceClass* mdc = reinterpret_cast<MyDeviceClass*>(transfer->user_data);
mdc->onBulkTransferCallback(transfer);
}
Then when you set the pointer, use:
transfer.callback = &BulkTransferCallback;
As you answered yourself, actually it should be __stdcall which is defined by LIBUSB_CALL. Their documentation should include this in the function pointer typedef to remove the ambiguity.
The lib_usb api defines the function libusb_fill_bulk_transfer with:
static void libusb_fill_bulk_transfer (struct libusb_transfer *transfer, libusb_device_handle *dev_handle, unsigned char endpoint, unsigned char *buffer, int length, libusb_transfer_cb_fn callback, void *user_data, unsigned int timeout)
It is possible to add a static class function to your class and call the non-static member-function
of the class within this static function.
You this Object would be at the place of void *user_data.
In the static class function you would have to cast the member of
transfer->user_data correctly to your class.
I am an absolute beginner to C++ and Qt.
I am broadcasting different data via TCP using Qt. The process of sending and retrieving data works fine but I have problems on interpreting the data on the receivers side.
The data is represented in different structs which have in common that they have a commandId and a state. The rest could be anything like an error message, a filename or something else. This code is not written on my own and I am not allowed to change it (e.g: define and implement a common interfaces.)
typedef struct
{
uint8_t commandId;
State state;
//special data
QString errorMessage;
} Command1;
typedef struct
{
uint8_t commandId;
State state;
//special data
uint8_t amountSensors;
} Command2;
enum State {
STATID_PAUSE = 50000
STATID_RECORD = 50001
STATID_PLAY = 50002
STATID_ERROR = 50003
}
The sender is converting a struct into a QByteArray this way:
Command1 example;
example.commandId = 134;
example.state = STATID_ERROR;
char *p_Char;
p_char = reinterpret_cast<char*>(&example);
QByteArray qba(p_char, sizeof(p_char));
Now I have to write a receiver, but the receiver doesn't know what he gets (Command1, Command2 or something else). He would be able to interpret if he could read out the commandId and the state.
At this moment I am able to read out the commandId like this:
commandId = static_cast<uint8_t>(qba[0]);
but how could I read out the State which is an enum?
State values will take the size of an int. which means to access it you will do :
State state = (State) (*( reinterpret_cast<const int*>(qba.constData()+1)) );
First you reinterpret the const char pointer as an const int pointer, then you deference it (which means you obtain the value), and you cast this value as an State.
In order to access other variables you will start at index 1 + sizeof(int) = 1+ sizeof(State)
See this thread about the size of an enum.