I have imported a DLL into my program, and there are a few functions as follows:
typedef int (*FEEDQ_CALLBACK) ( long nSD, long nQtype, long nNumber ) ;
typedef int (*CALLDISP_CALLBACK) ( AODFeedDispositionBase* CallDisposition );
typedef int (*SERVICE_STATUS_CALLBACK) ( long nSD, long nStatus ) ;
typedef int (*AUTH_SERVICE_CALLBACK) ( long nSD, char* sSDesc, long nSType ) ;
typedef int (*INBOUND_ABANDON_CALLBACK) ( long nSD, DCCProInboundDisposition* inbounCall ) ;
typedef int (*SESSION_STATUS_CALLBACK) ( long lTypeId, long lStatus ) ;
extern "C"
{
//Methods
AODFEEDAPI short Initialize(const char * sTenantName, const char * sUserID, const char * sPassword, AUTH_SERVICE_CALLBACK pAuthSrvFunc, SERVICE_STATUS_CALLBACK pSrvStatFunc, FEEDQ_CALLBACK pFeedQFunc, CALLDISP_CALLBACK pCallDispFunc, INBOUND_ABANDON_CALLBACK pInboundCallFunc, SESSION_STATUS_CALLBACK pSessionStatFunc = 0);
AODFEEDAPI short Close();
AODFEEDAPI short StopService( long nServiceID, long nQueueAction );
AODFEEDAPI short StartService(long nServiceID);
}
I want to call the Initialize() function in the DLL. I'm confused as to how I should pass the parameters in the callback function.
You don't pass parameters to the callbacks. The callbacks are functions you define in your own code and then give to the DLL so it can call them when needed, passing parameters to you. For example:
int MyFeedQCallback( long nSD, long nQtype, long nNumber )
{
// do something...
}
int MyCallDispCallback( AODFeedDispositionBase* CallDisposition )
{
// do something...
}
int MyServiceStatusCallback( long nSD, long nStatus )
{
// do something...
}
int MyAuthServiceCallback( long nSD, char* sSDesc, long nSType )
{
// do something...
}
int MyInboundAbandonCallback( long nSD, DCCProInboundDisposition* inbounCall )
{
// do something...
}
int MySessionStatusCallback( long lTypeId, long lStatus )
{
// do something...
}
int main()
{
...
short ret = Initialize("tenant name", "user ID", "password", &AuthServiceCallback, &MyServiceStatusCallback, &MyFeedQCallback, &MyCallDispCallback, &MyInboundAbandonCallback, &MySessionStatusCallback);
...
long serviceID = ...;
StartService(serviceID);
...
StopService(serviceID, queueAction);
...
Close();
return 0;
}
Related
I'm just trying to copy the input buffer of portaudio in a callback function. Thats my callback:
static int recordCallback( const void *inputBuffer, void *outputBuffer,
unsigned long framesPerBuffer,
const PaStreamCallbackTimeInfo* timeInfo,
PaStreamCallbackFlags statusFlags,
void *userData )
{
paTestData *data = (paTestData*)userData;
const SAMPLE *rptr = (const SAMPLE*)inputBuffer;
SAMPLE *wptr = &data->recordedSamples[data->frameIndex * NUM_CHANNELS];
long framesToCalc;
long i;
int finished;
unsigned long framesLeft = data->maxFrameIndex - data->frameIndex;
memcpy(&circularBuffer[data->write], inputBuffer, 1024); // Assuming samplesPerFrame = FRAME_SIZE
data->write = data->write + 1024;
(void) outputBuffer; /* Prevent unused variable warnings. */
(void) timeInfo;
(void) statusFlags;
(void) userData;
if( framesLeft < framesPerBuffer )
{
framesToCalc = framesLeft;
finished = paComplete;
}
else
{
framesToCalc = framesPerBuffer;
finished = paContinue;
}
data->frameIndex += framesToCalc;
return finished;
}
And this is the original callback from portaudio examples:
static int recordCallback( const void *inputBuffer, void *outputBuffer,
unsigned long framesPerBuffer,
const PaStreamCallbackTimeInfo* timeInfo,
PaStreamCallbackFlags statusFlags,
void *userData )
{
paTestData *data = (paTestData*)userData;
const SAMPLE *rptr = (const SAMPLE*)inputBuffer;
SAMPLE *wptr = &data->recordedSamples[data->frameIndex * NUM_CHANNELS];
long framesToCalc;
long i;
int finished;
unsigned long framesLeft = data->maxFrameIndex - data->frameIndex;
(void) outputBuffer; /* Prevent unused variable warnings. */
(void) timeInfo;
(void) statusFlags;
(void) userData;
if( framesLeft < framesPerBuffer )
{
framesToCalc = framesLeft;
finished = paComplete;
}
else
{
framesToCalc = framesPerBuffer;
finished = paContinue;
}
if( inputBuffer == NULL )
{
for( i=0; i<framesToCalc; i++ )
{
*wptr++ = SAMPLE_SILENCE; /* left */
if( NUM_CHANNELS == 2 ) *wptr++ = SAMPLE_SILENCE; /* right */
}
}
else
{
for( i=0; i<framesToCalc; i++ )
{
*wptr++ = *rptr++; /* left */
if( NUM_CHANNELS == 2 ) *wptr++ = *rptr++; /* right */
}
}
data->frameIndex += framesToCalc;
return finished;
}
And I'm just using memcpy instead of to iterate pointer. But the sound I record has so much noise. I can't figure out the problem. Maybe, I'm missing the channels(2 channels) but I'm not sure. Do you have any idea?
You can access the full code from here
The approach is true but I couldn`t specify the frame size correctly
Instead of this:
memcpy(&circularBuffer[data->write], inputBuffer, 1024); // 1024 = FRAME_SIZE
This will be better:
memcpy(&circularBuffer[data->write], inputBuffer, 1024*sizeof(float)); // Assuming 1024 = FRAME_SIZE
because of:
typedef float SAMPLE; is 4 bytes.
I have dll and I want to use a function from that dll in my project.
Dll and app project are in different projects (different IDEs).
Part of the dll (including shown below) code is generated with some code generator and I have little control over it.
dll code:
#define EXPORT_API extern "C" __declspec(dllexport)
typedef unsigned long UINT32;
typedef unsigned char UINT8;
typedef unsigned short RESULT;
typedef struct VARIANT_s
{
UINT32 Len;
UINT8* pData;
} VARIANT;
#pragma optimize( "", off )
EXPORT_API RESULT ExecuteV25 ( const UINT32 cmd
, const UINT32 inLen , const char* const in
, const UINT32 inoutLen, const char* inout
, const UINT32 outLen , const char* out)
{
switch (cmd)
{
case 1:
{
VARIANT _odk_internal_variant_inout = {inoutLen, (UINT8*)inout};
return func1 (_odk_internal_variant_inout);
}
case 2:
{
VARIANT _odk_internal_variant_inout = {inoutLen, (UINT8*)inout};
return func2 (_odk_internal_variant_inout);
}
case 3:
{
VARIANT _odk_internal_variant_inout = {inoutLen, (UINT8*)inout};
return func3 (_odk_internal_variant_inout);
}
default:
{
}
}
}
#pragma optimize( "", on )
Dependancy walker shows:
[https://imgur.com/QPvPkLr][1]
In other project (in which i want to call function above) i have:
typedef ODK_RESULT ( *_fpExecute) ( const ODK_UINT32 cmd
, const ODK_UINT32 inLen , const char* const in
, const ODK_UINT32 inoutLen, const char* inout
, const ODK_UINT32 outLen , const char* out
);
char* a = new char[sizeof(_struc)]; //_struct size is ~19000 bytes
unsigned long a_size = sizeof(_struc);
memset(a, 0, sizeof(_struc));
HMODULE hm = LoadLibrary("lib.dll");
_fpExecute _ExecuteV25 = (_fpExecute) GetProcAddress(hm, "ExecuteV25");
_ExecuteV25 = 1 after this. And than I try calling function with bellow line, but app crashes:
(_ExecuteV25) (1, 0, nullptr, a_size, a , 0, nullptr);
What I'm doing wrong?
My purpose is quite simple: when I start the mongoose server, the server will initialize a variable which is defined by me. To do this, I hooked __libc_start_main. Then when the server receives a request, it will print out that initialized variable. To do this, I hooked recv. Below is my code.
#include <string>
#include <stdio.h>
#include <dlfcn.h>
#include <stdlib.h>
#include "common-structure.h"
# define dprintf(fmt...)
data datainfo; //defined in common-structure.h
typedef int (*main_type)(int, char**, char**);
struct arg_type
{
char **argv;
int (*main_func) (int, char **, char **);
};
main_type saved_init_func = NULL;
void tern_init_func(int argc, char **argv, char **env){
dprintf("%04d: __tern_init_func() called.\n", (int) pthread_self());
if(saved_init_func)
saved_init_func(argc, argv, env);
datainfo.age = 10;
}
typedef void (*fini_type)(void*);
fini_type saved_fini_func = NULL;
extern "C" int my_main(int argc, char **pt, char **aa)
{
int ret;
arg_type *args = (arg_type*)pt;
dprintf("%04d: __libc_start_main() called.\n", (int) pthread_self());
ret = args->main_func(argc, args->argv, aa);
return ret;
}
extern "C" int __libc_start_main(
void *func_ptr,
int argc,
char* argv[],
void (*init_func)(void),
void (*fini_func)(void),
void (*rtld_fini_func)(void),
void *stack_end)
{
typedef void (*fnptr_type)(void);
typedef int (*orig_func_type)(void *, int, char *[], fnptr_type,
fnptr_type, fnptr_type, void*);
orig_func_type orig_func;
arg_type args;
void * handle;
int ret;
// Get lib path.
Dl_info dli;
dladdr((void *)dlsym, &dli);
std::string libPath = dli.dli_fname;
libPath = dli.dli_fname;
size_t lastSlash = libPath.find_last_of("/");
libPath = libPath.substr(0, lastSlash);
libPath += "/libc.so.6";
libPath = "/lib/x86_64-linux-gnu/libc.so.6";
if(!(handle=dlopen(libPath.c_str(), RTLD_LAZY))) {
puts("dlopen error");
abort();
}
orig_func = (orig_func_type) dlsym(handle, "__libc_start_main");
if(dlerror()) {
puts("dlerror");
abort();
}
dlclose(handle);
dprintf("%04d: __libc_start_main is hooked.\n", (int) pthread_self());
args.argv = argv;
args.main_func = (main_type)func_ptr;
saved_init_func = (main_type)init_func;
saved_fini_func = (fini_type)rtld_fini_func;
ret = orig_func((void*)my_main, argc, (char**)(&args),
(fnptr_type)tern_init_func, (fnptr_type)fini_func,
rtld_fini_func, stack_end);
return ret;
}
//hook recv
extern "C" ssize_t recv(int sockfd, void *buf, size_t len, int flags)
{
ssize_t (*orig_recv)(int sockfd, void *buf, size_t len, int flags);
orig_recv = dlsym(RTLD_NEXT, "recv");
orig_recv(sockfd, buf, len, flags);
printf("age is %d\n", datainfo.age);
}
However, when I makefile, I get the error: invalid conversion from ‘void*’ to ‘ssize_t (*)(int, void*, size_t, int) coming from dlsym(RTLD_NEXT, "recv");. My another question is can I achieve my goal in this way? If not, what is the correct way?
C++ is much more strongly typed than C, you need to explicitly cast void * to the correct type.
For example:
extern "C" ssize_t recv(int sockfd, void *buf, size_t len, int flags)
{
using orig_recv_t = ssize_t (*)(int, void *, size_t, int);
// Or for pre C++11 compilers: typedef ssize_t (*orig_recv_t)(int, void *, size_t, int);
orig_recv_t orig_recv;
orig_recv = reinterpret_cast<orig_recv_t>(dlsym(RTLD_NEXT, "recv"));
orig_recv(sockfd, buf, len, flags);
printf("age is %d\n", datainfo.age);
}
Does this function has the same behavior that memset?
inline void SetZeroArray( void *vArray[], unsigned int uArraySize )
{
for(unsigned i=0; i<=uArraySize; i++ )
vArray[i] = NULL;
}
int main( int argc, char *argv[] )
{
unsigned int uLevels[500];
SetZeroArray( (void**)uLevels, 500 );
unsigned int ulRLevels[500];
memset( &ulRLevels, 0, sizeof( ulRLevels ) );
system("pause>nul");
return EXIT_SUCCESS;
}
NO, your function does not behave the same as memset. Your function sets a pointer to NULL and memset sets the values of the data to the value supplied.
Different things altogether.
I want to use class member functions as callbacks, I don't use libsigc, because it's slow.
In ATL, we can use member function for C-style callback(http://www.codeproject.com/KB/cpp/SoloGenericCallBack.aspx), so can we implement c++ thunk in linux?
The code below will crash:
#include <assert.h>
#include <stdio.h>
#include <sys/mman.h>
typedef char BYTE;
typedef int DWORD;
typedef int* DWORD_PTR;
typedef int* INT_PTR;
typedef bool BOOL;
typedef unsigned long ULONG;
typedef unsigned long* ULONG_PTR;
#define PtrToUlong( p ) ((ULONG)(ULONG_PTR) (p) )
#define __stdcall __attribute__((__stdcall__))
//#pragma pack( push, 1 )
struct MemFunToStdCallThunk
{
BYTE m_mov;
DWORD m_this;
BYTE m_pushEax;
BYTE m_jmp;
DWORD m_relproc;
void Init( DWORD_PTR proc, void* pThis )
{
printf("proc=%x\n", proc);
m_mov = 0xB8; // mov eax
m_this = PtrToUlong(pThis);
m_pushEax = 0xc3;// push eax
m_jmp = 0xe9; //jmp
m_relproc = DWORD((INT_PTR)proc - ((INT_PTR)this+sizeof(MemFunToStdCallThunk)));
printf("m_relproc = %x\n", m_relproc);
mprotect(this, sizeof(MemFunToStdCallThunk), PROT_READ|PROT_WRITE|PROT_EXEC);
}
void* GetCodeAddress()
{
return this;
}
}__attribute__ ((packed));
//#pragma pack( pop )
template< typename TDst, typename TSrc >
TDst UnionCastType( TSrc src )
{
union
{
struct
{
int* pfn; //function,index
long delta; // offset,
}funcPtr;
TSrc uSrc;
}uMedia;
uMedia.uSrc = src;
return uMedia.funcPtr.pfn;
}
typedef int ( __stdcall *StdCallFun)(int, int);
class CTestClass
{
public:
int m_nBase;
MemFunToStdCallThunk m_thunk;
int memFun( int m, int n )
{
int nSun = m_nBase + m + n;
printf("m=%d,n=%d,nSun=%d\n", m, n, nSun);
return 1234;
}
public:
CTestClass()
{
m_nBase = 10;
}
void Test()
{
printf("%x\n", &CTestClass::memFun);
m_thunk.Init(UnionCastType<DWORD_PTR>(&CTestClass::memFun), this );
StdCallFun fun = (StdCallFun)m_thunk.GetCodeAddress();
assert( fun != NULL );
int ret = fun( 9, 3 );
printf("ret = %x\n", ret);
}
};
int main()
{
CTestClass test;
test.Test();
return 0;
}
EDIT:
Thanks to user786653, I get the right answer:
#include <assert.h>
#include <stdio.h>
#include <sys/mman.h>
#include <unistd.h>
typedef char BYTE;
typedef int DWORD;
typedef int* DWORD_PTR;
typedef int* INT_PTR;
typedef bool BOOL;
typedef unsigned long ULONG;
typedef unsigned long* ULONG_PTR;
#define PtrToUlong(p) ((ULONG)(ULONG_PTR) (p) )
#define __stdcall __attribute__((__stdcall__))
struct MemFunToStdCallThunk
{
BYTE m_repairStack[10];
DWORD m_mov;
DWORD m_this;
BYTE m_jmp;
DWORD m_relproc;
void Init( DWORD_PTR proc, void* pThis )
{
printf("proc=%p\n", proc);
m_repairStack[0] = 0x83; //sub esp, 0x4
m_repairStack[1] = 0xec;
m_repairStack[2] = 0x04;
m_repairStack[3] = 0x8b; //mov eax,[esp + 0x4]
m_repairStack[4] = 0x44;
m_repairStack[5] = 0x24;
m_repairStack[6] = 0x04;
m_repairStack[7] = 0x89;//mov [esp], eax
m_repairStack[8] = 0x04;
m_repairStack[9] = 0x24;
m_mov = 0x042444C7; // mov dword ptr [esp+0x4],
m_this = PtrToUlong(pThis);
m_jmp = 0xe9; //jmp
m_relproc = (DWORD)proc - ((DWORD)this+sizeof(MemFunToStdCallThunk));
printf("m_relproc = %d\n", m_relproc);
//long page_size = sysconf(_SC_PAGE_SIZE);
//mprotect((void*)(PtrToUlong(this) & -page_size), 2*page_size, PROT_READ|PROT_WRITE|PROT_EXEC);
}
void* GetCodeAddress()
{
return this;
}
}__attribute__ ((packed));
template< typename TDst, typename TSrc >
TDst UnionCastType( TSrc src )
{
union
{
struct
{
int* pfn; //function or index
long delta; // offset
}funcPtr;
TSrc uSrc;
}uMedia;
uMedia.uSrc = src;
return uMedia.funcPtr.pfn;
}
typedef int ( __stdcall *StdCallFun)(int, int);
class CTestClass
{
public:
int m_nBase;
MemFunToStdCallThunk m_thunk;
int memFun( int m, int n )
{
printf("this=%p\n", this);
int nSun = m_nBase + m + n;
printf("m=%d,n=%d,nSun=%d\n", m, n, nSun);
return nSun;
}
public:
CTestClass()
{
m_nBase = 10;
}
void Test()
{
int (CTestClass::*abc)(int, int);
printf("sizeof(MemFunToStdCallThunk)=%d,sizeof(abc)=%d\n", sizeof(MemFunToStdCallThunk), sizeof(abc));
printf("memFun=%p\n", &CTestClass::memFun);
m_thunk.Init(UnionCastType<DWORD_PTR>(&CTestClass::memFun), this );
StdCallFun fun = (StdCallFun)m_thunk.GetCodeAddress();
assert( fun != NULL );
int ret = memFun(2, 3);
printf("ret 1= %d\n", ret);
ret = fun( 9, 3 );
printf("ret 2= %d\n", ret);
}
};
int main()
{
CTestClass test;
test.Test();
return 0;
}
Yes, but I wouldn't recommend it. It will (obviously) make your code a lot less portable and you're potentially opening a security hole if you're not careful.
You will need to make the code executable with mprotect(2). Something like mprotect(&thunk_struct, sizeof(struct _CallBackProcThunk), PROT_READ|PROT_WRITE|PROT_EXEC).
Also the normal GCC syntax for structure packing is struct S { /* ... */ } __attribute__ ((packed)) though newer versions might support the #pragma pack syntax.
You will probably also want to substitute DWORD with uint32_t from stdint.h and BYTE with uint8_t (or just stick a typedef in there).
EDIT:
From the man page on mprotect "[..]addr must be aligned to a page boundary". You should check the return value. Try doing something like this instead:
long page_size = sysconf(_SC_PAGE_SIZE);
uintptr_t addr = ((uintptr_t)this) & -page_size;
if (mprotect((void*)addr, 2*page_size, PROT_READ|PROT_WRITE|PROT_EXEC)) {
perror("mprotect");
/* handle error */
}
The following calculation is wrong:
DWORD((INT_PTR)proc - ((INT_PTR)this+sizeof(MemFunToStdCallThunk)))
It's doing its calculations on int*'s.
(DWORD)proc - ((DWORD)this+sizeof(MemFunToStdCallThunk)
should be sufficient here.
A very ugly (non-portable etc. etc.), but small and self-contained example follows:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <sys/mman.h>
struct thunk {
uint32_t mov;
uint32_t this_ptr;
uint8_t jmp;
uint32_t rel;
} __attribute__((packed));
class Test {
public:
virtual int foo(void) {
printf("foo! %p\n", (void*)this);
return 42;
}
};
int main()
{
Test test;
printf("%d\n", test.foo());
thunk t;
t.mov = 0x042444C7;
t.this_ptr = (uint32_t)&test;
t.jmp = 0xe9;
t.rel = ((uint32_t)(void*)&Test::foo) - ((uint32_t)&t + sizeof(thunk));
uint32_t addr = (uint32_t)&t;
long page_size = sysconf(_SC_PAGE_SIZE);
if (mprotect((void*)(addr & -page_size), 2*page_size, PROT_READ|PROT_WRITE|PROT_EXEC)) {
perror("mprotect");
return 1;
}
union {
void* p;
int (*foo)(int);
} u;
u.p = &t;
printf("%d\n", u.foo(0));
return 0;
}
A reasonable approach is something like this:
struct Foo {
void doit();
};
extern "C" {
void callback(void *handle) {
reinterpret_cast<Foo*>(handle)->doit();
}
}
The assembly of callback looks like this here (x64):
callback:
jmpq _ZN3Foo4doitEv
You can't pass pointer-to-member pointers to C callbacks directly, but there are portable tricks (i.e. not restricted to one target OS) that work very well.
The easiest way to do that is just to use a wrapper non-member function whose only purpose is to call your member function.
void wrapper()
{
object->callWhatever();
}
You can pass wrapper() as a function pointer.
See also for example Cast member function for create_pthread() call for how to handle cases where you get a void* parameter with the callback and want to use that to store (directly or not) a reference/pointer to the object you want to operate on.
I want to use class member functions as callbacks, I don't use libsigc, because it's slow. In ATL, we can use member function for C-style callback(http://www.codeproject.com/KB/cpp/SoloGenericCallBack.aspx), so can we implement c++ thunk in linux?
You probably can. However, there is no need to.
Most asynchronous APIs allow to pass a void* argument when registering for an asynchronous event. When the event gets reported this void* is reported as well and can be used to call a member function of an object. (Vague language because APIs like epoll_wait() don't actually call you back, where as pthread_create() does.).