How to pass a member function pointer to libusb? - c++

I'm writing a simple library that uses libusb to connect to my custom hardware that sends signals to a host device every 50ms. It's designed to provide a simple abstraction layer so that users are not bothered with libusb at all. I need to pass a pointer to a non-static class member function to libusb_fill_bulk_transfer. I.e. I need to have a separate callback for every instance of MyDevice without exposing libusb logic to my users.
The basic design is:
init the lib
int mylib_init(){
libusb_init(&context);
}
find all compatible devices
int mylib_get_valid_devices(vector devs){
//...
libusb_device **devs1;
int countAll = libusb_get_device_list(context, &devs1);
//... fill devs
}
int mylib_print_device_info(MyDevice* dev);
connect to as many devices as the user likes
int mylib_init_device(MyDevice* dev){
libusb_open(dev->device, &dev->dev_handle);
// check for kernel driver & remove if needed
libusb_claim_interface(dev->dev_handle, 0);
//...
}
set up callbacks for incoming data to all instances of connected devices
int mylib_start_transmission_async(MyDevice* dev, MyLibCallbackIn user_cb, unsigned char* buffer_in, int bufferSize){
libusb_control_transfer(dev->dev_handle, p1, p2, p3, p4, p5, p6, p7);
// .. rest of libusb_control_transfer -s
//start device:
int actual;
unsigned char startSig = 0b00110111;
libusb_bulk_transfer(dev->dev_handle, (1 | LIBUSB_ENDPOINT_OUT), &tosend, 1, &actual, 100);
dev->user_callback = user_cb;
dev->buffer_in = buffer_in;
dev->bufferSize = bufferSize;
//setup transfer
dev->transfer_in = libusb_alloc_transfer(0);
libusb_fill_bulk_transfer(dev->transfer_in, dev->dev_handle, LIBUSB_ENDPOINT_IN, dev->buffer_in,dev->bufferSize, cb_in, NULL, 0);
libusb_submit_transfer(dev->transfer_in);
}
disconnect when finished
int mylib_disconnect_device(MyDevice* device);
exit the lib
int mylib_exit();
MyDevice is defined as:
typedef int (*MyLibdCallbackIn)(unsigned char* buffer, int length);
class MyDevice{
unsigned char* buffer_in;
unsigned char* buffer_out;
libusb_device* device = nullptr;
libusb_device_handle* dev_handle = nullptr;
struct libusb_transfer* transfer_in = nullptr;
struct libusb_transfer* transfer_out = nullptr;
//this obviously wouldn't work because libusb doesn't accept it as a param:
void LIBUSB_CALL cb_in(struct libusb_transfer* transfer);
MyLibCallbackIn user_callback;
void run();
//...
}
and cb_in is defined as:
void LIBUSB_CALL MyDevice::cb_in(libusb_transfer* transfer){
int r = libusb_submit_transfer(this->transfer_in);
callback_in(transfer->buffer, transfered);
}
I can't pass MyDevice::cb_in to libusb_fill_bulk_transfer because the function pointer types are incompatible. In the same time I don't want my users to have to write a callback function with libusb_transfer* as a parameter (exposing to libusb) to pass directly to libusb_fill_bulk_transfer.
EDIT:
I tried with
void LIBUSB_CALL callback_wrapper(struct libusb_transfer* transfer){
MyDevice* dev = reinterpret_cast<MyDevice*>(transfer->user_data);
dev->cb_in(transfer);
}
but get Sementation fault (Core dumped) error

As per Max Langhof and Sam Varshavchik's comments the solution is to pass the instance of MyDevice to libusb_fill_bulk_transfer . So:
int mylib_start_transmission_async(MyDevice* dev, MyLibCallbackIn user_cb, unsigned char* buffer_in, int bufferSize){
//...
// setup transfer:
dev->transfer_in = libusb_alloc_transfer(0);
libusb_fill_bulk_transfer(dev->transfer_in, dev->dev_handle, LIBUSB_ENDPOINT_IN, dev->buffer_in,dev->bufferSize, cb_in, dev, 0);
libusb_submit_transfer(dev->transfer_in); ^^^
}
and then use the callback_wrapper as in the Edit. Thanks!

Related

What is the best of passing taskHandle to another class in freeRTOS with pointers

OK it was not wise to ask question with some assumptions. Here is the detailed version.
I have 2 task, 1 for MQTT and 1 for LED. I want to read a data over MQTT and take an action to turn on an LED.
Here is my task declarations:
void taskMqtt(void *param);
xTaskHandle handleTaskMqtt;
void taskLed(void *param);
xTaskHandle handleTaskLed;
Here is the task creation part
status = xTaskCreate(taskMqtt, "taskMqtt", 4096, NULL, 2, handleTaskMqtt);
configASSERT(status == pdPASS);
ESP_LOGI(TAG, "taskMqtt CREATED");
status = xTaskCreate(taskLed, "taskLed", 4096, NULL, 2, &handleTaskLed);
configASSERT(status == pdPASS);
ESP_LOGI(TAG, "taskLed CREATED");
I created my Mqtt object like this and it works fine.
Mqtt mqtt("192.168.137.212", move(uptrWifi), handleTaskLed);
Here is the Mqtt.h file to observe class declaration
class Mqtt
{
private:
std::unique_ptr<Wifi> uptrWifi;
static xTaskHandle handlerTask;
static const char *subscribeTopic;
static const char *publishTopic;
static esp_mqtt_client_config_t _mqttCfg;
static esp_mqtt_client_handle_t _clientCfg;
static void mqttEventHandler(void *arg, esp_event_base_t eventBase, int32_t eventId, void *eventData);
public:
Mqtt(const char *brokerIp, std::unique_ptr<Wifi> uptrToWifi, xTaskHandle taskToNotify);
void init(void);
void sendDataOverMqtt(std::string title, int data);
void sendDataOverMqtt(std::string title, int data, std::string pubTopic);
static void getDataOverMqtt(char *data, int dataLen);
void setTopics(std::string subTopic, std::string pubTopic);
};
In Mqtt.cpp file I defined
xTaskHandle Mqtt::handlerTask;
and constructor
Mqtt::Mqtt(const char *brokerIp, std::unique_ptr<Wifi> uptrToWifi,
xTaskHandle taskToNotify)
{
_mqttCfg.host = brokerIp;
ESP_LOGI("MQTT_H", "MQTT BROKER IP SET\n");
uptrWifi = move(uptrToWifi);
handlerTask = taskToNotify;
}
and here is my function for read data and forward to the LED task.
void Mqtt::getDataOverMqtt(char *data, int dataLen)
{
static uint32_t valueToSend = 1;
if (strncmp(data, "Led ON", 6) == 0)
{
ESP_LOGI(TAG, "\nDATA COMES \n");
if (handlerTask != NULL)
{
xTaskNotify(handlerTask, valueToSend, eSetValueWithOverwrite);
}
else
{
printf("\nNULL pointer\n");
fflush(stdout);
}
printf("\nCMD=%.*s\n\n", dataLen, data);
}
else if (strncmp(data, "Led OFF", 7) == 0)
{
printf("\nCMD=%.*s\n\n", dataLen, data);
}
}
And here is the LED task
void taskLed(void *param)
{
uint32_t ulNotifiedValue = false;
while (1)
{
ESP_LOGI(TAG, "LED WAITING");
xTaskNotifyWait(0, ULONG_MAX, &ulNotifiedValue, portMAX_DELAY);
ESP_LOGI(TAG, "\n NOTIFICATION \n");
ESP_LOGI(TAG, "LED TASK RUNNING");
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
When I run the code and sent Led ON command, I can see the logs
LED WAITING (from taskLED definition)
DATA COMES (from getDataOverMqtt definition)
Null Pointer (from getDataOverMqtt definition)
After that I was hoping to see on the logs
NOTIFICATION (from taskLED defition)
////////////////////////////////////// ORIGINAL POST BEFORE EDITS IS BELOW
I am trying to learn FreeRtos and C++.
I need to pass taskHandle to another class and want to use them for notify function. What is the best way to do that?
In taskControl.cpp file I created tasks as below.
void task1(void *param);
TaskHandle_t handleTask1;
void task2(void *param);
TaskHandle_t handleTask2;
status = xTaskCreate(task1, "task1", 4096, NULL, 2, &handleTask1);
configASSERT(status == pdPASS);
ESP_LOGI(TAG, "task1 CREATED");
status = xTaskCreate(task2, "task2", 4096, NULL, 2, &handleTask2);
configASSERT(status == pdPASS);
ESP_LOGI(TAG, "task2 CREATED");
I thought I can pass handleTask2 into another class via constructor
M m(&handleTask2);
In classM.h file, M is declared as below
class M
{
private:
static TaskHandle_t *handlerTask;
public:
M(TaskHandle_t *taskToNotify)
{
handlerTask = taskToNotify;
}
};
And I tried to use handlerTask as below in classM.cpp file.
xTaskNotify(&handlerTask, valueToSend, eSetValueWithoutOverwrite);
What am I missing? What is the correct way to do this kind of thing?
Sorry for if my question is not clear.

C++ variable changed during interrupt resets after interrupt

I'm trying to use a flag to see if an event has finished.
Via the debugger, I have seen that the interrupt triggers correctly and does set the value of transmitCompleteI2c to 1. When I return to the if statement which checks whether or not the flag has been set to 1, it has been reset to 0.
The only 2 locations where i alter the value of transmitCompleteI2c are after the if statement and in the interrupt routine.
I'm running the following bits of code. The declaration of transmitCompleteI2c is done in the header file of the class. fireEvent() is a member function of the class I2c.
volatile uint8_t transmitCompleteI2c;
void I2c::foo() {
if (transmitCompleteI2c) {
transmitCompleteI2c = 0;
// trigger event which sets transmitComplete back to 0 when done
fireEvent();
}
}
void I2c::sendHandler(XIic *InstancePtr) {
transmitCompleteI2c = 1;
}
After some extensive digging, it turned out that the address the interrupt routine writes a transmitCompleteI2c to is not the same as the variable in the class. Even after renaming the variable, it is still happening. Below are the header file and source code of my class.
Header file:
#define SLAVE_ADDRESS 0xA0/2
#define SEND_COUNT 16
#define RECEIVE_COUNT 16
#define IIC_INTR_ID XPAR_FABRIC_AXI_IIC_0_IIC2INTC_IRPT_INTR
#define IIC_DEVICE_ID XPAR_AXI_IIC_0_DEVICE_ID
#define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID
class I2c{
private:
void sendHandler(void* InstancePtr, int);
void receiveHandler(XIic* InstancePtr, int);
void statusHandler(XIic* InstancePtr, int);
XIic_Config* configPtr;
const XScuGic& intcInterrupt;
XIic iicDevice;
int status;
uint8_t writeBuffer[SEND_COUNT];
uint8_t readBuffer[RECEIVE_COUNT];
volatile uint8_t transmitCompleteI2c, receiveComplete;
volatile bool test;
public:
I2c() : intcInterrupt{IntcInstance} {};
uint8_t initialize();
int writeData(u16 ByteCount);
int readData(u8 *BufferPtr, u16 ByteCount);
};
Implementation:
Initialization function:
uint8_t I2c::initialize() {
// init driver
configPtr = XIic_LookupConfig(IIC_DEVICE_ID);
XIic_CfgInitialize(&iicDevice, configPtr, configPtr->BaseAddress);
//init interrupt system
XScuGic_SetPriorityTriggerType((XScuGic*) &intcInterrupt, IIC_INTR_ID, 0xA0, 0x3);
status = XScuGic_Connect((XScuGic*) &intcInterrupt, IIC_INTR_ID, (Xil_ExceptionHandler) XIic_InterruptHandler, &iicDevice);
XScuGic_Enable((XScuGic*) &intcInterrupt, IIC_INTR_ID);
Xil_ExceptionInit();
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_IRQ_INT, (Xil_ExceptionHandler) XScuGic_InterruptHandler, &IntcInstance);
Xil_ExceptionEnable();
// set transmit flag
transmitCompleteI2c = true;
xil_printf("%08x\n", &transmitCompleteI2c);
// attach interrupts to i2c device
XIic_SetSendHandler(&iicDevice, &iicDevice, (XIic_Handler) (&I2c::sendHandler));
XIic_SetRecvHandler(&iicDevice, &iicDevice, (XIic_Handler) &I2c::receiveHandler);
XIic_SetStatusHandler(&iicDevice, &iicDevice, (XIic_StatusHandler) &I2c::statusHandler);
// set slave address
status = XIic_SetAddress(&iicDevice, XII_ADDR_TO_SEND_TYPE, SLAVE_ADDRESS);
// start device
status = XIic_Start(&iicDevice);
if (status != XST_SUCCESS) {
return XST_FAILURE;
}
return 0;
}
Write data function:
int I2c::writeData(u16 ByteCount) {
xil_printf("%08x\n", &transmitCompleteI2c);
/*
* Set flag
*/
transmitCompleteI2c = false;
/*
* Send the data
*/
status = XIic_MasterSend(&iicDevice, &writeBuffer[0], 6);
if (status != XST_SUCCESS) {
xil_printf("%d\n", status);
return XST_FAILURE;
}
return XST_SUCCESS;
}
Interrupt routine:
void I2c::sendHandler(void *InstancePtr, int byteCount) {
transmitCompleteI2c = true;
xil_printf("%08x\n", &transmitCompleteI2c);
}
"...it should all be in the same class"
but transmitCompleteI2c isn't a static member, so it has to be the same object, not just the same class. Every instance of I2c gets its own copy of each non-static data member.
You can just make it static if you know only one copy is required (this effectively makes it a global, although still only accessible by I2c) - but don't forget it needs a single non-inline definition.
Alternatively, you need to figure out what I2c objects exist, and where they're created. You can implement all constructor and assignment operator overloads with logging (or to set breakpoints) if you're having trouble figuring out where they get created.

Memory Access error using STK and the FMVoices class

I'm trying to use the STK from Stanford to do some realtime wavetable synthesis. I'm using the FMVoices instrument class https://ccrma.stanford.edu/software/stk/classstk_1_1FMVoices.html
and trying to use it in a callback routine defined below.
int tick( void *outputBuffer, void *inputBuffer, unsigned int nBufferFrames,
double streamTime, RtAudioStreamStatus status, void *dataPointer )
{
FMVoices *FM = (FMVoices *) dataPointer;
register StkFloat *samples = (StkFloat *) outputBuffer;
for ( unsigned int i=0; i<nBufferFrames; i++ )
*samples++ = FM->tick();
return 0;
}
The issue, I think, is with the type of that last parameter. I'm getting a runtime error : "0xC0000005: Access violation executing location 0x000000001." Now, this is the way that the callback is supposed to be written for other STK instruments like Clarinet or even the FileLoop class, but there's something funky about FMVoices. The object is passed to openStream (which handles platform specific realtime output) as a pointer to void. The callback is called automatically when the system's audio buffer is full. A code snippet that implements this and DOES work for other instruments is shown below:
int main()
{
// Set the global sample rate before creating class instances.
Stk::setSampleRate( 44100.0 );
RtAudio dac;
Instrmnt * instrument_FM;
int nFrames = 10000;
try {
instrument_FM = new FMVoices;
}
catch ( StkError & ) {
goto cleanup;
}
instrument_FM->setFrequency(440.0);
// Figure out how many bytes in an StkFloat and setup the RtAudio stream.
RtAudio::StreamParameters parameters;
parameters.deviceId = dac.getDefaultOutputDevice();
parameters.nChannels = 1;
RtAudioFormat format = ( sizeof(StkFloat) == 8 ) ? RTAUDIO_FLOAT64 : RTAUDIO_FLOAT32;
unsigned int bufferFrames = RT_BUFFER_SIZE;
try {
dac.openStream( &parameters, NULL, format, (unsigned int)Stk::sampleRate(), &bufferFrames, &tick, (void *)&instrument_FM);
}
catch ( RtError &error ) {
error.printMessage();
Sleep(1000);
goto cleanup;
}
The size of nFrames does not seem to have an effect. It just seemed to me that these types of errors usually come from referencing a pointer to void.
The problem is you are taking the address of a pointer, and passing it into openStream.
// pointer to instrument
Instrmnt * instrument_FM;
// snip ...
// &instrument_FM is a pointer to a pointer! i.e. Instrmnt **
dac.openStream( &parameters, /* other params */, (void *)&instrument_FM)
The quickest solution is to just get rid of the & in that line.
Now some comments on C++, and some more fixes to your code. The code looks like a mixture of C and Java, and opens up a lot of pitfalls to fall into, one of which led to your problem.
There is no need for dynamically allocating FMVoices . Use the stack just like you did for RtAudio dac.
No need to worry about pointers, and deleteing the memory you allocated
Therefore no memory leaks.
Just write FMVoices instrument_FM;
There is no need to do try/catch in most cases for cleanup since C++ has destructors that trigger at the end of scope, and propagate the error.
If you only use the stack, there is no need to worry about delete and having cleanup operations
Don't ever use goto in C++, it's really not needed. (unlike in C, where it could be used for cleanup).
There are destructors and RAII for that.
Use C++ casts which are more fine-grained, such as static_cast<> and reinterpret_cast<>, instead of C-style casts
See this article for an explanation.
Here's the revised code:
int main()
{
// Set the global sample rate before creating class instances.
Stk::setSampleRate( 44100.0 );
RtAudio dac;
FMVoices instrument_FM;
instrument_FM.setFrequency(440.0);
// Figure out how many bytes in an StkFloat and setup the RtAudio stream.
RtAudio::StreamParameters parameters;
parameters.deviceId = dac.getDefaultOutputDevice();
parameters.nChannels = 1;
RtAudioFormat format = ( sizeof(StkFloat) == 8 ) ? RTAUDIO_FLOAT64 : RTAUDIO_FLOAT32;
unsigned int bufferFrames = RT_BUFFER_SIZE;
// didn't get rid of this try since you want to print the error message.
try {
// note here i need the ampersand &, because instrument_FM is on the stack
dac.openStream( &parameters, NULL, format, static_cast<unsigned int>(Stk::sampleRate()), &bufferFrames, &tick, reinterpret_cast<void*>(&instrument_FM));
}
catch ( RtError& error ) {
error.printMessage();
}
}

Error occured when sending message through Google Play Game Service with Cocos2d-x

I'm developing a multiplayer game with Google Play Services and Cocos2d-x. I already set up communication between Java and C++ using JNI, and can run processes like Sign-in, Create room, Invitation... Everything is fine until I need to send some struct to another players. When receive data from other, an error has occurred.
Here's the structs:
typedef enum
{
MESSAGE_TYPE_PING = -1,
MESSAGE_TYPE_PING_BACK = 0,
MESSAGE_TYPE_RTT = 3
} MESSAGE_TYPE;
typedef struct
{
MESSAGE_TYPE messType;
} MESSAGE;
typedef struct
{
MESSAGE mess;
timeval sendTime;
const char* text;
} PING_MESSAGE;
And in this code snippet I convert struct and send it to another players:
void MyClass::sendData()
{
// Send package
PING_MESSAGE ping;
ping.mess.messType = MESSAGE_TYPE_PING;
ping.sendTime = startTime;
ping.text = "Ohhhhhh";
char byte[sizeof(ping)];
memcpy(byte, &ping, sizeof(ping));
GCHelper::sendReliableRealTimeMessage(&byte[0]);
}
// In GCHelper's implementation
void GCHelper::sendReliableRealTimeMessage(const char* byteMess)
{
// Convert char* to jbyteArray
jbyteArray bArray = env->NewByteArray(16); //env is a static JNIEnv* in this class; 16 since my PING_MESSAGE struct is 16 bytes in size;
env->SetByteArrayRegion(bArray,0,16,(jbyte*)byteMess);
// Make Java call
env->CallStaticVoidMethod(classID, methodID, bArray);
methodInfo.env->DeleteLocalRef(bArray);
methodInfo.env->DeleteLocalRef(classID);
}
Now, Java code take responsibility to send the byte array to participants in room. At receiver side, I'm continue send received data to C++. And error occured here when I convert jbyteArray back to struct:
void Java_package_name_TestMulti_nativeOnRealTimeMessageReceived(JNIEnv *env, jobject thiz, jbyteArray receivedMess)
{
CCLOG("Called from java");
jboolean isCopy;
jbyte * pCData = env->GetByteArrayElements(receivedMess, &isCopy);
jsize size = env->GetArrayLength(receivedMess);
const char* sd = (const char*)pCData;
PING_MESSAGE result;
memcpy(&result, sd, sizeof(result));
CCLOG("TEST size: %d", size); // This log out: "TEST size: 16"
CCLOG("TEST type: %d", result.mess.messType); // This log out: "TEST type: -1"
CCLOG("TEST text: %s", result.text); // AND ERROR!!!!!!!
cocos2d::CCByteArray* data = cocos2d::CCByteArray::createWithData(sd);
cocos2d::CCNotificationCenter::sharedNotificationCenter()->postNotification("onRealTimeMessageReceived", data);
if(isCopy)
{
env->ReleaseByteArrayElements(receivedMess,pCData,JNI_ABORT);
}
}
I'm not understand here. If I don't send byte array to another players yet send that array back to C++ by calling nativeOnRealTimeMessageReceived() method from Java side, it runs fine and logs correctly. It's mean that with the same byte[] package converted from char* in C++, if I just pass it back to C++, it's correct, but if I send it through Google Play Game Services, it goes wrong. What does this mean?

WinSock2 IOCP WSARecv GetQueuedCompletionStatus: data (automatically) ends up in char*buffer, not WSABUF.buf...why?

While debugging, when WSARecv is called, I supply the function with the address of the PerIoData->WSABUF structure. This should assign the sent data to the WSABUF.buf char* array, which it seems to. When The worker thread loops back to the waiting GetQueuedCompletionStatus, it seems to somehow (magically) send that data to PerIoData.Buffer (char* array). So essentially, the PerIoData.Buffer and PerIoData.WSABUF.buf both equal the same char* array. When I remove the PerIoData.Buffer from the PER_IO_DATA Struct (and all references to it), the GetQueuedCompletionStaus never returns when the client sends data though i know the WSABUF.buf should be populated with data.
The pertinent information:
I'm implementing the Completion Port Model found in "Network Programming for Microsoft Windows" (p.157). Though the examples in that book left much to be independently discovered, my code works fine now.
In the while loop of the ServerWorkerThread: GetQueuedCompletionStatus , called first, receives per_handle_data, and per_io_data
per_io_data struct is as such:
struct _PER_IO_DATA{ //in the interests of an efficient question, i'm omitting the
//constructor/destructor code
public:
OVERLAPPED Overlapped;
WSABUF DataBuf;
char myBuffer[BUFFER_LENGTH];
int BufferLen;
int OperationType;
};
typedef _PER_IO_DATA PER_IO_DATA;
typedef _PER_IO_DATA *PPER_IO_DATA;
My GetQueuedCompletionStatus function is called like so:
ret = GetQueuedCompletionStatus(CompletionPort,
&BytesTransferred,
(LPDWORD)&PerHandleData,
(LPOVERLAPPED *)&PerIoData,
INFINITE);
My WSARecv Function is called like so:
WSARecv(PerHandleData->Socket, &(PerIoData->DataBuf), 1, NULL, &Flags, ((LPWSAOVERLAPPED)&PerIoData->Overlapped), NULL);
//i know casting the Overlapped structure as LPWSAOVERLAPPED is unnecessary, but I was tweaking the
//code when I didn't fully understand the problems I was having.
My problem is that I never explicitly assign anything to the PerIoData->Buffer yet it seems to always get populated with the sent data. I'm lead to believe GetQueuedCompletionStatus "knows" to send this data to that PerIoData->Buffer though it's expecting a pointer to a LPOVERLAPPED structure (to which i pass my PerIoData struct instance containing the Buffer char array in question). It's really bugging me... Maybe it's not behaving like I'm thinking it is, but the only place I can see the PerIoData->Buffer being populated is from within the GetQueuedCompletionStatus method. If that's not the case, then PerIoData->Buffer seems to be populated from nowhere? I've scoured MSDN and google for days. I'll continue looking and if I find the answer I'll post an update. Please Help? Thanks in advance!
*Note: I would've created the tags WSABUF and GetQueuedCompletionStatus, but this is my first post.
--EDIT: I'm posting the structs and worker thread, leaving out all other unrelated code.--
You'll notice that _PER_IO_DATA::DataBuf.buf is allocated memory, then zeroed out. Not pointing to the myBuffer array....
#include "stdafx.h"
#define SEND_POSTED 1
#define RECV_POSTED 2
#define BUFFER_LENGTH 1024
HANDLE CompletionPort;
SOCKADDR_IN serverAddress, *clientAddress;
SOCKET listener, client;
unsigned short port = 5000;
SYSTEM_INFO SystemInfo;
int i;
struct _PER_HANDLE_DATA{//Per handle data structure
SOCKET Socket;
SOCKADDR_STORAGE Address;
_PER_HANDLE_DATA(){
Socket = 0;
ZeroMemory(&Address, sizeof(SOCKADDR_STORAGE));
}
~_PER_HANDLE_DATA(){
Socket = NULL;
ZeroMemory(&Address, sizeof(SOCKADDR_STORAGE));
}
};typedef _PER_HANDLE_DATA PER_HANDLE_DATA;typedef _PER_HANDLE_DATA *PPER_HANDLE_DATA;
struct _PER_IO_DATA{
public:
OVERLAPPED Overlapped;
WSABUF DataBuf;
char myBuffer[BUFFER_LENGTH];
int BufferLen;
int OperationType;
_PER_IO_DATA(){
OperationType = 0;
DataBuf.len = BUFFER_LENGTH;
DataBuf.buf = (char*)malloc(BUFFER_LENGTH+1);
BufferLen = BUFFER_LENGTH;
ZeroMemory(DataBuf.buf, (sizeof(BUFFER_LENGTH+1)));
ZeroMemory(&myBuffer, (sizeof(char)*BUFFER_LENGTH));
SecureZeroMemory((PVOID)&Overlapped, sizeof(Overlapped));
}
~_PER_IO_DATA(){
free(&DataBuf.buf);
}
};
typedef _PER_IO_DATA PER_IO_DATA;
typedef _PER_IO_DATA *PPER_IO_DATA;
unsigned _stdcall ServerWorkerThread(LPVOID CompletionPortID);
int _tmain(int argc, _TCHAR* argv[])
{
/*
INITIALIZE WINSOCK AND COMPLETION PORT, AND ACCEPT CONNECTIONS
*/
}
unsigned _stdcall ServerWorkerThread(LPVOID CompletionPortID){
printf("ServerWorkerThread(%d) Working\n", GetCurrentThreadId());
HANDLE CompletionPort = (HANDLE) CompletionPortID;
DWORD BytesTransferred;
PPER_HANDLE_DATA PerHandleData = new PER_HANDLE_DATA;
PPER_IO_DATA PerIoData = new PER_IO_DATA;
DWORD SendBytes = 0, RecvBytes = 0;
DWORD Flags;
BOOL ret;
Sleep(2000);
while(TRUE){
ret = GetQueuedCompletionStatus(CompletionPort,
&BytesTransferred,
(LPDWORD)&PerHandleData,
(LPOVERLAPPED *)&PerIoData,
INFINITE);
//printf("\n\nBytesTransferred: %d\n\n", BytesTransferred);
if(BytesTransferred == 0 && (PerIoData->OperationType == RECV_POSTED || PerIoData->OperationType == SEND_POSTED)){
closesocket(PerHandleData->Socket);
GlobalFree(PerHandleData);
GlobalFree(PerIoData);
continue;
}
if(PerIoData->OperationType == RECV_POSTED){
//output received data
if(!strcmp(PerIoData->DataBuf.buf, "Disconnect") || !strcmp(PerIoData->DataBuf.buf, "disconnect")){
printf("Disconnecting...\n");
if(!shutdown(PerHandleData->Socket, SD_BOTH)){
closesocket(PerHandleData->Socket);
delete(PerHandleData);
}
}else{
printf("RECV_POSTED: %s\n", PerIoData->DataBuf.buf);
}
}
Flags = 0;
SecureZeroMemory((PVOID)&PerIoData->Overlapped, sizeof(WSAOVERLAPPED));
PerIoData->DataBuf.len = BUFFER_LENGTH;
//***************************************************************************
//Even though the following is commented out, PerIoData->DataBuf.buf
//is still being populated and so is PerIoData-myBuffer
//So why is myBuffer being populated with data when DataBuf.buf is not pointing to it??
//PerIoData->DataBuf.buf = PerIoData->myBuffer;
//Also, if you comment out all references of myBuffer, GetQueuedCompletionStatus(),
//will never return if myBuffer doesn't exist...how does it seem to be 'aware' of myBuffer?
//***************************************************************************
PerIoData->OperationType = RECV_POSTED;
WSARecv(PerHandleData->Socket, &(PerIoData->DataBuf), 1, NULL, &Flags, ((LPWSAOVERLAPPED)&PerIoData->Overlapped), NULL);
}
return 0;
}