Embedding Flash in Linux GTK Application - Sandbox Violation - c

I'm embedding a Flash SWF file in a Linux application using the NPAPI. Everything works fine but when the Flash calls "fscommand", I'm getting a security sandbox violation. I tried the program with several Linux distributions and several versions of the Flash Player (9,10,11) but no luck.
Does anybody know if this is a limitation of the Flash Player in Linux platforms?
In this post Closing gtk application when SWF ends (NPAPI) it seems they have been able to receive Javascript events.
This is the code I'm using:
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
#include <string.h>
#include <unistd.h>
#include <ctype.h>
#include <gtk/gtk.h>
#include <gdk/gdkx.h>
//#include "npupp.h"
#include "npapi.h"
#include "npfunctions.h"
//#ifdef __i386__
#define FLASH_PLUGIN_SO "./flash/libflashplayer32.so"
//#else
//#define FLASH_PLUGIN_SO "./flash/libflashplayer64.so"
//#endif
#define PR_TRUE 1
#define PR_FALSE 0
#define WINDOW_XSIZE 1600/2
#define WINDOW_YSIZE 900/2
#define NO_IDENTIFIER ((NPIdentifier)0)
#define SPECIAL_IDENTIFIER 0x0FEEBBCC
#define SPECIAL_METHOD_NAME "swhxCall"
#define FLASH_REQUEST "__flash__request"
#define FSCMD "_DoFSCommand"
#define INVOKE_RESPONSE "<invoke name=\"%s\" returntype=\"javascript\"><arguments><null/></arguments></invoke>"
typedef intptr_t int_val;
void *flash_plugin_handle;
NPNetscapeFuncs browserFuncs;
NPPluginFuncs pluginFuncs;
GtkWidget *main_window;
char* URL;
NPStream * stream;
const char * uagent = "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.13) Gecko/20101206 Ubuntu/10.10 (maverick) Firefox/3.6.13";
NPError (*iNP_Initialize)(NPNetscapeFuncs* bFuncs, NPPluginFuncs* pFuncs);
NPError (*iNP_Shutdown)();
char* (*iNP_GetMIMEDescription)();
// --- Property IDs
static char **np_ids = NULL;
static int_val np_id_count = 0;
static NPIdentifier resolveNPId( const char *id ) {
int_val i;
for(i=0;i<np_id_count;i++)
if( strcmp(np_ids[i],id) == 0 )
return (NPIdentifier)(i+1);
if( strcmp(id,SPECIAL_METHOD_NAME) == 0 )
return (NPIdentifier)SPECIAL_IDENTIFIER;
return NO_IDENTIFIER;
}
static NPIdentifier addNPId( const char *id ) {
NPIdentifier newid = resolveNPId(id);
if( newid == NO_IDENTIFIER ) {
np_id_count++;
printf("New npid added: %i == %s\n",np_id_count, id);
np_ids = realloc(np_ids,np_id_count*sizeof(char*));
np_ids[np_id_count-1] = strdup(id);
return (NPIdentifier)np_id_count;
}
return newid;
}
static const char *getNPId( NPIdentifier id ) {
int_val index = ((int_val)id)-1;
if( index >= 0 && index < np_id_count )
return np_ids[index];
if( id == (NPIdentifier)SPECIAL_IDENTIFIER )
return SPECIAL_METHOD_NAME;
return NULL;
}
static int matchNPId(NPIdentifier id, const char *str) {
const char *strid = getNPId(id);
return ( strid != NULL && strcmp(strid,str) == 0 );
}
void freeNPIds() {
while( np_id_count )
free(np_ids[--np_id_count]);
free(np_ids);
}
static bool NPN_InvokeProc( NPP npp, NPObject *npobj, NPIdentifier methodName, const NPVariant *args, uint32_t argCount, NPVariant *result ) ;
static bool NPN_InvokeDefaultProc( NPP npp, NPObject *npobj, const NPVariant *args, uint32_t argCount, NPVariant *result ) ;
static bool NPN_GetPropertyProc( NPP npp, NPObject *npobj, NPIdentifier propertyName, NPVariant *result ) ;
static bool NPN_SetPropertyProc( NPP npp, NPObject *npobj, NPIdentifier propertyName, const NPVariant *value ) ;
static bool NPN_RemovePropertyProc( NPP npp, NPObject *npobj, NPIdentifier propertyName ) ;
static bool NPN_HasPropertyProc( NPP npp, NPObject *npobj, NPIdentifier propertyName ) ;
static bool NPN_HasMethodProc( NPP npp, NPObject *npobj, NPIdentifier methodName ) ;
static NPObject *NPN_CreateObjectProc( NPP npp, NPClass *aClass );
static NPObject *NPN_RetainObjectProc( NPObject *npobj );
// Window class;
static NPClass __gen_class =
{ NP_CLASS_STRUCT_VERSION
, (NPAllocateFunctionPtr) malloc
, (NPDeallocateFunctionPtr) free
, 0
, (NPHasMethodFunctionPtr) NPN_HasMethodProc
, (NPInvokeFunctionPtr) NPN_InvokeProc
, (NPInvokeDefaultFunctionPtr)NPN_InvokeDefaultProc
, (NPHasPropertyFunctionPtr) NPN_HasPropertyProc
, (NPGetPropertyFunctionPtr) NPN_GetPropertyProc
, (NPSetPropertyFunctionPtr) NPN_SetPropertyProc
, (NPRemovePropertyFunctionPtr) NPN_RemovePropertyProc
};
static NPObject __window = { &__gen_class, 1 };
static NPObject __location = { &__gen_class, 1};
static NPObject __top = { &__gen_class, 1 };
static NPObject __top_location = { &__gen_class, 1 };
static void traceObjectOnCall(const char *f, NPObject *o){
if (o == &__top) printf("DOM object 'top': %s\n",f);
else if (o == &__window) printf("DOM object 'window': %s\n",f);
else if (o == &__location) printf("DOM object 'location': %s\n",f);
else if (o == &__top_location) printf("DOM object 'top.location': %s\n",f);
}
static void checkError(const char* str, NPError err) {
if(err == NPERR_NO_ERROR)
printf("[+] %s: success\n", str);
else
printf("[-] %s: failed (%d)\n", str, err);
fflush (stdout);
}
void* loadFlashPluginSo() {
void *handle;
handle = dlopen(FLASH_PLUGIN_SO, RTLD_LAZY | RTLD_LOCAL);
if(!handle) {
fprintf(stderr, "[-] error loading libflasplayer.so: %s\n", dlerror());
exit(1);
}
puts("[+] loaded libflashplayer.so");
return handle;
}
void* loadSymbol(void *handle, const char *name) {
char *error;
void *ret;
ret = dlsym(handle, name);
if((error = dlerror()) != NULL) {
fprintf(stderr, "[-] error loading symbol %s: %s\n", name, error);
exit(1);
} else {
printf("[+] loaded symbol %s, address: %p\n", name, ret);
}
return ret;
}
void loadNPEntryPoints(void *handle) {
iNP_Initialize=(NPError (*)(NPNetscapeFuncs* bFuncs, NPPluginFuncs* pFuncs))loadSymbol(handle, "NP_Initialize");
iNP_Shutdown=(NPError (*)())loadSymbol(handle, "NP_Shutdown");
iNP_GetMIMEDescription = (char*(*)())loadSymbol(handle,"NP_GetMIMEDescription");
}
void printPluginEntrypoints(NPPluginFuncs* pFuncs) {
printf("[*] NPP struct:\n");
printf("\t- NPP_size: %8d\n",pFuncs->size);
printf("\t- NPP_version: %8d\n",pFuncs->version);
printf("\t- NPP_NewProcPtr: %p\n", pFuncs->newp);
printf("\t- NPP_DestroyProcPtr: %p\n", pFuncs->destroy);
printf("\t- NPP_SetWindowProcPtr: %p\n", pFuncs->setwindow);
printf("\t- NPP_NewStreamProcPtr: %p\n", pFuncs->newstream);
printf("\t- NPP_DestroyStreamProcPtr: %p\n", pFuncs->destroystream);
printf("\t- NPP_StreamAsFileProcPtr: %p\n", pFuncs->asfile);
printf("\t- NPP_WriteReadyProcPtr: %p\n", pFuncs->writeready);
printf("\t- NPP_WriteProcPtr: %p\n", pFuncs->write);
printf("\t- NPP_PrintProcPtr: %p\n", pFuncs->print);
printf("\t- NPP_HandleEventProcPtr: %p\n", pFuncs->event);
printf("\t- NPP_URLNotifyProcPtr: %p\n", pFuncs->urlnotify);
printf("\t- javaClass: %p\n", pFuncs->javaClass);
printf("\t- NPP_GetValueProcPtr: %p\n", pFuncs->getvalue);
printf("\t- NPP_SetValueProcPtr: %p\n", pFuncs->setvalue);
}
NPError NPN_SetValueProc(NPP instance, NPPVariable variable, void *value)
{
switch(variable) {
case NPPVpluginWindowBool:
printf( "NPPVpluginWindowBool - %p\n", value);
break;
default:
printf( "SetValue %i\n", variable );
break;
}
return NPERR_NO_ERROR;
}
NPError NPN_GetValueProc(NPP instance, NPNVariable variable, void *ret_value) {
printf("[D] NPN_GetValueProc instance:%p, variable:%d, abi_mask:%d\n", instance, variable, 0);
switch (variable) {
case NPNVSupportsXEmbedBool:
*((int*)ret_value)= PR_TRUE;
break;
case NPNVToolkit:
*((int*)ret_value)= NPNVGtk2;
break;
case NPNVnetscapeWindow:
*((int*)ret_value)= PR_TRUE;
break;
default:
*((int*)ret_value)=PR_FALSE;
break;
}
return NPERR_NO_ERROR;
}
const char* NPN_UserAgentProc(NPP instance) {
return uagent;
}
static void Status_( NPP instance, const char* message ) {
printf( "Status\n" );
}
uint32_t MemFlush( uint32_t size ) {
return 0;
}
void ReloadPlugins( NPBool reloadPages ) {
}
void * GetJavaEnv(void) {
return NULL;
}
void * GetJavaPeer( NPP instance ) {
return NULL;
}
NPIdentifier NPN_GetStringIdentifierProc(const NPUTF8* name) {
return addNPId(name);
}
void GetStringIdentifiers( const NPUTF8 **names, int32_t nameCount, NPIdentifier *identifiers ) {
}
NPIdentifier GetIntIdentifier( int32_t intid ) {
return NO_IDENTIFIER;
}
bool IdentifierIsString( NPIdentifier id ) {
return getNPId(id) != NULL;
}
NPUTF8* UTF8FromIdentifier( NPIdentifier identifier ) {
const char *result = getNPId(identifier);
return result ? strdup(result) : NULL;
}
int32_t IntFromIdentifier( NPIdentifier id ) {
return 0;
}
static gboolean plug_removed_cb (GtkWidget *widget, gpointer data) {
printf("[!] plug_removed_cb\n");
return TRUE;
}
static void socket_unrealize_cb(GtkWidget *widget, gpointer data) {
printf("[!] socket_unrealize_cb\n");
}
static NPWindow * npwindow_construct (GtkWidget *widget) {
NPWindow *npwindow;
NPSetWindowCallbackStruct *ws_info = NULL;
GdkWindow *parent_win = widget->window;
GtkWidget *socketWidget = gtk_socket_new();
gtk_widget_set_parent_window(socketWidget, parent_win);
g_signal_connect(socketWidget, "plug_removed", G_CALLBACK(plug_removed_cb), NULL);
g_signal_connect(socketWidget, "unrealize", G_CALLBACK(socket_unrealize_cb), NULL);
g_signal_connect(socketWidget, "destroy", G_CALLBACK(gtk_widget_destroyed), &socketWidget);
gpointer user_data = NULL;
gdk_window_get_user_data(parent_win, &user_data);
GtkContainer *container = GTK_CONTAINER(user_data);
gtk_container_add(container, socketWidget);
gtk_widget_realize(socketWidget);
GtkAllocation new_allocation;
new_allocation.x = 0;
new_allocation.y = 0;
new_allocation.width = WINDOW_XSIZE;
new_allocation.height = WINDOW_YSIZE;
gtk_widget_size_allocate(socketWidget, &new_allocation);
gtk_widget_show(socketWidget);
gdk_flush();
GdkNativeWindow ww = gtk_socket_get_id(GTK_SOCKET(socketWidget));
GdkWindow *w = gdk_window_lookup(ww);
npwindow = (NPWindow*) malloc (sizeof (NPWindow));
npwindow->window = (void*)(unsigned long)ww;
npwindow->x = 0;
npwindow->y = 0;
npwindow->width = WINDOW_XSIZE;
npwindow->height = WINDOW_YSIZE;
ws_info = (NPSetWindowCallbackStruct*) malloc(sizeof (NPSetWindowCallbackStruct));
ws_info->type = NP_SETWINDOW;
ws_info->display = GDK_WINDOW_XDISPLAY(w);
ws_info->colormap = GDK_COLORMAP_XCOLORMAP(gdk_drawable_get_colormap(w));
GdkVisual* gdkVisual = gdk_drawable_get_visual(w);
ws_info->visual = GDK_VISUAL_XVISUAL(gdkVisual);
ws_info->depth = gdkVisual->depth;
npwindow->ws_info = ws_info;
npwindow->type = NPWindowTypeWindow;
return npwindow;
}
static NPStream * npstream_construct() {
NPStream *stream = (NPStream *) malloc(sizeof(NPStream));
stream->url=strdup(URL);
stream->ndata = 0;
stream->end = 99782;
stream->lastmodified= 1201822722;
stream->notifyData = 0x00000000;
stream->headers = (char*)malloc(200);
return stream;
}
bool NPN_InvokeProc( NPP npp, NPObject *npobj, NPIdentifier npid, const NPVariant *args, uint32_t argCount, NPVariant *result ) {
traceObjectOnCall(__FUNCTION__,npobj);
if( matchNPId(npid,FLASH_REQUEST) && argCount == 1 && args[0].type == NPVariantType_String ) {
return 1;
}
if( matchNPId(npid,FLASH_REQUEST) && argCount == 3 &&
args[0].type == NPVariantType_String &&
args[1].type == NPVariantType_String &&
args[2].type == NPVariantType_String
) {
return 1;
}
if( matchNPId(npid,"_DoFSCommand") && argCount == 2 && args[0].type == NPVariantType_String && args[1].type == NPVariantType_String ) {
printf("[D] FSCOMMAND\n");
return 1;
}
if( npobj == &__top_location ) {
if( matchNPId(npid,"toString") ) {
result->type = NPVariantType_String;
// "chrome://global/content/console.xul" is what Firefox returns for 'top.location.toString()';
result->value.stringValue.UTF8Characters = strdup("chrome://global/content/console.xul");
result->value.stringValue.UTF8Length = (int)strlen(result->value.stringValue.UTF8Characters);
printf("[D] Returned %s\n", result->value.stringValue.UTF8Characters);
}
return 1;
}
//On OSX, Flash retreives locations by injected functions:
if( matchNPId(npid,"__flash_getWindowLocation") ) {
// return the location object:
result->type = NPVariantType_Object;
result->value.objectValue = &__location;
NPN_RetainObjectProc(&__location);
return 1;
}
if( matchNPId(npid,"__flash_getTopLocation") ) {
// return the top_location object:
result->type = NPVariantType_Object;
result->value.objectValue = &__top_location;
NPN_RetainObjectProc(&__top_location);
return 1;
}
return 0;
}
static bool NPN_InvokeDefaultProc( NPP npp, NPObject *npobj, const NPVariant *args, uint32_t argCount, NPVariant *result ) {
return 0;
}
static bool NPN_GetPropertyProc( NPP npp, NPObject *npobj, NPIdentifier npid, NPVariant *result ) {
if (npobj == &__window) {
if( matchNPId(npid,"location") ) {
result->type = NPVariantType_Object;
result->value.objectValue = &__location;
NPN_RetainObjectProc(&__location);
return 1;
}
if( matchNPId(npid,"top") ) {
result->type = NPVariantType_Object;
result->value.objectValue = &__top;
NPN_RetainObjectProc(&__top);
return 1;
}
} else if (npobj == &__top) {
if ( matchNPId(npid,"location") ) {
result->type = NPVariantType_Object;
result->value.objectValue = &__top_location;
NPN_RetainObjectProc(&__top_location);
return 1;
}
}
return 0;
}
static bool NPN_SetPropertyProc( NPP npp, NPObject *npobj, NPIdentifier propertyName, const NPVariant *value ) {
return 0;
}
static bool NPN_RemovePropertyProc( NPP npp, NPObject *npobj, NPIdentifier propertyName ) {
return 0;
}
static bool NPN_HasPropertyProc( NPP npp, NPObject *npobj, NPIdentifier propertyName ) {
return 0;
}
static bool NPN_HasMethodProc( NPP npp, NPObject *npobj, NPIdentifier methodName ) {
return 0;
}
static int unescape( char *str, int *ssize ) {
int k = 0, esc = 0;
// UNESCAPE the string
while( k < *ssize ) {
if( !esc ) {
if( str[k++] == '\\' )
esc = 1;
} else {
char c;
switch( str[k] ) {
case '"': c = '"'; break;
case '\\': c = '\\'; break;
case 'r': c = '\r'; break;
case 'n': c = '\n'; break;
case 't': c = '\t'; break;
default:
return 0;
}
(*ssize)--;
memcpy(str+k,str+k+1,*ssize-k);
str[k-1] = c;
esc = 0;
}
}
str[*ssize] = 0;
return 1;
}
static const char *end_of_string( const char *send ) {
int esc = 0;
while( *send ) {
switch( *send ) {
case '"':
if( !esc )
return send;
esc = 0;
break;
case '\\':
esc = !esc;
break;
default:
esc = 0;
break;
}
send++;
}
return NULL;
}
#define JS_CALL_START "try { __flash__toXML("
#define JS_RESULT_START "var __flash_temp = \""
bool Evaluate( NPP npp, NPObject *npobj, NPString *script, NPVariant *result ) {
printf( "Evaluate %s\n", script->UTF8Characters );
if( memcmp(script->UTF8Characters,JS_CALL_START,strlen(JS_CALL_START)) == 0 ) {
const char *p = script->UTF8Characters + strlen(JS_CALL_START);
const char *s = p;
const char *send;
while( *s && *s != '(' )
s++;
if( !*s || s[1] != '"' )
return 0;
s += 2;
send = end_of_string(s);
if( send == NULL || send[1] != ')' )
return 0;
{
int isize = (int)(s - p) - 2;
int ssize = (int)(send - s);
char *ident = (char*)malloc(isize+1);
char *str = (char*)malloc(ssize+1);
memcpy(ident,p,isize);
memcpy(str,s,ssize);
ident[isize] = 0;
if( !unescape(str,&ssize) ) {
free(ident);
free(str);
return 0;
}
// CALLBACK
{
printf("CALLBACK\n");
int size = 0;
const char *res = "callback";
free(ident);
free(str);
if( res == NULL )
return 0;
result->type = NPVariantType_String;
result->value.stringValue.UTF8Characters = strdup(res);
result->value.stringValue.UTF8Length = size;
return 1;
}
}
}
if( memcmp(script->UTF8Characters,JS_RESULT_START,strlen(JS_RESULT_START)) == 0 ) {
const char *s = script->UTF8Characters + strlen(JS_RESULT_START);
const char *send = end_of_string(s);
char *str;
int ssize;
if( send == NULL || send[1] != ';' )
return 0;
ssize = (int)(send - s);
str = (char*)malloc(ssize+1);
memcpy(str,s,ssize);
if( !unescape(str,&ssize) ) {
free(str);
return 0;
}
result->type = NPVariantType_String;
result->value.stringValue.UTF8Characters = str;
result->value.stringValue.UTF8Length = ssize;
return 1;
}
result->type = NPVariantType_Void;
return 1;
}
void NPN_ReleaseObjectProc(NPObject *npobj) {
if( npobj == NULL )
return;
npobj->referenceCount--;
if( npobj->referenceCount != 0 )
return;
if( npobj->_class->deallocate ) {
npobj->_class->deallocate(npobj);
return;
}
if( npobj->_class->invalidate )
npobj->_class->invalidate(npobj);
free(npobj);
}
NPObject* NPN_CreateObjectProc(NPP npp, NPClass *aClass) {
NPObject *o;
if( aClass->allocate )
o = aClass->allocate(npp,aClass);
else
o = (NPObject*)malloc(sizeof(NPObject));
o->_class = aClass;
o->referenceCount = 1;
return o;
}
NPObject* NPN_RetainObjectProc(NPObject *npobj) {
if( npobj == NULL )
return NULL;
npobj->referenceCount++;
return npobj;
}
void NPN_ReleaseVariantValueProc(NPVariant *variant) {
//printf("ReleaseVariantValueProc\n");
switch( variant->type ) {
case NPVariantType_Null:
case NPVariantType_Void:
break;
case NPVariantType_String:
free( (char*)variant->value.stringValue.UTF8Characters );
variant->type = NPVariantType_Void;
break;
case NPVariantType_Object:
NPN_ReleaseObjectProc(variant->value.objectValue);
variant->type = NPVariantType_Void;
break;
default:
break;
}
}
void SetException( NPObject *npobj, const NPUTF8 *message ) {
printf("SetException %s\n",message);
}
NPError NPN_GetURLNotifyProc(NPP instance, const char* url, const char* window, void* notifyData) {
printf("[D] NPN_GetURLNotifyProc:%p, url: %s, window: %s\n", instance, url, window);
if (window && strlen(window)==6 && memcmp("_blank",window,6)==0) {
//system_launch_url(url);
pluginFuncs.urlnotify(instance,url,NPRES_DONE,notifyData);
} else if( memcmp(url,"javascript:",11) == 0 ) {
NPStream s;
uint16_t stype;
int success;
memset(&s,0,sizeof(NPStream));
s.url = strdup(url);
success = (pluginFuncs.newstream(instance,"text/html",&s,0,&stype) == NPERR_NO_ERROR);
if( success ) {
int pos = 0;
int size;
char buf[256];
sprintf(buf,"%X__flashplugin_unique__",(int_val)instance);
size = (int)strlen(buf);
s.end = size;
while( pos < size ) {
int len = pluginFuncs.writeready(instance,&s);
if( len <= 0 )
break;
if( len > size - pos )
len = size - pos;
len = pluginFuncs.write(instance,&s,pos,len,buf+pos);
if( len <= 0 )
break;
pos += len;
}
success = (pos == size);
}
pluginFuncs.urlnotify(instance,url,success?NPRES_DONE:NPRES_NETWORK_ERR,notifyData);
pluginFuncs.destroystream(instance,&s,NPRES_DONE);
free((void*)s.url);
} else {
NPStream stream;
uint16_t stype;// = NP_NORMAL;
memset(&stream,0,sizeof(NPStream));
stream.url = strdup(url);
stream.notifyData = notifyData;
pluginFuncs.newstream(instance,"application/x-shockwave-flash",&stream, 0, &stype);
//fprintf(stderr, "NPP: %p URL: %s\n", instance, url);
FILE *pp;
char buffer[8192];
pp = fopen(url,"rb");
int len;
while((len=fread(buffer, 1, sizeof(buffer), pp)) != 0) {
pluginFuncs.writeready(instance, &stream);
pluginFuncs.write(instance, &stream, 0, len, buffer);
}
fclose(pp);
pluginFuncs.destroystream(instance, &stream, NPRES_DONE);
free((void*)stream.url);
//pluginFuncs.urlnotify(instance, url, NPRES_DONE, notifyData);
}
return NPERR_NO_ERROR;
}
NPError NPN_GetURL( NPP instance, const char* url, const char* target ) {
printf( "GetURL %s\n", url );
if (target && strlen(target)==6 && memcmp("_blank",target,6)==0) {
//system_launch_url(url);
return NPERR_NO_ERROR;
}
return NPERR_NO_ERROR;
}
NPError NPN_PostURLNotify( NPP instance, const char* url, const char* target, uint32_t len, const char* buf, NPBool file, void* notifyData) {
printf( "PostURLNotify (url) %s (target) %s (buf) %s[%d] (file) %i (nd) %p\n", url, target, buf, len, file, notifyData);
//url_process(instance,url,buf,len,notifyData);
return NPERR_NO_ERROR;
}
NPError NPN_PostURL( NPP instance, const char* url, const char* target, uint32_t len, const char* buf, NPBool file ) {
printf( "PostURL" );
return NPERR_NO_ERROR;
}
NPError NPN_RequestRead(NPStream* stream, NPByteRange* range_list) {
printf("[D] NPN_RequestRead\n");
return NPERR_NO_ERROR;
}
NPError NewStream( NPP instance, NPMIMEType type, const char* target, NPStream** stream ) {
printf( "NewStream\n" );
return NPERR_NO_ERROR;
}
int32_t Write( NPP instance, NPStream* stream, int32_t len, void* buffer ) {
printf( "Write\n" );
return 0;
}
NPError DestroyStream( NPP instance, NPStream* stream, NPReason reason ) {
printf( "DestroyStream\n" );
return NPERR_NO_ERROR;
}
void _InvalidateRect( NPP instance, NPRect *invalidRect ) {
printf( "InvalidateRect\n" );
}
void InvalidateRegion( NPP instance, NPRegion invalidRegion ) {
printf( "InvalidateRegion\n" );
}
void ForceRedraw( NPP instance ) {
printf( "ForceRedraw\n" );
}
void initNPNetscapeFuncs(NPNetscapeFuncs *bFuncs) {
int i=0;
for(i=1; i<sizeof(*bFuncs)/sizeof(ssize_t); i++)
*(((ssize_t*)bFuncs)+i)=i+1000;
bFuncs->geturl=NPN_GetURL;
bFuncs->posturl=NPN_PostURL;
bFuncs->requestread=NPN_RequestRead;
bFuncs->newstream=NewStream;
bFuncs->write=Write;
bFuncs->destroystream=DestroyStream;
bFuncs->status=Status_;
bFuncs->uagent=NPN_UserAgentProc;
bFuncs->memalloc=malloc;
bFuncs->memfree=free;
bFuncs->memflush=MemFlush;
bFuncs->reloadplugins=ReloadPlugins;
bFuncs->getJavaEnv=GetJavaEnv;
bFuncs->getJavaPeer=GetJavaPeer;
bFuncs->geturlnotify=NPN_GetURLNotifyProc;
bFuncs->posturlnotify=NPN_PostURLNotify;
bFuncs->getvalue=NPN_GetValueProc;
bFuncs->setvalue=NPN_SetValueProc;
bFuncs->invalidaterect=_InvalidateRect;
bFuncs->invalidateregion=InvalidateRegion;
bFuncs->forceredraw=ForceRedraw;
bFuncs->getstringidentifier=NPN_GetStringIdentifierProc;
bFuncs->getstringidentifiers=GetStringIdentifiers;
bFuncs->getintidentifier=GetIntIdentifier;
bFuncs->identifierisstring=IdentifierIsString;
bFuncs->utf8fromidentifier=UTF8FromIdentifier;
bFuncs->intfromidentifier=IntFromIdentifier;
bFuncs->createobject=NPN_CreateObjectProc;
bFuncs->retainobject=NPN_RetainObjectProc;
bFuncs->releaseobject=NPN_ReleaseObjectProc;
bFuncs->invoke=NPN_InvokeProc;
bFuncs->invokeDefault=NPN_InvokeDefaultProc;
bFuncs->evaluate=Evaluate;
bFuncs->getproperty=NPN_GetPropertyProc;
bFuncs->setproperty=NPN_SetPropertyProc;
bFuncs->removeproperty=NPN_RemovePropertyProc;
bFuncs->hasproperty=NPN_HasPropertyProc;
bFuncs->hasmethod=NPN_HasMethodProc;
bFuncs->releasevariantvalue=NPN_ReleaseVariantValueProc;
bFuncs->setexception=SetException;
bFuncs->size= sizeof(bFuncs);
// bFuncs->version=(NP_VERSION_MAJOR << 8) + NP_VERSION_MINOR;
bFuncs->version=20;
}
static void destroy(GtkWidget *widget, gpointer data) {
gtk_main_quit ();
}
int main(int argc, char **argv)
{
if(argc < 2) {
printf("[-] Usage: %s <swfuri>\n", argv[0]);
exit(-1);
}
URL = argv[1];
gtk_init (&argc, &argv);
main_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_widget_set_usize (main_window, WINDOW_XSIZE, WINDOW_YSIZE);
g_signal_connect (G_OBJECT (main_window), "destroy", G_CALLBACK (destroy), NULL);
gtk_widget_realize(main_window);
//gtk_window_fullscreen((GtkWindow *)main_window);
gtk_widget_show_all(main_window);
printf("[+] created GTK widget\n");
flash_plugin_handle = loadFlashPluginSo();
loadNPEntryPoints(flash_plugin_handle);
printf("[+] initialized flash plugin entry points\n");
initNPNetscapeFuncs(&browserFuncs);
printf("[+] initialized browser functions\n");
checkError("NP_Initialize", iNP_Initialize(&browserFuncs, &pluginFuncs));
printPluginEntrypoints(&pluginFuncs);
printBrowserEntrypoints(&browserFuncs);
NPWindow *npwin = npwindow_construct(main_window);
printf("[+] created NPWindow widget\n");
NPP_t *instancep = (NPP_t *) malloc(sizeof(NPP_t));
memset(instancep,0,sizeof(sizeof(NPP_t)));
NPP instance = instancep;
NPSavedData* saved = (NPSavedData*) malloc(sizeof(NPSavedData));
memset(saved,0,sizeof(sizeof(NPSavedData)));
stream = npstream_construct();
uint16_t stype;
NPObject object;
char *xargv[]= {"allowscriptaccess", "quality", "wmode"};
char *xargm[]= {"always", "best", "direct"};
checkError("NPN_New", pluginFuncs.newp("application/x-shockwave-flash", instance, NP_EMBED, 3, xargv, xargm, 0));
checkError("NPN_GetValue NPPVpluginScriptableNPObject", pluginFuncs.getvalue(instance, NPPVpluginScriptableNPObject, &object));
checkError("NPN_SetWindow", pluginFuncs.setwindow(instance, npwin));
checkError("NPN_NewStream", pluginFuncs.newstream(instance, "application/x-shockwave-flash", stream, 0, &stype));
FILE *pp;
char buffer[8192];
pp = fopen(argv[1],"rb");
int len;
while((len=fread(buffer, 1, sizeof(buffer), pp)) != 0) {
pluginFuncs.writeready(instance, stream);
pluginFuncs.write(instance, stream, 0, len, buffer);
}
fclose(pp);
checkError("NPN_DestroyStream",pluginFuncs.destroystream(instance, stream, NPRES_DONE));
free(stream);
gtk_main();
checkError("NPN_Destroy",pluginFuncs.destroy(instance, &saved));
checkError("NP_Shutdown", iNP_Shutdown());
dlclose(flash_plugin_handle);
return 0;
}

Related

How to add function for mqtt server authentication

How can I add the functions for username and password to authen mqtt broker.
The original file has not section for authentication. How can I adding function for username and password in authentication mqtt server?
This file has mqtt.h that is sitting parameters (such as hotsname, port, etc.). and I have added parameter for username and password in mqtt.h following this
struct mqtt_handle_s {
// Public members
char *host;
int port;
char *username;
char *password;
char *client_id;
mqtt_on_connect_t on_connect;
mqtt_on_message_t on_message;
// Private members
struct mosquitto *client;
char *topic_list;
size_t topic_size;
};
and then how can I adding the function for running that parameter to using in mqtt server authentication?
the main code is following..
#mqtt.c full code.
#if defined(_WIN32)
#include <windows.h>
#endif
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include "app_log.h"
#include "mqtt.h"
// Check if libmosquitto version is at least 1.5.7
#if LIBMOSQUITTO_VERSION_NUMBER < 1005007
#warning Untested libmosquitto version!
#endif
#define QOS 1
#define KEEPALIVE_INTERVAL_SEC 30
#define LOOP_TIMEOUT_MS 1
#define LOG_MASK MOSQ_LOG_NONE
static void mqtt_on_connect(struct mosquitto *mosq, void *obj, int rc);
static void mqtt_on_disconnect(struct mosquitto *mosq, void *obj, int rc);
static void mqtt_on_message(struct mosquitto *mosq, void *obj, const struct mosquitto_message *message);
static void mqtt_on_log(struct mosquitto *mosq, void *obj, int level, const char *str);
static const char * mqtt_err2str(int rc);
mqtt_status_t mqtt_init(mqtt_handle_t *handle)
{
mqtt_status_t ret = MQTT_SUCCESS;
int rc = MOSQ_ERR_ERRNO; // return code if mosquitto_new() fails
struct mosquitto *mosq;
mosquitto_lib_init();
mosq = mosquitto_new(handle->client_id, true, handle);
if (mosq != NULL) {
mosquitto_connect_callback_set(mosq, mqtt_on_connect);
mosquitto_disconnect_callback_set(mosq, mqtt_on_disconnect);
mosquitto_message_callback_set(mosq, mqtt_on_message);
mosquitto_log_callback_set(mosq, mqtt_on_log);
rc = mosquitto_connect(mosq, handle->host, handle->port, KEEPALIVE_INTERVAL_SEC);
}
if (rc != MOSQ_ERR_SUCCESS) {
app_log("MQTT init failed: '%s'\n", mqtt_err2str(rc));
ret = MQTT_ERROR_CONNECT;
handle->client = NULL;
if (mosq != NULL) {
mosquitto_destroy(mosq);
}
} else {
handle->client = mosq;
}
handle->topic_list = NULL;
handle->topic_size = 0;
return ret;
}
mqtt_status_t mqtt_publish(mqtt_handle_t *handle, const char *topic, const char *payload)
{
mqtt_status_t ret = MQTT_SUCCESS;
int rc;
int mid;
if (handle->client != NULL) {
rc = mosquitto_publish(handle->client, &mid, topic, strlen(payload), payload, QOS, false);
if (rc != MOSQ_ERR_SUCCESS) {
app_log("MQTT publish attempt failed: '%s'\n", mqtt_err2str(rc));
ret = MQTT_ERROR_PUBLISH;
}
} else {
ret = MQTT_ERROR_PUBLISH;
}
return ret;
}
mqtt_status_t mqtt_step(mqtt_handle_t *handle)
{
mqtt_status_t ret = MQTT_SUCCESS;
int rc;
if (handle->client != NULL) {
rc = mosquitto_loop(handle->client, LOOP_TIMEOUT_MS, 1);
if (rc != MOSQ_ERR_SUCCESS) {
app_log("MQTT loop failed: '%s'\n", mqtt_err2str(rc));
ret = MQTT_ERROR_STEP;
}
} else {
ret = MQTT_ERROR_STEP;
}
return ret;
}
mqtt_status_t mqtt_subscribe(mqtt_handle_t *handle, const char *topic)
{
mqtt_status_t ret = MQTT_SUCCESS;
int rc;
size_t topic_size;
if (handle->client != NULL) {
// Try to subscribe to topic.
rc = mosquitto_subscribe(handle->client, NULL, topic, QOS);
if ((rc != MOSQ_ERR_SUCCESS) && (rc != MOSQ_ERR_NO_CONN)) {
app_log("MQTT subscribe attempt failed to topic '%s': '%s'\n", topic, mqtt_err2str(rc));
ret = MQTT_ERROR_SUBSCRIBE;
}
// Append topic to topic list.
topic_size = strlen(topic) + 1;
handle->topic_list = realloc(handle->topic_list, handle->topic_size + topic_size);
if (handle->topic_list == NULL) {
app_log("MQTT failed to append topic to topic list.\n");
ret = MQTT_ERROR_SUBSCRIBE;
} else {
strcpy(&handle->topic_list[handle->topic_size], topic);
handle->topic_size += topic_size;
}
} else {
ret = MQTT_ERROR_SUBSCRIBE;
}
return ret;
}
mqtt_status_t mqtt_deinit(mqtt_handle_t *handle)
{
int rc;
if (handle->client != NULL) {
rc = mosquitto_disconnect(handle->client);
if (rc != MOSQ_ERR_SUCCESS) {
app_log("MQTT failed to disconnect: '%s', continue deinit.\n", mqtt_err2str(rc));
}
mosquitto_destroy(handle->client);
mosquitto_lib_cleanup();
if (handle->topic_list != NULL) {
free(handle->topic_list);
}
}
return MQTT_SUCCESS;
}
static void mqtt_on_connect(struct mosquitto *mosq, void *obj, int rc)
{
mqtt_handle_t *handle = (mqtt_handle_t *)obj;
size_t topic_start = 0;
char *topic;
int ret = MOSQ_ERR_SUCCESS;
app_log("MQTT connect status '%s'\n", mosquitto_connack_string(rc));
if (rc == 0) {
if (handle->on_connect != NULL) {
handle->on_connect(handle);
}
while (topic_start < handle->topic_size) {
topic = &handle->topic_list[topic_start];
ret = mosquitto_subscribe(mosq, NULL, topic, QOS);
topic_start += strlen(topic) + 1;
if (ret != MOSQ_ERR_SUCCESS) {
app_log("MQTT subscribe attempt failed to topic '%s': '%s'\n", topic, mqtt_err2str(ret));
}
}
}
}
static void mqtt_on_disconnect(struct mosquitto *mosq, void *obj, int rc)
{
int ret;
app_log("MQTT disconnected with reason '%d'\n", rc);
if (rc != 0) {
ret = mosquitto_reconnect(mosq);
app_log("MQTT reconnection attempt with status '%s'\n", mqtt_err2str(ret));
}
}
static void mqtt_on_message(struct mosquitto *mosq, void *obj, const struct mosquitto_message *message)
{
mqtt_handle_t *handle = (mqtt_handle_t *)obj;
char *payload;
if (handle->on_message != NULL) {
payload = malloc(message->payloadlen + 1);
if (NULL == payload) {
app_log("MQTT failed to allocate payload buffer.\n");
} else {
memcpy(payload, message->payload, message->payloadlen);
// Make sure that payload is NULL terminated.
payload[message->payloadlen] = 0;
handle->on_message(handle, message->topic, payload);
free(payload);
}
}
}
static void mqtt_on_log(struct mosquitto *mosq, void *obj, int level, const char *str)
{
if (level & LOG_MASK) {
app_log("MQTT log (%d): %s\n", level, str);
}
}
#if defined(_WIN32)
static const char * mqtt_err2str(int rc)
{
char *ret = NULL;
static char err_str[256];
if (MOSQ_ERR_ERRNO == rc) {
// Make sure to have a default output if FormatMessage fails
// or if error code is not available in errno.
strncpy(err_str, "Unknown system error", sizeof(err_str));
if (errno != 0) {
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, // dwFlags
NULL, // lpSource
errno, // dwMessageId
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // dwLanguageId
err_str, // lpBuffer
sizeof(err_str), // nSize
NULL); // Arguments
}
// Make sure that err_str is NULL terminated.
err_str[sizeof(err_str) - 1] = 0;
ret = err_str;
} else {
ret = (char *)mosquitto_strerror(rc);
}
return ret;
}
#else
static const char * mqtt_err2str(int rc)
{
return (MOSQ_ERR_ERRNO == rc) ? strerror(errno) : mosquitto_strerror(rc);
}
#endif // _WIN32

Programmatically change VersionInfo of a foreign DLL

I am trying to programmatically change the VersionInfo attributes of a DLL file. I used this article as reference.
#include <iostream>
#include <stdio.h>
#include <windows.h>
int main(int argc, char** argv) {
LPCTSTR lpszFile = "E:\\_test\\rand_test\\test.dll";
DWORD dwHandle,
dwSize;
struct {
WORD wLanguage;
WORD wCodePage;
} *lpTranslate;
// determine the size of the resource information
dwSize = GetFileVersionInfoSize(lpszFile, &dwHandle);
if (0 < dwSize)
{
unsigned char* lpBuffer = (unsigned char*) malloc(dwSize);
// Get whole VersionInfo resource/structure
GetFileVersionInfo(lpszFile, 0, dwSize, lpBuffer);
char strSubBlock[37]; // fits "\\StringFileInfo\\xxxxxxxx\\CompanyName\0"
LPTSTR pValueBuffer;
HANDLE hResource = BeginUpdateResource(lpszFile, FALSE);
if (NULL != hResource)
{
UINT uTemp;
// get the language information
if (!VerQueryValue(lpBuffer, "\\VarFileInfo\\Translation", (LPVOID *) &lpTranslate, &uTemp) != FALSE)
{
printf("Error 1\n");
return 1;
}
sprintf(strSubBlock, "\\StringFileInfo\\%04x%04x\\CompanyName", lpTranslate->wLanguage, lpTranslate->wCodePage);
if (!VerQueryValue(lpBuffer, (LPTSTR) ((LPCTSTR) strSubBlock), (LPVOID *) &pValueBuffer, &uTemp)) {
printf("Error 2\n");
return 1;
}
// PROBLEM!!!
// (pValueBuffer-lpBuffer) is 0x438 (longer than the Versioninfo resource!) but should be 0xB8
// so, pValueBuffer does not point to the actual company name.
ZeroMemory(pValueBuffer, strlen(pValueBuffer) * sizeof(TCHAR));
strcpy(pValueBuffer, "My Company, Inc."); // String may only become smaller or equal, never bigger than strlen(pValueBuffer)
if (UpdateResource(hResource,
RT_VERSION,
MAKEINTRESOURCE(VS_VERSION_INFO),
lpTranslate->wLanguage, // or 0
lpBuffer,
dwSize) != FALSE)
{
EndUpdateResource(hResource, FALSE);
}
}
free(lpBuffer);
}
return 0;
}
I think I have understood everything the code does. The plan is to read the Versioninfo block, then find the position where e.g. the CompanyName lies using VerQueryValue, then change the data, and then write it back using UpdateResource.
But there is a problem: VerQueryValue should output the position where the CompanyName string lies. But instead, it gives a pointer location, which is a few hundred bytes away, so it points somewhere outside the VersionInfo structure.
What am I doing wrong and how can I make it work?
(Also, does anybody know if there is a more elegant way to do this task, maybe even remove the limitation that the string has to be smaller or equal to the original?)
version resource this is serialized tree. if you want modify it - you need deserialize it to tree structure in memory, modify node, and serialize to new memory.
despite in msdn defined several Version Information Structures, really all it have common format
struct RsrcHeader
{
WORD wLength;
WORD wValueLength;
WORD wType;
WCHAR szKey[];
// aligned on 4*n
// BYTE Value[wValueLength]; // if (wType == 0)
// or
// WCHAR Value[wValueLength]; // if (wType == 1)
// every element aligned on 4*n
// RsrcHeader childs[];
};
so possible write common parse and serialize procedures
#if DBG
#define DBG_OPT(x) _CRT_UNPARENTHESIZE(x)
#else
#define DBG_OPT(x)
#endif
class RsrcNode
{
struct RsrcHeader
{
WORD wLength;
WORD wValueLength;
WORD wType;
WCHAR szKey[];
};
C_ASSERT(sizeof(RsrcHeader) == 6);
RsrcNode* _first, *_next;
PCWSTR _name;
const void* _pvValue;
ULONG _cbValue;
WORD _wValueLength;
WORD _wType;
DBG_OPT((PCSTR _prefix)); // only for debug output
public:
bool ParseResourse(PVOID buf, ULONG size, ULONG* pLength, PCSTR prefix);
RsrcNode(DBG_OPT((PCSTR prefix = "")))
: _next(0), _first(0) DBG_OPT((, _prefix(prefix)))
{
}
~RsrcNode();
bool IsStringValue() const
{
return _wType;
}
const void* getValue(ULONG& cb)
{
cb = _cbValue;
return _pvValue;
}
void setValue(const void* pv, ULONG cb)
{
_pvValue = pv, _cbValue = cb;
_wValueLength = (WORD)(_wType ? cb / sizeof(WCHAR) : cb);
}
RsrcNode* find(const PCWSTR strings[], ULONG n);
ULONG GetSize() const;
PVOID Store(PVOID buf, ULONG* pcb) const;
};
bool RsrcNode::ParseResourse(PVOID buf, ULONG size, ULONG* pLength, PCSTR prefix)
{
union {
PVOID pv;
RsrcHeader* ph;
ULONG_PTR up;
PCWSTR sz;
};
pv = buf;
if (size < sizeof(RsrcHeader) || (up & 3))
{
return false;
}
WORD wType = ph->wType;
ULONG wValueLength = ph->wValueLength, wLength = ph->wLength;
ULONG cbValue = 0;
switch (wType)
{
case 1:
cbValue = wValueLength * sizeof(WCHAR);
break;
case 0:
cbValue = wValueLength;
break;
default:
return false;
}
*pLength = wLength;
if (wLength > size || wLength < sizeof(RsrcHeader) || cbValue >= (wLength -= sizeof(RsrcHeader)))
{
return false;
}
wLength -= cbValue;
sz = ph->szKey, _name = sz;
do
{
if (wLength < sizeof(WCHAR))
{
return false;
}
wLength -= sizeof(WCHAR);
} while (*sz++);
DbgPrint("%s%S {\n", prefix, _name);
if (up & 3)
{
if (wLength < 2)
{
return false;
}
up += 2, wLength -= 2;
}
_wType = wType, _wValueLength = (WORD)wValueLength, _cbValue = cbValue, _pvValue = pv;
if (wValueLength && wType)
{
if (sz[wValueLength - 1])
{
return false;
}
DbgPrint("%s\t%S\n", prefix, sz);
}
if (wLength)
{
if (!*--prefix) return false;
up += wValueLength;
do
{
if (up & 3)
{
if (wLength < 2)
{
return false;
}
up += 2;
if (!(wLength -= 2))
{
break;
}
}
if (RsrcNode* node = new RsrcNode(DBG_OPT((prefix))))
{
node->_next = _first, _first = node;
if (node->ParseResourse(ph, wLength, &size, prefix))
{
continue;
}
}
return false;
} while (up += size, wLength -= size);
prefix++;
}
DbgPrint("%s}\n", prefix);
return true;
}
RsrcNode::~RsrcNode()
{
if (RsrcNode* next = _first)
{
do
{
RsrcNode* cur = next;
next = next->_next;
delete cur;
} while (next);
}
DBG_OPT((DbgPrint("%s%S\n", _prefix, _name)));
}
RsrcNode* RsrcNode::find(const PCWSTR strings[], ULONG n)
{
PCWSTR str = *strings++;
if (!str || !wcscmp(str, _name))
{
if (!--n)
{
return this;
}
if (RsrcNode* next = _first)
{
do
{
if (RsrcNode* p = next->find(strings, n))
{
return p;
}
} while (next = next->_next);
}
}
return 0;
}
ULONG RsrcNode::GetSize() const
{
ULONG size = sizeof(RsrcHeader) + (1 + (ULONG)wcslen(_name)) * sizeof(WCHAR);
if (_cbValue)
{
size = ((size + 3) & ~3) + _cbValue;
}
if (RsrcNode* next = _first)
{
do
{
size = ((size + 3) & ~3) + next->GetSize();
} while (next = next->_next);
}
return size;
}
PVOID RsrcNode::Store(PVOID buf, ULONG* pcb) const
{
union {
RsrcHeader* ph;
ULONG_PTR up;
PVOID pv;
};
pv = buf;
ph->wType = _wType;
ph->wValueLength = _wValueLength;
ULONG size = (1 + (ULONG)wcslen(_name)) * sizeof(WCHAR), cb;
memcpy(ph->szKey, _name, size);
up += (size += sizeof(RsrcHeader));
if (_cbValue)
{
up = (up + 3) & ~3;
memcpy(pv, _pvValue, _cbValue);
up += _cbValue;
size = ((size + 3) & ~3) + _cbValue;
}
if (RsrcNode* next = _first)
{
do
{
up = (up + 3) & ~3;
pv = next->Store(pv, &cb);
size = ((size + 3) & ~3) + cb;
} while (next = next->_next);
}
reinterpret_cast<RsrcHeader*>(buf)->wLength = (WORD)size;
*pcb = size;
return pv;
}
with this helper structure we can update version in next way:
#include "VerHlp.h"
BOOL UpdateVersion(PVOID pvVersion, ULONG cbVersion, PVOID& pvNewVersion, ULONG& cbNewVersion)
{
BOOL fOk = FALSE;
char prefix[16];
memset(prefix, '\t', sizeof(prefix));
prefix[RTL_NUMBER_OF(prefix) - 1] = 0;
*prefix = 0;
if (RsrcNode* node = new RsrcNode)
{
if (node->ParseResourse(pvVersion, cbVersion, &cbVersion, prefix + RTL_NUMBER_OF(prefix) - 1))
{
static const PCWSTR str[] = {
L"VS_VERSION_INFO", L"StringFileInfo", 0, L"CompanyName"
};
if (RsrcNode *p = node->find(str, RTL_NUMBER_OF(str)))
{
if (p->IsStringValue())
{
ULONG cb;
const void* pvCompanyName = p->getValue(cb);
DbgPrint("CompanyName: %S\n", pvCompanyName);
static WCHAR CompanyName[] = L"[ New Company Name ]";
if (cb != sizeof(CompanyName) ||
memcmp(pvCompanyName, CompanyName, sizeof(CompanyName)))
{
p->setValue(CompanyName, sizeof(CompanyName));
cbVersion = node->GetSize();
if (pvVersion = LocalAlloc(0, cbVersion))
{
node->Store(pvVersion, &cbNewVersion);
pvNewVersion = pvVersion;
fOk = TRUE;
}
}
}
}
}
delete node;
}
return fOk;
}
struct EnumVerData
{
HANDLE hUpdate;
BOOL fDiscard;
};
BOOL CALLBACK EnumResLangProc(HMODULE hModule,
PCWSTR lpszType,
PCWSTR lpszName,
WORD wIDLanguage,
EnumVerData* Ctx
)
{
if (HRSRC hResInfo = FindResourceExW(hModule, lpszType, lpszName, wIDLanguage))
{
if (HGLOBAL hg = LoadResource(hModule, hResInfo))
{
if (ULONG size = SizeofResource(hModule, hResInfo))
{
if (PVOID pv = LockResource(hg))
{
if (UpdateVersion(pv, size, pv, size))
{
if (UpdateResource(Ctx->hUpdate, lpszType, lpszName, wIDLanguage, pv, size))
{
Ctx->fDiscard = FALSE;
}
LocalFree(pv);
}
}
}
}
}
return TRUE;
}
ULONG UpdateVersion(PCWSTR FileName)
{
ULONG dwError = NOERROR;
EnumVerData ctx;
if (ctx.hUpdate = BeginUpdateResource(FileName, FALSE))
{
ctx.fDiscard = TRUE;
if (HMODULE hmod = LoadLibraryExW(FileName, 0, LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE))
{
if (!EnumResourceLanguages(hmod, RT_VERSION,
MAKEINTRESOURCE(VS_VERSION_INFO),
(ENUMRESLANGPROCW)EnumResLangProc, (LONG_PTR)&ctx))
{
dwError = GetLastError();
}
FreeLibrary(hmod);
}
else
{
dwError = GetLastError();
}
if (!dwError && !EndUpdateResourceW(ctx.hUpdate, ctx.fDiscard))
{
dwError = GetLastError();
}
}
else
{
dwError = GetLastError();
}
return dwError;
}

OpenSSL bad hostname lookup Windows C

I am trying to get the SSL/TLS client with OpenSSL from here: https://wiki.openssl.org/index.php/SSL/TLS_Client to build and run in visual studio.
I have it successfully building in visual studio, but it won't run successfully.
Currently it will run to res = BIO_do_connect(web); andssl_err = ERR_get_error(); eventually failing at the following if (!(1 == res)) the console output is bad hostname lookup
I've looked around to try and find some solution, but nothing seems effective.
The H file I'm using is pretty much the same as the one at the openssl.org. with the exception of the addition of
typedef struct {
int status_code;
char *reason;
char *content;
} HttpResponse;
This is pretty much my first run in C, I've done Java before, so if someone has any insight, that would be great. Or if they can point to an example of an https post request for Windows in C.
#include "openssl-bio-fetch.h"
#include "corecrt_wstdio.h"
#ifndef HEADER_X509_H
#include <openssl/x509.h>
/* openssl/x509.h ends up #include-ing this file at about the only
* appropriate moment. */
#endif
int verify_callback(int preverify, X509_STORE_CTX* x509_ctx);
void init_openssl_library(void);
void print_cn_name(const char* label, X509_NAME* const name);
void print_san_name(const char* label, X509* const cert);
void print_error_string(unsigned long err, const char* const label);
const char* const PREFERRED_CIPHERS = "HIGH:!aNULL:!kRSA:!SRP:!PSK:!CAMELLIA:!RC4:!MD5:!DSS";
#if 0
const char* const PREFERRED_CIPHERS = "kEECDH:kEDH:kRSA:AESGCM:AES256:AES128:3DES:SHA256:SHA84:SHA1:!aNULL:!eNULL:!EXP:!LOW:!MEDIUM!ADH:!AECDH";
#endif
#if 0
const char* const PREFERRED_CIPHERS = NULL;
#endif
#if 0
const char* PREFERRED_CIPHERS =
/* TLS 1.2 only */
"ECDHE-ECDSA-AES256-GCM-SHA384:"
"ECDHE-RSA-AES256-GCM-SHA384:"
"ECDHE-ECDSA-AES128-GCM-SHA256:"
"ECDHE-RSA-AES128-GCM-SHA256:"
/* TLS 1.2 only */
"DHE-DSS-AES256-GCM-SHA384:"
"DHE-RSA-AES256-GCM-SHA384:"
"DHE-DSS-AES128-GCM-SHA256:"
"DHE-RSA-AES128-GCM-SHA256:"
/* TLS 1.0 only */
"DHE-DSS-AES256-SHA:"
"DHE-RSA-AES256-SHA:"
"DHE-DSS-AES128-SHA:"
"DHE-RSA-AES128-SHA:"
/* SSL 3.0 and TLS 1.0 */
"EDH-DSS-DES-CBC3-SHA:"
"EDH-RSA-DES-CBC3-SHA:"
"DH-DSS-DES-CBC3-SHA:"
"DH-RSA-DES-CBC3-SHA";
#endif
void add_char_header(char *current, char *key, char *value)
{
strcat(current, "\r\n");
strcat(current, key);
strcat(current, ": ");
strcat(current, value);
}
void add_int_header(char *current, char *key, int value)
{
char *buffer = malloc(5);
sprintf(buffer, "%d", value);
strcat(current, "\r\n");
strcat(current, key);
strcat(current, ": ");
strcat(current, buffer);
free(buffer);
}
void parse_http_response(char *resp, HttpResponse *response)
{
response.reason = "";
response.content = "";
}
char * buildRequest(char *request) {
size_t size;
size = strlen("{\"client_ip\":\"10.20.30.40\"}");
strcpy(request, "{\"client_ip\":\"10.20.30.40\"}");
printf("pks-368\n");
return request;
}
int
main(int ac, char **av)
{
char *request = malloc(225);
buildRequest(request);
HttpResponse response;
response.reason = calloc(1, 64);
response.content = calloc(1, 10 * 1024);
response.status_code = 0;
int a = openssl_fetch(request, &response);
fprintf(stderr, "C %d", response.status_code);
fprintf(stderr, "A %s", response.content);
fprintf(stderr, "B %s", response.reason);
printf("Paused");
}
int openssl_fetch(char *request, HttpResponse *response)
{
char *HOST_NAME = "google.com";
char *HOST_PORT = "443";
char *hostname = calloc(1, 100);
strcpy(hostname, HOST_NAME);
strcat(hostname, ":");
strcat(hostname, HOST_PORT);
long res = 1;
int ret = 1;
unsigned long ssl_err = 0;
SSL_CTX* ctx = NULL;
BIO *web = NULL, *out = NULL;
SSL *ssl = NULL;
do {
init_openssl_library();
const SSL_METHOD* method = SSLv23_method();
ssl_err = ERR_get_error();
if (!(NULL != method))
{
print_error_string(ssl_err, "SSLv23_method");
break; /* failed */
}
ctx = SSL_CTX_new(method);
ssl_err = ERR_get_error();
if (!(ctx != NULL))
{
print_error_string(ssl_err, "SSL_CTX_new");
break; /* failed */
}
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, verify_callback);
SSL_CTX_set_verify_depth(ctx, 5);
const long flags = SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_COMPRESSION;
long old_opts = SSL_CTX_set_options(ctx, flags);
UNUSED(old_opts);
const char *file_loc = "C:\\Users\\$USER\\Desktop\\trusted-roots.pem";
res = SSL_CTX_load_verify_locations(ctx, file_loc, NULL);
ssl_err = ERR_get_error();
if (!(1 == res))
{
fprintf(stderr, "SSL_CTX_load_verify_locations -- [%s]\n", ssl_err);
}
web = BIO_new_ssl_connect(ctx);
ssl_err = ERR_get_error();
if (!(web != NULL))
{
print_error_string(ssl_err, "BIO_new_ssl_connect");
break; /* failed */
}
res = BIO_set_conn_hostname(web, hostname);
ssl_err = ERR_get_error();
if (!(1 == res))
{
print_error_string(ssl_err, "BIO_set_conn_hostname");
break; /* failed */
}
BIO_get_ssl(web, &ssl);
ssl_err = ERR_get_error();
if (!(ssl != NULL))
{
print_error_string(ssl_err, "BIO_get_ssl");
break; /* failed */
}
res = SSL_set_cipher_list(ssl, PREFERRED_CIPHERS);
ssl_err = ERR_get_error();
if (!(1 == res))
{
print_error_string(ssl_err, "SSL_set_cipher_list");
break; /* failed */
}
res = SSL_set_tlsext_host_name(ssl, HOST_NAME);
ssl_err = ERR_get_error();
if (!(1 == res))
{
print_error_string(ssl_err, "SSL_set_tlsext_host_name");
}
out = BIO_new_fp(stdout, BIO_NOCLOSE);
ssl_err = ERR_get_error();
if (!(NULL != out))
{
print_error_string(ssl_err, "BIO_new_fp");
break; /* failed */
}
res = BIO_do_connect(web);
ssl_err = ERR_get_error();
if (!(1 == res))
{
print_error_string(ssl_err, "BIO_do_connect");
break; /* failed */
}
res = BIO_do_handshake(web);
ssl_err = ERR_get_error();
if (!(1 == res))
{
print_error_string(ssl_err, "BIO_do_handshake");
break; /* failed */
}
X509* cert = SSL_get_peer_certificate(ssl);
if (cert) { X509_free(cert); } /* Free immediately */
if (NULL == cert)
{
print_error_string(X509_V_ERR_APPLICATION_VERIFICATION, "SSL_get_peer_certificate");
break; /* failed */
}
res = SSL_get_verify_result(ssl);
if (!(X509_V_OK == res))
{
print_error_string((unsigned long)res, "SSL_get_verify_results");
break; /* failed */
}
char message[2048];
strcpy(message, "POST ");
strcat(message, HOST_RESOURCE);
strcat(message, " HTTP/1.1 ");
add_char_header(message, "Host", HOST_NAME);
add_char_header(message, "Connection", "close");
add_char_header(message, "Accept", "*/*");
add_int_header(message, "Content-Length", (int)strlen(request));
strcat(message, "\r\n\r\n");
strcat(message, request);
BIO_puts(web, message);
char buff[6144] = { 0 };
int len = 0;
do {
len = BIO_read(web, buff, sizeof(buff));
} while (len > 0 || BIO_should_retry(web));
ret = 0;
parse_http_response(buff, response);
free(hostname);
} while (0);
if (out)
BIO_free(out);
if (web != NULL)
BIO_free_all(web);
if (NULL != ctx)
SSL_CTX_free(ctx);
return ret;
}
void init_openssl_library(void)
{
(void)SSL_library_init();
SSL_load_error_strings();
#if defined (OPENSSL_THREADS)
// fprintf(stdout, "Warning: thread locking is not implemented\n");
#endif
}
void print_cn_name(const char* label, X509_NAME* const name)
{
int idx = -1, success = 0;
unsigned char *utf8 = NULL;
do
{
if (!name) break; /* failed */
idx = X509_NAME_get_index_by_NID(name, NID_commonName, -1);
if (!(idx > -1)) break; /* failed */
X509_NAME_ENTRY* entry = X509_NAME_get_entry(name, idx);
if (!entry) break; /* failed */
ASN1_STRING* data = X509_NAME_ENTRY_get_data(entry);
if (!data) break; /* failed */
int length = ASN1_STRING_to_UTF8(&utf8, data);
if (!utf8 || !(length > 0)) break; /* failed */
fprintf(stdout, " %s: %s\n", label, utf8);
success = 1;
} while (0);
if (utf8)
OPENSSL_free(utf8);
if (!success)
fprintf(stdout, " %s: <not available>\n", label);
}
void print_san_name(const char* label, X509* const cert)
{
int success = 0;
GENERAL_NAMES* names = NULL;
unsigned char* utf8 = NULL;
do
{
if (!cert) break; /* failed */
names = X509_get_ext_d2i(cert, NID_subject_alt_name, 0, 0);
if (!names) break;
int i = 0, count = sk_GENERAL_NAME_num(names);
if (!count) break; /* failed */
for (i = 0; i < count; ++i)
{
GENERAL_NAME* entry = sk_GENERAL_NAME_value(names, i);
if (!entry) continue;
if (GEN_DNS == entry->type)
{
int len1 = 0, len2 = -1;
len1 = ASN1_STRING_to_UTF8(&utf8, entry->d.dNSName);
if (utf8) {
len2 = (int)strlen((const char*)utf8);
}
if (len1 != len2) {
fprintf(stderr, " Strlen and ASN1_STRING size do not match (embedded null?): %d vs %d\n", len2, len1);
}
if (utf8 && len1 && len2 && (len1 == len2)) {
fprintf(stdout, " %s: %s\n", label, utf8);
success = 1;
}
if (utf8) {
OPENSSL_free(utf8), utf8 = NULL;
}
}
else
{
fprintf(stderr, " Unknown GENERAL_NAME type: %d\n", entry->type);
}
}
} while (0);
if (names)
GENERAL_NAMES_free(names);
if (utf8)
OPENSSL_free(utf8);
if (!success)
fprintf(stdout, " %s: <not available>\n", label);
}
int verify_callback(int preverify, X509_STORE_CTX* x509_ctx)
{
int depth = X509_STORE_CTX_get_error_depth(x509_ctx);
int err = X509_STORE_CTX_get_error(x509_ctx);
if (depth == 0) {
}
if (preverify == 0)
{
if (err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY)
fprintf(stdout, " Error = X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY\n");
else if (err == X509_V_ERR_CERT_UNTRUSTED)
fprintf(stdout, " Error = X509_V_ERR_CERT_UNTRUSTED\n");
else if (err == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN)
fprintf(stdout, " Error = X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN\n");
else if (err == X509_V_ERR_CERT_NOT_YET_VALID)
fprintf(stdout, " Error = X509_V_ERR_CERT_NOT_YET_VALID\n");
else if (err == X509_V_ERR_CERT_HAS_EXPIRED)
fprintf(stdout, " Error = X509_V_ERR_CERT_HAS_EXPIRED\n");
else if (err == X509_V_OK)
fprintf(stdout, " Error = X509_V_OK\n");
else
fprintf(stdout, " Error = %d\n", err);
}
#if !defined(NDEBUG)
return 1;
#else
return preverify;
#endif
}
void print_error_string(unsigned long err, const char* const label)
{
const char* const str = ERR_reason_error_string(err);
if (str)
fprintf(stderr, "%s\n", str);
else
fprintf(stderr, "%s failed: %lu (0x%lx)\n", label, err, err);
}

Directive name "SCGIMount" is not recognized

I am trying to get a simple django app up on Http Server. The server is IBM Websphere Application Server. I have successfully compiled mod_scgi.c to the iseries.
I proceeded to create a server and edit the configuration file with the following code:
#Load the mod_scgi module
LoadModule scgi_module /qsys.lib/qgpl.lib/mod_scgi.srvpgm
# Set up location to be server by an SCGI server process
SCGIMount /dynamic 127.0.0.1:8080
This produces an error on the configuration file: "Directive name "SCGIMount" is not recognized."
I am not sure how to proceed from here. Also, the mod_scgi.c file has been modified to allow it to be compiled to the iseries. I have provided the code below:
/* mod_scgi.c
*
* Apache 2 implementation of the SCGI protocol.
*
*/
#define MOD_SCGI_VERSION "1.14"
#define SCGI_PROTOCOL_VERSION "1"
#include "ap_config.h"
#include "apr_version.h"
#include "apr_lib.h"
#include "apr_strings.h"
#include "httpd.h"
#include "http_config.h"
#include "http_core.h"
#include "http_request.h"
#include "http_log.h"
#include "http_protocol.h"
#include "util_script.h"
#ifdef AS400
#include <strings.h>
#endif
#define DEFAULT_TIMEOUT 60 /* default socket timeout */
#define UNSET 0
#define ENABLED 1
#define DISABLED 2
#if APR_MAJOR_VERSION == 0
#define apr_socket_send apr_send
#define GET_PORT(port, addr) apr_sockaddr_port_get(&(port), addr)
#define CREATE_SOCKET(sock, family, pool) \
apr_socket_create(sock, family, SOCK_STREAM, pool)
#else
#define GET_PORT(port, addr) ((port) = (addr)->port)
#define CREATE_SOCKET(sock, family, pool) \
apr_socket_create(sock, family, SOCK_STREAM, APR_PROTO_TCP, pool)
#endif
typedef struct {
char *path;
char *addr;
apr_port_t port;
} mount_entry;
/*
* Configuration record. Used per-directory configuration data.
*/
typedef struct {
mount_entry mount;
int enabled; /* mod_scgi is enabled from this directory */
int timeout;
} scgi_cfg;
/* Server level configuration */
typedef struct {
apr_array_header_t *mounts;
int timeout;
} scgi_server_cfg;
/*
* Declare ourselves so the configuration routines can find and know us.
* We'll fill it in at the end of the module.
*/
module AP_MODULE_DECLARE_DATA scgi_module;
/*
* Locate our directory configuration record for the current request.
*/
static scgi_cfg *
our_dconfig(request_rec *r)
{
return (scgi_cfg *) ap_get_module_config(r->per_dir_config, &scgi_module);
}
static scgi_server_cfg *our_sconfig(server_rec *s)
{
return (scgi_server_cfg *) ap_get_module_config(s->module_config,
&scgi_module);
}
static int
mount_entry_matches(const char *url, const char *prefix,
const char **path_info)
{
int i;
for (i=0; prefix[i] != '\0'; i++) {
if (url[i] == '\0' || url[i] != prefix[i])
return 0;
}
if (url[i] == '\0' || url[i] == '/') {
*path_info = url + i;
return 1;
}
return 0;
}
static int scgi_translate(request_rec *r)
{
scgi_cfg *cfg = our_dconfig(r);
if (cfg->enabled == DISABLED) {
return DECLINED;
}
if (cfg->mount.addr != UNSET) {
ap_assert(cfg->mount.port != UNSET);
r->handler = "scgi-handler";
r->filename = r->uri;
return OK;
}
else {
int i;
scgi_server_cfg *scfg = our_sconfig(r->server);
mount_entry *entries = (mount_entry *) scfg->mounts->elts;
for (i = 0; i < scfg->mounts->nelts; ++i) {
const char *path_info;
mount_entry *mount = &entries[i];
if (mount_entry_matches(r->uri, mount->path, &path_info)) {
r->handler = "scgi-handler";
r->path_info = apr_pstrdup(r->pool, path_info);
r->filename = r->uri;
ap_set_module_config(r->request_config, &scgi_module, mount);
return OK;
}
}
}
return DECLINED;
}
static int scgi_map_location(request_rec *r)
{
if (r->handler && strcmp(r->handler, "scgi-handler") == 0) {
return OK; /* We don't want directory walk. */
}
return DECLINED;
}
static void log_err(const char *file, int line, request_rec *r,
apr_status_t status, const char *msg)
{
ap_log_rerror(file, line, APLOG_ERR, status, r, "scgi: %s", msg);
}
static void log_debug(const char *file, int line, request_rec *r, const
char *msg)
{
ap_log_rerror(file, line, APLOG_DEBUG, APR_SUCCESS, r, msg);
}
static char *http2env(apr_pool_t *p, const char *name)
{
char *env_name = apr_pstrcat(p, "HTTP_", name, NULL);
char *cp;
for (cp = env_name + 5; *cp != 0; cp++) {
if (*cp == '-') {
*cp = '_';
}
else {
*cp = apr_toupper(*cp);
}
}
return env_name;
}
static char *lookup_name(apr_table_t *t, const char *name)
{
const apr_array_header_t *hdrs_arr = apr_table_elts(t);
apr_table_entry_t *hdrs = (apr_table_entry_t *) hdrs_arr->elts;
int i;
for (i = 0; i < hdrs_arr->nelts; ++i) {
if (hdrs[i].key == NULL)
continue;
if (strcasecmp(hdrs[i].key, name) == 0)
return hdrs[i].val;
}
return NULL;
}
static char *lookup_header(request_rec *r, const char *name)
{
return lookup_name(r->headers_in, name);
}
static void add_header(apr_table_t *t, const char *name, const char *value)
{
if (name != NULL && value != NULL)
apr_table_addn(t, name, value);
}
static int find_path_info(const char *uri, const char *path_info)
{
int n;
n = strlen(uri) - strlen(path_info);
ap_assert(n >= 0);
return n;
}
/* This code is a duplicate of what's in util_script.c. We can't use
* r->unparsed_uri because it gets changed if there was a redirect. */
static char *original_uri(request_rec *r)
{
char *first, *last;
if (r->the_request == NULL) {
return (char *) apr_pcalloc(r->pool, 1);
}
first = r->the_request; /* use the request-line */
while (*first && !apr_isspace(*first)) {
++first; /* skip over the method */
}
while (apr_isspace(*first)) {
++first; /* and the space(s) */
}
last = first;
while (*last && !apr_isspace(*last)) {
++last; /* end at next whitespace */
}
return apr_pstrmemdup(r->pool, first, last - first);
}
/* buffered socket implementation (buckets are overkill) */
#define BUFFER_SIZE 8000
struct sockbuff {
apr_socket_t *sock;
char buf[BUFFER_SIZE];
int used;
};
static void binit(struct sockbuff *s, apr_socket_t *sock)
{
s->sock = sock;
s->used = 0;
}
static apr_status_t sendall(apr_socket_t *sock, char *buf, apr_size_t len)
{
apr_status_t rv;
apr_size_t n;
while (len > 0) {
n = len;
if ((rv = apr_socket_send(sock, buf, &n))) return rv;
buf += n;
len -= n;
}
return APR_SUCCESS;
}
static apr_status_t bflush(struct sockbuff *s)
{
apr_status_t rv;
ap_assert(s->used >= 0 && s->used <= BUFFER_SIZE);
if (s->used) {
if ((rv = sendall(s->sock, s->buf, s->used))) return rv;
s->used = 0;
}
return APR_SUCCESS;
}
static apr_status_t bwrite(struct sockbuff *s, char *buf, apr_size_t len)
{
apr_status_t rv;
if (len >= BUFFER_SIZE - s->used) {
if ((rv = bflush(s))) return rv;
while (len >= BUFFER_SIZE) {
if ((rv = sendall(s->sock, buf, BUFFER_SIZE))) return rv;
buf += BUFFER_SIZE;
len -= BUFFER_SIZE;
}
}
if (len > 0) {
ap_assert(len < BUFFER_SIZE - s->used);
memcpy(s->buf + s->used, buf, len);
s->used += len;
}
return APR_SUCCESS;
}
static apr_status_t bputs(struct sockbuff *s, char *buf)
{
return bwrite(s, buf, strlen(buf));
}
static apr_status_t bputc(struct sockbuff *s, char c)
{
char buf[1];
buf[0] = c;
return bwrite(s, buf, 1);
}
static apr_status_t
send_headers(request_rec *r, struct sockbuff *s)
{
/* headers to send */
apr_table_t *t;
const apr_array_header_t *hdrs_arr, *env_arr;
apr_table_entry_t *hdrs, *env;
unsigned long int n = 0;
char *buf;
int i;
apr_status_t rv = 0;
apr_port_t port = 0;
GET_PORT(port, r->connection->remote_addr);
log_debug(APLOG_MARK,r, "sending headers");
t = apr_table_make(r->pool, 40);
if (!t)
return APR_ENOMEM;
/* CONTENT_LENGTH must come first and always be present */
buf = lookup_header(r, "Content-Length");
if (buf == NULL)
buf = "0";
add_header(t, "CONTENT_LENGTH", buf);
add_header(t, "SCGI", SCGI_PROTOCOL_VERSION);
add_header(t, "SERVER_SOFTWARE", ap_get_server_version());
add_header(t, "SERVER_PROTOCOL", r->protocol);
add_header(t, "SERVER_NAME", ap_get_server_name(r));
add_header(t, "SERVER_ADMIN", r->server->server_admin);
add_header(t, "SERVER_ADDR", r->connection->local_ip);
add_header(t, "SERVER_PORT", apr_psprintf(r->pool, "%u",
ap_get_server_port(r)));
add_header(t, "REMOTE_ADDR", r->connection->remote_ip);
add_header(t, "REMOTE_PORT", apr_psprintf(r->pool, "%d", port));
add_header(t, "REMOTE_USER", r->user);
add_header(t, "REQUEST_METHOD", r->method);
add_header(t, "REQUEST_URI", original_uri(r));
add_header(t, "QUERY_STRING", r->args ? r->args : "");
if (r->path_info) {
int path_info_start = find_path_info(r->uri, r->path_info);
add_header(t, "SCRIPT_NAME", apr_pstrndup(r->pool, r->uri,
path_info_start));
add_header(t, "PATH_INFO", r->path_info);
}
else {
/* skip PATH_INFO, don't know it */
add_header(t, "SCRIPT_NAME", r->uri);
}
add_header(t, "CONTENT_TYPE", lookup_header(r, "Content-type"));
add_header(t, "DOCUMENT_ROOT", ap_document_root(r));
/* HTTP headers */
hdrs_arr = apr_table_elts(r->headers_in);
hdrs = (apr_table_entry_t *) hdrs_arr->elts;
for (i = 0; i < hdrs_arr->nelts; ++i) {
if (hdrs[i].key) {
add_header(t, http2env(r->pool, hdrs[i].key), hdrs[i].val);
}
}
/* environment variables */
env_arr = apr_table_elts(r->subprocess_env);
env = (apr_table_entry_t*) env_arr->elts;
for (i = 0; i < env_arr->nelts; ++i) {
add_header(t, env[i].key, env[i].val);
}
hdrs_arr = apr_table_elts(t);
hdrs = (apr_table_entry_t*) hdrs_arr->elts;
/* calculate length of header data (including nulls) */
for (i = 0; i < hdrs_arr->nelts; ++i) {
n += strlen(hdrs[i].key) + 1;
n += strlen(hdrs[i].val) + 1;
}
buf = apr_psprintf(r->pool, "%lu:", n);
if (!buf)
return APR_ENOMEM;
rv = bputs(s, buf);
if (rv)
return rv;
for (i = 0; i < hdrs_arr->nelts; ++i) {
rv = bputs(s, hdrs[i].key);
if (rv) return rv;
rv = bputc(s, '\0');
if (rv) return rv;
rv = bputs(s, hdrs[i].val);
if (rv) return rv;
rv = bputc(s, '\0');
if (rv) return rv;
}
rv = bputc(s, ',');
if (rv)
return rv;
return APR_SUCCESS;
}
static apr_status_t send_request_body(request_rec *r, struct sockbuff *s)
{
if (ap_should_client_block(r)) {
char buf[BUFFER_SIZE];
apr_status_t rv;
apr_off_t len;
while ((len = ap_get_client_block(r, buf, sizeof buf)) > 0) {
if ((rv = bwrite(s, buf, len))) return rv;
}
if (len == -1)
return HTTP_INTERNAL_SERVER_ERROR; /* what to return? */
}
return APR_SUCCESS;
}
#define CONFIG_VALUE(value, fallback) ((value) != UNSET ? (value) : (fallback))
static apr_status_t
open_socket(apr_socket_t **sock, request_rec *r)
{
int timeout;
int retries = 4;
int sleeptime = 1;
apr_status_t rv;
apr_sockaddr_t *sockaddr;
scgi_server_cfg *scfg = our_sconfig(r->server);
scgi_cfg *cfg = our_dconfig(r);
mount_entry *m = (mount_entry *) ap_get_module_config(r->request_config,
&scgi_module);
if (!m) {
m = &cfg->mount;
}
timeout = CONFIG_VALUE(cfg->timeout, CONFIG_VALUE(scfg->timeout,
DEFAULT_TIMEOUT));
rv = apr_sockaddr_info_get(&sockaddr,
CONFIG_VALUE(m->addr, "localhost"),
APR_UNSPEC,
CONFIG_VALUE(m->port, 4000),
0,
r->pool);
if (rv) {
log_err(APLOG_MARK, r, rv, "apr_sockaddr_info_get() error");
return rv;
}
restart:
*sock = NULL;
rv = CREATE_SOCKET(sock, sockaddr->family, r->pool);
if (rv) {
log_err(APLOG_MARK, r, rv, "apr_socket_create() error");
return rv;
}
rv = apr_socket_timeout_set(*sock, apr_time_from_sec(timeout));
if (rv) {
log_err(APLOG_MARK, r, rv, "apr_socket_timeout_set() error");
return rv;
}
rv = apr_socket_connect(*sock, sockaddr);
if (rv) {
apr_socket_close(*sock);
if ((APR_STATUS_IS_ECONNREFUSED(rv) |
APR_STATUS_IS_EINPROGRESS(rv)) && retries > 0) {
/* server may be temporarily down, retry */
ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_DEBUG, rv, r,
"scgi: connection failed, retrying");
apr_sleep(apr_time_from_sec(sleeptime));
--retries;
sleeptime *= 2;
goto restart;
}
log_err(APLOG_MARK, r, rv, "scgi: can't connect to server");
return rv;
}
#ifdef APR_TCP_NODELAY
/* disable Nagle, we don't send small packets */
apr_socket_opt_set(*sock, APR_TCP_NODELAY, 1);
#endif
return APR_SUCCESS;
}
#ifdef AS400
static int getsfunc_BRIGADE(char *buf, int len, void *arg)
{
apr_bucket_brigade *bb = (apr_bucket_brigade *)arg;
const char *dst_end = buf + len - 1; /* leave room for terminating null */
char *dst = buf;
apr_bucket *e = APR_BRIGADE_FIRST(bb);
apr_status_t rv;
int done = 0;
while ((dst < dst_end) && !done && e != APR_BRIGADE_SENTINEL(bb)
&& !APR_BUCKET_IS_EOS(e)) {
const char *bucket_data;
apr_size_t bucket_data_len;
const char *src;
const char *src_end;
apr_bucket * next;
rv = apr_bucket_read(e, &bucket_data, &bucket_data_len,
APR_BLOCK_READ);
if (rv != APR_SUCCESS || (bucket_data_len == 0)) {
*dst = '\0';
return APR_STATUS_IS_TIMEUP(rv) ? -1 : 0;
}
src = bucket_data;
src_end = bucket_data + bucket_data_len;
while ((src < src_end) && (dst < dst_end) && !done) {
if (*src == '\n') {
done = 1;
}
else if (*src != '\r') {
*dst++ = *src;
}
src++;
}
if (src < src_end) {
apr_bucket_split(e, src - bucket_data);
}
next = APR_BUCKET_NEXT(e);
APR_BUCKET_REMOVE(e);
apr_bucket_destroy(e);
e = next;
}
*dst = 0;
return done;
}
#endif
static int scgi_handler(request_rec *r)
{
apr_status_t rv = 0;
int http_status = 0;
struct sockbuff s;
apr_socket_t *sock;
apr_bucket_brigade *bb = NULL;
apr_bucket *b = NULL;
const char *location;
if (strcmp(r->handler, "scgi-handler"))
return DECLINED;
http_status = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR);
if (http_status != OK)
return http_status;
log_debug(APLOG_MARK, r, "connecting to server");
rv = open_socket(&sock, r);
if (rv) {
return HTTP_INTERNAL_SERVER_ERROR;
}
binit(&s, sock);
rv = send_headers(r, &s);
if (rv) {
log_err(APLOG_MARK, r, rv, "error sending request headers");
return HTTP_INTERNAL_SERVER_ERROR;
}
rv = send_request_body(r, &s);
if (rv) {
log_err(APLOG_MARK, r, rv, "error sending request body");
return HTTP_INTERNAL_SERVER_ERROR;
}
rv = bflush(&s);
if (rv) {
log_err(APLOG_MARK, r, rv, "error sending request");
return HTTP_INTERNAL_SERVER_ERROR;
}
log_debug(APLOG_MARK, r, "reading response headers");
bb = apr_brigade_create(r->connection->pool, r->connection->bucket_alloc);
b = apr_bucket_socket_create(sock, r->connection->bucket_alloc);
APR_BRIGADE_INSERT_TAIL(bb, b);
b = apr_bucket_eos_create(r->connection->bucket_alloc);
APR_BRIGADE_INSERT_TAIL(bb, b);
#ifdef AS400
rv = ap_scan_script_header_err_core(r, NULL, getsfunc_BRIGADE, bb);
#else
rv = ap_scan_script_header_err_brigade(r, bb, NULL);
#endif
if (rv) {
if (rv == HTTP_INTERNAL_SERVER_ERROR) {
log_err(APLOG_MARK, r, rv, "error reading response headers");
}
else {
/* Work around an Apache bug whereby the returned status is
* ignored and status_line is used instead. This bug is
* present at least in 2.0.54.
*/
r->status_line = NULL;
}
apr_brigade_destroy(bb);
return rv;
}
location = apr_table_get(r->headers_out, "Location");
if (location && location[0] == '/' &&
((r->status == HTTP_OK) || ap_is_HTTP_REDIRECT(r->status))) {
apr_brigade_destroy(bb);
/* Internal redirect -- fake-up a pseudo-request */
r->status = HTTP_OK;
/* This redirect needs to be a GET no matter what the original
* method was.
*/
r->method = apr_pstrdup(r->pool, "GET");
r->method_number = M_GET;
/* We already read the message body (if any), so don't allow
* the redirected request to think it has one. We can ignore
* Transfer-Encoding, since we used REQUEST_CHUNKED_ERROR.
*/
apr_table_unset(r->headers_in, "Content-Length");
ap_internal_redirect_handler(location, r);
return OK;
}
rv = ap_pass_brigade(r->output_filters, bb);
if (rv) {
log_err(APLOG_MARK, r, rv, "ap_pass_brigade()");
return HTTP_INTERNAL_SERVER_ERROR;
}
return OK;
}
static int scgi_init(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp,
server_rec *base_server)
{
ap_add_version_component(p, "mod_scgi/" MOD_SCGI_VERSION);
return OK;
}
static void *
create_dir_config(apr_pool_t *p, char *dirspec)
{
scgi_cfg *cfg = apr_pcalloc(p, sizeof(scgi_cfg));
cfg->enabled = UNSET;
cfg->mount.addr = UNSET;
cfg->mount.port = UNSET;
cfg->timeout = UNSET;
return cfg;
}
#define MERGE(b, n, a) (n->a == UNSET ? b->a : n->a)
static void *
merge_dir_config(apr_pool_t *p, void *basev, void *newv)
{
scgi_cfg* cfg = apr_pcalloc(p, sizeof(scgi_cfg));
scgi_cfg* base = basev;
scgi_cfg* new = newv;
cfg->enabled = MERGE(base, new, enabled);
cfg->mount.addr = MERGE(base, new, mount.addr);
cfg->mount.port = MERGE(base, new, mount.port);
cfg->timeout = MERGE(base, new, timeout);
return cfg;
}
static void *
create_server_config(apr_pool_t *p, server_rec *s)
{
scgi_server_cfg *c =
(scgi_server_cfg *) apr_pcalloc(p, sizeof(scgi_server_cfg));
c->mounts = apr_array_make(p, 20, sizeof(mount_entry));
c->timeout = UNSET;
return c;
}
static void *
merge_server_config(apr_pool_t *p, void *basev, void *overridesv)
{
scgi_server_cfg *c = (scgi_server_cfg *)
apr_pcalloc(p, sizeof(scgi_server_cfg));
scgi_server_cfg *base = (scgi_server_cfg *) basev;
scgi_server_cfg *overrides = (scgi_server_cfg *) overridesv;
c->mounts = apr_array_append(p, overrides->mounts, base->mounts);
c->timeout = MERGE(base, overrides, timeout);
return c;
}
static const char *
cmd_mount(cmd_parms *cmd, void *dummy, const char *path, const char *addr)
{
int n;
apr_status_t rv;
char *scope_id = NULL; /* A ip6 parameter - not used here. */
scgi_server_cfg *scfg = our_sconfig(cmd->server);
mount_entry *new = apr_array_push(scfg->mounts);
n = strlen(path);
while (n > 0 && path[n-1] == '/') {
n--; /* strip trailing slashes */
}
new->path = apr_pstrndup(cmd->pool, path, n);
rv = apr_parse_addr_port(&new->addr, &scope_id, &new->port, addr,
cmd->pool);
if (rv)
return "error parsing address:port string";
return NULL;
}
static const char *
cmd_server(cmd_parms *cmd, void *pcfg, const char *addr_and_port)
{
apr_status_t rv;
scgi_cfg *cfg = pcfg;
char *scope_id = NULL; /* A ip6 parameter - not used here. */
if (cmd->path == NULL)
return "not a server command";
rv = apr_parse_addr_port(&cfg->mount.addr, &scope_id, &cfg->mount.port,
addr_and_port, cmd->pool);
if (rv)
return "error parsing address:port string";
return NULL;
}
static const char *
cmd_handler(cmd_parms* cmd, void* pcfg, int flag)
{
scgi_cfg *cfg = pcfg;
if (cmd->path == NULL) /* server command */
return "not a server command";
if (flag)
cfg->enabled = ENABLED;
else
cfg->enabled = DISABLED;
return NULL;
}
static const char *
cmd_timeout(cmd_parms *cmd, void* pcfg, const char *strtimeout)
{
scgi_cfg *dcfg = pcfg;
int timeout = atoi(strtimeout);
if (cmd->path == NULL) {
scgi_server_cfg *scfg = our_sconfig(cmd->server);
scfg->timeout = timeout;
}
else {
dcfg->timeout = timeout;
}
return NULL;
}
static const command_rec scgi_cmds[] =
{
AP_INIT_TAKE2("SCGIMount", cmd_mount, NULL, RSRC_CONF,
"path prefix and address of SCGI server"),
AP_INIT_TAKE1("SCGIServer", cmd_server, NULL, ACCESS_CONF,
"Address and port of an SCGI server (e.g. localhost:4000)"),
AP_INIT_FLAG( "SCGIHandler", cmd_handler, NULL, ACCESS_CONF,
"On or Off to enable or disable the SCGI handler"),
AP_INIT_TAKE1("SCGIServerTimeout", cmd_timeout, NULL, ACCESS_CONF|RSRC_CONF,
"Timeout (in seconds) for communication with the SCGI server."),
{NULL}
};
static void scgi_register_hooks(apr_pool_t *p)
{
ap_hook_post_config(scgi_init, NULL, NULL, APR_HOOK_MIDDLE);
ap_hook_handler(scgi_handler, NULL, NULL, APR_HOOK_MIDDLE);
ap_hook_translate_name(scgi_translate, NULL, NULL, APR_HOOK_LAST);
ap_hook_map_to_storage(scgi_map_location, NULL, NULL, APR_HOOK_FIRST);
}
/* Dispatch list for API hooks */
module AP_MODULE_DECLARE_DATA scgi_module = {
STANDARD20_MODULE_STUFF,
create_dir_config, /* create per-dir config structs */
merge_dir_config, /* merge per-dir config structs */
create_server_config, /* create per-server config structs */
merge_server_config, /* merge per-server config structs */
scgi_cmds, /* table of config file commands */
scgi_register_hooks, /* register hooks */
};
UPDATE to the UPDATE:
I have narrowed down the problem to the following Error Message MCH3601:
MCH3601 Escape 40 06/05/15 15:41:10.884937 MOD_SCGI QGPL *STMT MOD_SCGI QGPL *STMT
From module . . . . . . . . : MOD_SCGI
From procedure . . . . . . : our_dconfig
Statement . . . . . . . . . : 1
To module . . . . . . . . . : MOD_SCGI
To procedure . . . . . . . : our_dconfig
Statement . . . . . . . . . : 1
Thread . . . . : 00000039
Message . . . . : Pointer not set for location referenced.
Cause . . . . . : A pointer was used, either directly or as a basing
pointer, that has not been set to an address.
It looks like the web server is actually Apache, not WAS. What does the Apache log say?
Is the Apache user profile authorised to the mod_scgi service program, and to the library QGPL?

DBusWatch and DBusTimeout examples

I need to write an application in C for asynchronous sending and reading messages on the dbus message queue. I've read that for doing that I should use the DBusWatch and DBusTimeout objects that the connection provides, but I cannot find an example of how to use these anywhere...
For the moment i use dbus_connection_read_write_dispatch in order to do that, but I've read that it is not recommended for asynchronous operations, so I'll have to switch to creating my own main loop and using it...
The closest answer to my question was this one:
http://lists.freedesktop.org/archives/dbus/2007-September/008555.html ,
suggesting to look through the dbus-gmain.c file, which I did, but all I found there was a call of the dbus_connection_set_watch_functions and dbus_connection_set_timeout_functions, with other functions as parameters - should I overwrite those functions? Should I use them as they are?
I simply cannot figure out how to use these in order to read and write something to the dbus message queue...
Any idea would be more than welcome...
Here's something I wrote some time ago. I removed application specific code, you should just add your snippets where you handle DBus messages meant for your application and that should be it.
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <dbus/dbus.h>
struct dbus_ctx {
DBusConnection *conn;
struct event_base *evbase;
struct event dispatch_ev;
void *extra;
};
static void dispatch(int fd, short ev, void *x)
{
struct dbus_ctx *ctx = x;
DBusConnection *c = ctx->conn;
logger(LOG_DEBUG "dispatching\n");
while (dbus_connection_get_dispatch_status(c) == DBUS_DISPATCH_DATA_REMAINS)
dbus_connection_dispatch(c);
}
static void handle_dispatch_status(DBusConnection *c,
DBusDispatchStatus status, void *data)
{
struct dbus_ctx *ctx = data;
logger(LOG_DEBUG "new dbus dispatch status: %d\n", status);
if (status == DBUS_DISPATCH_DATA_REMAINS) {
struct timeval tv = {
.tv_sec = 0,
.tv_usec = 0,
};
event_add(&ctx->dispatch_ev, &tv);
}
}
static void handle_watch(int fd, short events, void *x)
{
struct dbus_ctx *ctx = x;
struct DBusWatch *watch = ctx->extra;
unsigned int flags = 0;
if (events & EV_READ)
flags |= DBUS_WATCH_READABLE;
if (events & EV_WRITE)
flags |= DBUS_WATCH_WRITABLE;
/*if (events & HUP)
flags |= DBUS_WATCH_HANGUP;
if (events & ERR)
flags |= DBUS_WATCH_ERROR;*/
logger(LOG_DEBUG "got dbus watch event fd=%d watch=%p ev=%d\n",
fd, watch, events);
if (dbus_watch_handle(watch, flags) == FALSE)
logger(LOG_ERROR "dbus_watch_handle() failed\n");
handle_dispatch_status(ctx->conn, DBUS_DISPATCH_DATA_REMAINS, ctx);
}
static dbus_bool_t add_watch(DBusWatch *w, void *data)
{
if (!dbus_watch_get_enabled(w))
return TRUE;
struct dbus_ctx *ctx = data;
ctx->extra = w;
int fd = dbus_watch_get_unix_fd(w);
unsigned int flags = dbus_watch_get_flags(w);
short cond = EV_PERSIST;
if (flags & DBUS_WATCH_READABLE)
cond |= EV_READ;
if (flags & DBUS_WATCH_WRITABLE)
cond |= EV_WRITE;
struct event *event = event_new(ctx->evbase, fd, cond, handle_watch, ctx);
if (!event)
return FALSE;
event_add(event, NULL);
dbus_watch_set_data(w, event, NULL);
logger(LOG_DEBUG "added dbus watch fd=%d watch=%p cond=%d\n", fd, w, cond);
return TRUE;
}
static void remove_watch(DBusWatch *w, void *data)
{
struct event *event = dbus_watch_get_data(w);
if (event)
event_free(event);
dbus_watch_set_data(w, NULL, NULL);
logger(LOG_DEBUG "removed dbus watch watch=%p\n", w);
}
static void toggle_watch(DBusWatch *w, void *data)
{
logger(LOG_DEBUG "toggling dbus watch watch=%p\n", w);
if (dbus_watch_get_enabled(w))
add_watch(w, data);
else
remove_watch(w, data);
}
static void handle_timeout(int fd, short ev, void *x)
{
struct dbus_ctx *ctx = x;
DBusTimeout *t = ctx->extra;
logger(LOG_DEBUG "got dbus handle timeout event %p\n", t);
dbus_timeout_handle(t);
}
static dbus_bool_t add_timeout(DBusTimeout *t, void *data)
{
struct dbus_ctx *ctx = data;
if (!dbus_timeout_get_enabled(t))
return TRUE;
logger(LOG_DEBUG "adding timeout %p\n", t);
struct event *event = event_new(ctx->evbase, -1, EV_TIMEOUT|EV_PERSIST,
handle_timeout, t);
if (!event) {
logger(LOG_ERROR "failed to allocate new event for timeout\n");
return FALSE;
}
int ms = dbus_timeout_get_interval(t);
struct timeval tv = {
.tv_sec = ms / 1000,
.tv_usec = (ms % 1000) * 1000,
};
event_add(event, &tv);
dbus_timeout_set_data(t, event, NULL);
return TRUE;
}
static void remove_timeout(DBusTimeout *t, void *data)
{
struct event *event = dbus_timeout_get_data(t);
logger(LOG_DEBUG "removing timeout %p\n", t);
event_free(event);
dbus_timeout_set_data(t, NULL, NULL);
}
static void toggle_timeout(DBusTimeout *t, void *data)
{
logger(LOG_DEBUG "toggling timeout %p\n", t);
if (dbus_timeout_get_enabled(t))
add_timeout(t, data);
else
remove_timeout(t, data);
}
static DBusHandlerResult handle_nameownerchanged(DBusMessage *message,
void *data)
{
struct dbus_ctx *ctx = data;
char *name, *old, *new;
if (dbus_message_get_args(message, NULL,
DBUS_TYPE_STRING, &name,
DBUS_TYPE_STRING, &old,
DBUS_TYPE_STRING, &new,
DBUS_TYPE_INVALID) == FALSE) {
logger(LOG_ERROR "spurious NameOwnerChanged signal\n");
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
logger(LOG_DEBUG "dbus NameOwnerChanged %s -> %s\n", old, new);
if (new[0] != '\0')
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
/* XXX handle disconnecting clients */
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
static DBusHandlerResult msg_filter(DBusConnection *connection,
DBusMessage *message, void *data)
{
if (dbus_message_is_signal(message, DBUS_INTERFACE_DBUS,
"NameOwnerChanged"))
return handle_nameownerchanged(message, data);
logger(LOG_DEBUG "got dbus message %d %s -> %s %s/%s/%s %s\n",
dbus_message_get_type(message),
dbus_message_get_sender(message),
dbus_message_get_destination(message),
dbus_message_get_path(message),
dbus_message_get_interface(message),
dbus_message_get_member(message),
dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_ERROR ?
dbus_message_get_error_name(message) : "");
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
static void unregister_func(DBusConnection *connection, void *data)
{
}
static DBusHandlerResult message_func(DBusConnection *connection,
DBusMessage *message, void *data)
{
struct dbus_ctx *ctx = data;
logger(LOG_DEBUG "got dbus message sent to %s %s %s\n",
dbus_message_get_destination(message),
dbus_message_get_interface(message),
dbus_message_get_path(message));
/* XXX handle DBus message */
return DBUS_HANDLER_RESULT_HANDLED;
}
static DBusObjectPathVTable dbus_vtable = {
.unregister_function = unregister_func,
.message_function = message_func,
};
struct dbus_ctx *dbus_init(struct event_base *eb)
{
DBusConnection *conn = NULL;
struct dbus_ctx *ctx = calloc(1, sizeof(struct dbus_ctx));
if (!ctx) {
logger_perror("can't allocate dbus_ctx\n");
goto out;
}
conn = dbus_bus_get_private(DBUS_BUS_SESSION, NULL);
if (conn == NULL) {
logger(LOG_ERROR "failed to get bus\n");
goto out;
}
dbus_connection_set_exit_on_disconnect(conn, FALSE);
ctx->conn = conn;
ctx->evbase = eb;
event_assign(&ctx->dispatch_ev, eb, -1, EV_TIMEOUT, dispatch, ctx);
if (!dbus_connection_set_watch_functions(conn, add_watch, remove_watch,
toggle_watch, ctx, NULL)) {
logger(LOG_ERROR "dbus_connection_set_watch_functions() failed\n");
goto out;
}
if (!dbus_connection_set_timeout_functions(conn, add_timeout,
remove_timeout, toggle_timeout,
ctx, NULL)) {
logger(LOG_ERROR "dbus_connection_set_timeout_functions() failed\n");
goto out;
}
if (dbus_connection_add_filter(conn, msg_filter, ctx, NULL) == FALSE) {
logger(LOG_ERROR "dbus_connection_add_filter() failed\n");
goto out;
}
dbus_connection_set_dispatch_status_function(conn, handle_dispatch_status,
ctx, NULL);
char match[256];
snprintf(match,
sizeof(match),
"type='signal',interface='%s',member='NameOwnerChanged'",
DBUS_INTERFACE_DBUS);
DBusError error;
dbus_error_init(&error);
dbus_bus_add_match(conn, match, &error);
if (dbus_error_is_set(&error)) {
logger(LOG_ERROR "dbus_bus_add_match() %s failed: %s\n",
"NameOwnerChanged", error.message);
dbus_error_free(&error);
goto out;
}
snprintf(match,
sizeof(match),
"type='signal',interface='%s',member='%s'",
GNP_IPC_INTERFACE, GNP_IPC_SIGNAL_DELIVER_SA);
dbus_error_init(&error);
dbus_bus_add_match(conn, match, &error);
if (dbus_error_is_set(&error)) {
logger(LOG_ERROR "dbus_bus_add_match() %s failed: %s\n",
GNP_IPC_SIGNAL_DELIVER_SA, error.message);
dbus_error_free(&error);
goto out;
}
if (dbus_connection_register_object_path(conn, GNP_IPC_PATH, &dbus_vtable,
ctx) != TRUE) {
logger(LOG_ERROR "failed to register object path\n");
goto out;
}
return ctx;
out:
if (conn) {
dbus_connection_close(conn);
dbus_connection_unref(conn);
}
if (ctx)
free(ctx);
return NULL;
}
void dbus_close(struct dbus_ctx *ctx)
{
if (ctx && ctx->conn) {
dbus_connection_flush(ctx->conn);
dbus_connection_close(ctx->conn);
dbus_connection_unref(ctx->conn);
event_del(&ctx->dispatch_ev);
}
if (ctx)
free(ctx);
}
Based on Idx's code and examples from other sources (mainly example by Matthew Johnson and Will Ware), here is a synchronous event handling sample with a mainloop on select(). Just run in two terminals to see how events are passing around.
#define _GNU_SOURCE /* for pipe2 in unistd.h */
#include <dbus/dbus.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h> /* for pipe2 */
#include <errno.h>
#include <fcntl.h> /* for O_NONBLOCK */
#include <sys/time.h> /* for gettimeofday */
#include <limits.h> /* for INT_MAX */
/* ------------------------------------------------------------ */
/* chgevt:
* when watch/timeout changes, pass a chgevt via a pipe to
* the selector loop so the loop will return from select() and
* react to the dbus change immediately. only need this when a new
* watch/timeout is added or enabled. when a watch/timeout is removed
* or disabled, immediate response is not needed.
*
* when running in single thread because those changes happen only
* in stage 2 of the selector loop, this chgevt path is not necessary.
* if running in multiple threads, e.g. calling dbus sending from
* another thread, then the path would be essential.
*/
/* events */
#define CHGEVT_ADD_WATCH (1)
#define CHGEVT_ADD_TIMEOUT (2)
static int watched_chgevt_fds[2] = {0,0}; /* [0] read, [1] write */
static void watched_chgevt_setup() {
int rc = pipe2(watched_chgevt_fds, O_NONBLOCK);
if ( rc != 0 ) watched_chgevt_fds[0] = watched_chgevt_fds[1] = 0;
}
static void watched_chgevt_send(int evt) {
if ( watched_chgevt_fds[1] ) write(watched_chgevt_fds[1], &evt, 1);
}
static int watched_chgevt_get() {
int rc = 0;
if ( watched_chgevt_fds[0] ) {
if ( (rc = read(watched_chgevt_fds[0], &rc, 1)) < 0 ) {
if ( errno != EAGAIN ) {
perror("watched_chgevt_fds pipe failed");
watched_chgevt_fds[0] = watched_chgevt_fds[1] = 0;
}
rc = 0;
}
}
return rc;
}
/* watch */
static DBusWatch * watched_watch = NULL;
static int watched_rd_fd = 0;
static int watched_wr_fd = 0;
static dbus_bool_t add_watch(DBusWatch *w, void *data)
{
if (!dbus_watch_get_enabled(w))
return TRUE;
int fd = dbus_watch_get_unix_fd(w);
unsigned int flags = dbus_watch_get_flags(w);
int old_rd_fd = watched_rd_fd;
int old_wr_fd = watched_wr_fd;
if (flags & DBUS_WATCH_READABLE)
watched_rd_fd = fd;
if (flags & DBUS_WATCH_WRITABLE)
watched_wr_fd = fd;
watched_watch = w;
printf(" WATCH: add dbus watch fd=%d watch=%p rd_fd=%d/%d wr_fd=%d/%d\n",
fd, w, watched_rd_fd, old_rd_fd, watched_wr_fd, old_wr_fd);
watched_chgevt_send( CHGEVT_ADD_WATCH );
return TRUE;
}
static void remove_watch(DBusWatch *w, void *data)
{
watched_watch = NULL;
watched_rd_fd = 0;
watched_wr_fd = 0;
printf(" WATCH: remove dbus watch watch=%p\n", w);
}
static void toggle_watch(DBusWatch *w, void *data)
{
printf(" WATCH: toggle dbus watch watch=%p\n", w);
if (dbus_watch_get_enabled(w))
add_watch(w, data);
else
remove_watch(w, data);
}
/* timeout */
static DBusTimeout * watched_timeout = NULL;
static struct timeval watched_timeout_start_tv = { 0, 0 };
/* at which timeout is enabled */
static unsigned int watched_timeout_setv = 0; /* set value */
static unsigned int watched_timeout_lastv = 0; /* last trigger */
#define TIMEOUT_MAX_MS ( 1000 * 1000 ) /* 1000 sec */
#define TIMEOUT_MOD_MS ( 8 * TIMEOUT_MAX_MS ) /* 8000 sec */
/* note: last_trigger is 0 to 7999 sec.
* next_timeout is 0 to 8999 sec.
*/
#define TIME_TV_TO_MS(x) /* convert a timeval to 0-to-7999 ms */ \
( (x.tv_sec%(TIMEOUT_MOD_MS/1000))*1000 + \
x.tv_usec/1000 )
static dbus_bool_t add_timeout(DBusTimeout *t, void *data)
{
if (!dbus_timeout_get_enabled(t))
return TRUE;
int ms = dbus_timeout_get_interval(t);
if ( ms < 0 || ms > TIMEOUT_MAX_MS ) {
ms = TIMEOUT_MAX_MS;
if ( ms < 0 || ms > INT_MAX/2-1 ) {
ms = INT_MAX/2-1;
}
}
if ( ms < 1 ) {
ms = 1;
}
struct timeval tnow = {0,0};
gettimeofday(&tnow, NULL);
unsigned int tnowms = TIME_TV_TO_MS(tnow);
printf(" TIMEOUT: add dbus timeout %p value %u ms\n", t, ms);
watched_timeout_start_tv = tnow;
watched_timeout_setv = ms;
watched_timeout_lastv = tnowms;
watched_timeout = t;
watched_chgevt_send( CHGEVT_ADD_TIMEOUT );
return TRUE;
}
static void remove_timeout(DBusTimeout *t, void *data)
{
printf(" TIMEOUT: remove timeout %p\n", t);
watched_timeout = NULL;
struct timeval tv = { .tv_sec = 0, .tv_usec = 0, };
watched_timeout_start_tv = tv;
watched_timeout_setv = 0;
watched_timeout_lastv = 0;
}
static void toggle_timeout(DBusTimeout *t, void *data)
{
printf(" TIMEOUT: toggle timeout %p\n", t);
if (dbus_timeout_get_enabled(t))
add_timeout(t, data);
else
remove_timeout(t, data);
}
/* the selector function */
/* receive */
static int dbus_selector_process_recv(DBusConnection* conn, int iswaiting_rpcreply,
DBusPendingCall** pendingargptr);
/* send rpc request */
static int dbus_selector_process_post_send(DBusConnection* conn, char * param,
DBusPendingCall** pendingargptr);
/* receive rpc reply, called by process_recv() */
static int dbus_selector_process_post_reply(DBusConnection* conn,
DBusPendingCall** pendingargptr );
/* selector */
#include <sys/select.h>
#include <time.h>
static unsigned int lastregtime = 0;
int dbus_selector(char *param, int altsel )
{
DBusConnection* conn;
DBusError err;
int ret = 1; /* default fail */
watched_chgevt_setup();
char * destarray[4] = { "test.selector.server", "test.selector.client",
"test.unknown.user1", "test.unknown.user2" };
char * deststr = destarray[0];
if ( altsel != 0 ) {
deststr = destarray[1];
lastregtime = time(NULL);
}
printf("Accepting method calls and signals\n");
// initialise the error
dbus_error_init(&err);
// connect to the bus and check for errors
conn = dbus_bus_get(DBUS_BUS_SESSION, &err);
if (dbus_error_is_set(&err)) {
fprintf(stderr, "Connection Error (%s)\n", err.message);
dbus_error_free(&err);
}
if (NULL == conn) {
fprintf(stderr, "Connection Null\n");
return ret; /* ret=1 fail */
}
// request our name on the bus and check for errors
ret = dbus_bus_request_name(conn, deststr /* "test.selector.server" */,
DBUS_NAME_FLAG_REPLACE_EXISTING , &err);
if (dbus_error_is_set(&err)) {
fprintf(stderr, "Name Error (%s)\n", err.message);
dbus_error_free(&err);
}
if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER != ret) {
fprintf(stderr, "Not Primary Owner (%d)\n", ret);
return ret; /* ret=1 fail */
}
// add a rule for which messages we want to see
dbus_bus_add_match(conn, "type='signal',interface='test.signal.Type'", &err);
// see signals from the given interface
dbus_connection_flush(conn); /* Note: this would block */
if (dbus_error_is_set(&err)) {
fprintf(stderr, "Match Error (%s)\n", err.message);
return ret; /* ret=1 fail */
}
printf("Match signal rule sent\n");
/* setup watch and timeout */
if (!dbus_connection_set_watch_functions(conn, add_watch, remove_watch,
toggle_watch, NULL, NULL)) {
printf(" ERROR dbus_connection_set_watch_functions() failed\n");
return ret; /* ret=1 fail */
}
if (!dbus_connection_set_timeout_functions(conn, add_timeout,
remove_timeout, toggle_timeout,
NULL, NULL)) {
printf(" ERROR dbus_connection_set_timeout_functions() failed\n");
return ret; /* ret=1 fail */
}
/* the selector loop */
ret = 0; /* default success */
struct timeval local_to_startv = {0,0}; /* timeout saved locally */
DBusPendingCall* pending = NULL; /* keep track of the outstanding rpc call */
while(ret == 0) {
/* the selector loop stage 1, setup for select() call.
* in this stage no dbus watch/timeout change should happen
*/
#define DEFAULT_SELECT_LOOP_MS (5500)
int modified_timeout = 0; /* yes or no */
fd_set rfds, wfds, efds;
struct timeval timeoutval = {
DEFAULT_SELECT_LOOP_MS/1000,
(DEFAULT_SELECT_LOOP_MS%1000)*1000 };
int nfds = 1;
int rc = 0;
printf("\n");
FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&efds);
if ( watched_watch != NULL ) {
if ( watched_rd_fd ) {
FD_SET(watched_rd_fd, &rfds);
FD_SET(watched_rd_fd, &efds);
if ( nfds <= watched_rd_fd ) { nfds = watched_rd_fd + 1; }
printf(" SELECT nfds %d rdfd %d\n", nfds, watched_rd_fd);
}
if ( watched_wr_fd ) {
FD_SET(watched_wr_fd, &wfds);
FD_SET(watched_wr_fd, &efds);
if ( nfds <= watched_wr_fd ) { nfds = watched_wr_fd + 1; }
printf(" SELECT nfds %d wrfd %d\n", nfds, watched_wr_fd);
}
}
if ( watched_chgevt_fds[0] != 0 ) {
FD_SET(watched_chgevt_fds[0], &rfds);
FD_SET(watched_chgevt_fds[0], &efds);
}
if ( watched_timeout != NULL ) {
struct timeval startv = watched_timeout_start_tv;
unsigned int setv = watched_timeout_setv;
unsigned int lastv = watched_timeout_lastv;
struct timeval tnow = {0,0};
unsigned int tnowms = 0;
unsigned int toms = 0;
unsigned int tdiff = 0;
gettimeofday(&tnow, NULL);
tnowms = TIME_TV_TO_MS(tnow);
if ( startv.tv_sec != local_to_startv.tv_sec ||
startv.tv_usec != local_to_startv.tv_sec )
{ /* new timeout */
local_to_startv = startv;
}
if ( lastv > tnowms ) {
tnowms += TIMEOUT_MOD_MS;
}
toms = lastv + setv + 1;
/* add 1 to make up for rounding loss */
if ( toms > tnowms ) {
tdiff = toms - tnowms; /* ms till timeout */
}
if ( tdiff < DEFAULT_SELECT_LOOP_MS ) {
/* revise timeout value */
timeoutval.tv_sec = tdiff/1000;
timeoutval.tv_usec = (tdiff%1000)*1000;
modified_timeout = 1; /* yes */
}
}
if ( modified_timeout ) {
printf(" SELECT with nfds %d ... modified tiemout %lu.%03lu\n",
nfds, timeoutval.tv_sec, timeoutval.tv_usec/1000);
} else {
printf(" SELECT with nfds %d...\n", nfds);
}
rc = select(nfds, &rfds, &wfds, &efds, &timeoutval);
if ( rc < 0 ) {
printf(" SELECT returned error %d\n", rc);
break;
}
/* the selector loop stage 2, dbus operation.
* in this stage dbus watch/timeout could change.
*/
/* check timeout */
if ( watched_timeout != NULL ) {
struct timeval startv = watched_timeout_start_tv;
unsigned int setv = watched_timeout_setv;
unsigned int lastv = watched_timeout_lastv;
struct timeval tnow = {0,0}; unsigned int tnowms = 0, toms = 0;
gettimeofday(&tnow, NULL);
tnowms = TIME_TV_TO_MS(tnow);
if ( startv.tv_sec == local_to_startv.tv_sec &&
startv.tv_usec == local_to_startv.tv_sec )
{ /* same timeout */
if ( lastv > tnowms ) {
tnowms += TIMEOUT_MOD_MS;
}
toms = lastv + setv + 1;
/* add 1 to make up for rounding loss */
if ( toms >= tnowms ) {
watched_timeout_lastv = tnowms%TIMEOUT_MOD_MS;
printf(" HANDLING dbus handle timeout %p\n",
watched_timeout);
dbus_timeout_handle(watched_timeout);
printf(" HANDLING dbus handle timeout %p done\n",
watched_timeout);
}
} /* else if not the same timeout as before select() skip for now */
}
/* self initiated rpc call */
if ( altsel ) {
unsigned int tmnow = time(NULL);
unsigned int tmdiff = tmnow - lastregtime;
if ( tmdiff > 10 ) { /* send a rpc evey 10 seconds */
dbus_selector_process_post_send(conn, param, &pending);
lastregtime = tmnow;
}
}
/* select() returned no event */
if ( rc == 0 ) {
printf(" SELECT returned rc 0 \n");
continue;
}
/* some event happened according to select() */
printf(" SELECT returned rc %d \n", rc);
if ( watched_watch != NULL ) {
if ( watched_rd_fd ) {
if ( FD_ISSET(watched_rd_fd, &rfds) ) {
printf(" HANDLING calls watch_handle\n");
dbus_watch_handle(watched_watch, DBUS_WATCH_READABLE);
printf(" HANDLING calls process_recv\n");
dbus_selector_process_recv(conn, pending==NULL?0:1,
&pending);
printf(" HANDLING done process_recv\n");
}
if ( FD_ISSET(watched_rd_fd, &efds) ) {
printf(" HANDLING EXCEPTION with rd fd %d \n",
watched_rd_fd);
}
}
if ( watched_wr_fd ) {
if ( FD_ISSET(watched_wr_fd, &wfds) ) {
dbus_watch_handle(watched_watch, DBUS_WATCH_WRITABLE);
}
if ( FD_ISSET(watched_wr_fd, &efds) ) {
printf(" HANDLING EXCEPTION with wr fd %d \n",
watched_wr_fd);
}
}
}
/* chgevt pipe */
if ( watched_chgevt_fds[0] != 0 && FD_ISSET(watched_chgevt_fds[0], &rfds) ) {
int chgevt = watched_chgevt_get();
switch (chgevt) {
case CHGEVT_ADD_WATCH:
printf(" HANDLING chgevt 1 consumed \n"); break;
case CHGEVT_ADD_TIMEOUT:
printf(" HANDLING chgevt 2 consumed \n"); break;
default:
printf(" HANDLING chgevt n=%d consumed \n", chgevt); break;
}
}
}
return ret;
}
static int dbus_selector_process_recv(DBusConnection* conn, int iswaiting_rpcreply,
DBusPendingCall** pendingargptr)
{
int ret = 1; /* default fail */
/* remove this call that consumes .1ms because dbus is already read
* by dbus_watch_handle():
* dbus_connection_read_write(conn, 0);
*
* according to dbus_connection_dispatch(): The incoming data buffer
* is filled when the connection reads from its underlying transport
* (such as a socket). Reading usually happens in dbus_watch_handle()
* or dbus_connection_read_write().
*/
DBusDispatchStatus dispatch_rc = dbus_connection_get_dispatch_status(conn);
if ( DBUS_DISPATCH_DATA_REMAINS != dispatch_rc ) {
printf(" ERROR recv no message in queue \n");
}
while( DBUS_DISPATCH_DATA_REMAINS == dispatch_rc ) {
DBusMessage* msg = dbus_connection_borrow_message(conn);
if ( msg == NULL ) {
printf(" ERROR recv pending check FAILED: remains but "
"no message borrowed. \n");
break;
}
int mtype = dbus_message_get_type(msg);
if ( iswaiting_rpcreply &&
( mtype == DBUS_MESSAGE_TYPE_METHOD_RETURN ||
mtype == DBUS_MESSAGE_TYPE_ERROR ) ) {
printf(" RPC REPLY pending check SUCCESS: received rpc reply \n");
dbus_connection_return_message(conn, msg);
dbus_connection_dispatch(conn);
/* dispatch so the received message at the
* head of queue is passed to the pendingcall
*/
dbus_selector_process_post_reply( conn, pendingargptr );
printf(" RPC REPLY pending check SUCCESS: processed rpc reply \n");
} else if ( mtype == DBUS_MESSAGE_TYPE_METHOD_RETURN ) {
printf(" RECV pending check FAILED: received rpc reply \n");
dbus_connection_steal_borrowed_message(conn, msg);
dbus_message_unref(msg);
} else if ( mtype == DBUS_MESSAGE_TYPE_ERROR ) {
printf(" RECV pending check FAILED: received ERROR \n");
dbus_connection_steal_borrowed_message(conn, msg);
dbus_message_unref(msg);
} else if ( mtype == DBUS_MESSAGE_TYPE_SIGNAL ) {
printf(" SIGNAL pending check SUCCESS: received and drop \n");
dbus_connection_steal_borrowed_message(conn, msg);
dbus_message_unref(msg);
} else if ( mtype == DBUS_MESSAGE_TYPE_METHOD_CALL ) {
printf(" RPC RECV check SUCCESS: received rpc call. \n");
dbus_connection_steal_borrowed_message(conn, msg);
DBusMessage* reply = NULL;
do {
/* craft a reply message */
DBusMessageIter args;
dbus_uint32_t serial = 111;
dbus_bool_t stat = TRUE;
dbus_uint32_t retval1 = 555;
const char *strval = "good";
reply = dbus_message_new_method_return(msg);
dbus_message_iter_init_append(reply, &args);
if ( !dbus_message_iter_append_basic(
&args, DBUS_TYPE_BOOLEAN, &stat) ) {
printf(" error rpc reply Out Of Memory!\n");
break;
}
if ( !dbus_message_iter_append_basic(
&args, DBUS_TYPE_UINT32, &retval1) ) {
printf(" error rpc reply Out Of Memory!\n");
break;
}
if ( !dbus_message_iter_append_basic(
&args, DBUS_TYPE_STRING, &strval) ) {
printf(" error rpc reply Out Of Memory!\n");
break;
}
if ( !dbus_connection_send(conn, reply, &serial)) {
printf(" error rpc reply Out Of Memory!\n");
break;
}
dbus_connection_flush(conn);
} while(0);
if ( reply != NULL ) { dbus_message_unref(reply); }
if ( msg != NULL ) { /* msg not consumed */
//dbus_connection_return_message(conn, msg);
dbus_message_unref(msg);
}
ret = 0; /* success */
} else {
printf(" error unknown msg type %d \n", mtype);
}
dispatch_rc = dbus_connection_get_dispatch_status(conn);
}
return ret;
}
static int dbus_selector_process_post_send( DBusConnection* conn, char * param,
DBusPendingCall** pendingargptr)
{ /* mostly a copy of query() */
DBusMessage* msg = NULL;
DBusMessageIter args = {0};
DBusError err = {0};
DBusPendingCall* pending = NULL;
int ret = 0;
* pendingargptr = NULL;
printf("Calling remote method with %s\n", param);
// initialiset the errors
dbus_error_init(&err);
msg = dbus_message_new_method_call(
"test.selector.server", // target for the method call
"/test/method/Object", // object to call on
"test.method.Type", // interface to call on
"Method"); // method name
if (NULL == msg) {
fprintf(stderr, "Message Null\n");
exit(1);
}
// append arguments
dbus_message_iter_init_append(msg, &args);
if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &param)) {
fprintf(stderr, "Out Of Memory!\n");
exit(1);
}
// send message and get a handle for a reply
if (!dbus_connection_send_with_reply (conn, msg, &pending, 300)) {
// -1 is default timeout
fprintf(stderr, "Out Of Memory!\n");
exit(1);
}
if (NULL == pending) {
fprintf(stderr, "Pending Call Null\n");
exit(1);
}
printf("Request Sent\n");
dbus_connection_flush(conn); /* Note: block until write finishes */
printf("Request flushed\n");
// free message
dbus_message_unref(msg);
* pendingargptr = pending;
return ret;
}
static int dbus_selector_process_post_reply( DBusConnection* conn,
DBusPendingCall** pendingargptr )
{
DBusMessage* msg = NULL;
DBusMessageIter args = {0};
dbus_bool_t stat = FALSE;
dbus_uint32_t level = 0;
DBusPendingCall* pending = *pendingargptr;
if ( ! dbus_pending_call_get_completed(pending) ) {
dbus_pending_call_unref(pending);
*pendingargptr = NULL;
fprintf(stderr, " error Reply incomplete\n");
exit(1);
}
// get the reply message
msg = dbus_pending_call_steal_reply(pending);
if (NULL == msg) {
fprintf(stderr, "Reply Null\n");
exit(1);
}
// free the pending message handle
dbus_pending_call_unref(pending);
*pendingargptr = NULL;
/* */
int validerror = 0;
{ int mtype = dbus_message_get_type(msg);
if ( mtype == DBUS_MESSAGE_TYPE_ERROR ) {
fprintf(stderr, " error Reply with a valid error detected!\n");
validerror = 1;
} else if ( mtype != DBUS_MESSAGE_TYPE_METHOD_RETURN ) {
fprintf(stderr, " error Reply not a valid return type!"
" received message type %d\n", mtype);
}
}
// read the parameters
if (!dbus_message_iter_init(msg, &args))
fprintf(stderr, "Message has no arguments!\n");
else if (DBUS_TYPE_BOOLEAN != dbus_message_iter_get_arg_type(&args))
{
fprintf(stderr, "Argument is not boolean!\n");
if (DBUS_TYPE_STRING == dbus_message_iter_get_arg_type(&args) ) {
fprintf(stderr, "Argument 1 is string!\n");
if ( validerror ) {
char * strval = (char*)"<init-unknown>";
dbus_message_iter_get_basic(&args, &strval);
if ( strval != NULL && strnlen(strval, 160) < 160 ) {
printf("RPC reply arg 0 is c%u %s\n", 160, strval);
} else {
printf("RPC reply arg 0 error \n");
}
}
} else if (DBUS_TYPE_UINT32 == dbus_message_iter_get_arg_type(&args) ) {
fprintf(stderr, "Argument 1 is uint32!\n");
} else {
fprintf(stderr, "Argument 1 is not recognized!\n");
}
}
else
dbus_message_iter_get_basic(&args, &stat);
if (!dbus_message_iter_next(&args))
fprintf(stderr, "Message has too few arguments!\n");
else if (DBUS_TYPE_UINT32 != dbus_message_iter_get_arg_type(&args))
fprintf(stderr, "Argument is not int!\n");
else
dbus_message_iter_get_basic(&args, &level);
printf("Got Reply: %d, %d\n", stat, level);
// free reply
dbus_message_unref(msg);
return 0;
}
/* ------------------------------------------------------------ */
int main(int argc, char** argv)
{
if (2 > argc) {
printf ("Syntax: dbus-select-watch [selector|selpost] [<param>]\n");
return 1;
}
char* param = "no cmdline param";
if (3 <= argc && NULL != argv[2]) param = argv[2];
if (0 == strncmp(argv[1], "selector", 20))
dbus_selector(param, 0);
else if (0 == strncmp(argv[1], "selpost", 20))
dbus_selector(param, 1);
else {
printf ("Syntax: dbus-select-watch [selector|selpost] [<param>]\n");
return 1;
}
return 0;
}
I have written an example for implementing main loop for dbus. I have tested it with bluez DBUS API and it works without any problem.
I have removed the bluetooth part of my application. I have used libevent to implement event loop.
Note: It is in C++. You can easily convert it to C programming language.
#include "dbus-ble/libevent.h"
#include <stdlib.h>
#include <errno.h>
#include <event2/event.h>
#include <event2/util.h>
#include <dbus/dbus.h>
struct watch_handler {
struct event *ev;
DBusConnection *dbus_cnx;
DBusWatch *watch;
};
struct timeout_handler {
struct event *ev;
DBusConnection *dbus_cnx;
DBusTimeout *timeout;
};
static struct event_base *ev_base = nullptr;
static void timeout_handler_free(void *data)
{
struct timeout_handler *to_handler = reinterpret_cast<struct timeout_handler *>(data);
if (to_handler == nullptr)
return;
if (to_handler->ev != nullptr) {
event_del(to_handler->ev);
event_free(to_handler->ev);
}
if (to_handler->dbus_cnx != nullptr)
dbus_connection_unref(to_handler->dbus_cnx);
free(to_handler);
}
static void libevent_dispatch_dbus(int fd, short event, void *data)
{
struct timeout_handler *to_handler = reinterpret_cast<struct timeout_handler *>(data);
DBusConnection *dbus_cnx = to_handler->dbus_cnx;
dbus_connection_ref(dbus_cnx);
while (dbus_connection_dispatch(dbus_cnx) == DBUS_DISPATCH_DATA_REMAINS);
dbus_connection_unref(dbus_cnx);
timeout_handler_free(to_handler);
}
static inline void throw_libevent_dispatch_dbus(DBusConnection *dbus_cnx)
{
const struct timeval timeout = {0,0};
struct timeout_handler *to_handler = reinterpret_cast<struct timeout_handler *>(calloc(1, sizeof(struct timeout_handler)));
if (to_handler == nullptr)
return;
to_handler->dbus_cnx = dbus_connection_ref(dbus_cnx);
to_handler->ev = evtimer_new(ev_base, libevent_dispatch_dbus, to_handler);
evtimer_add(to_handler->ev, &timeout);
}
static void watch_handler_dispatch(int fd, short event, void *data)
{
struct watch_handler *io_handler = reinterpret_cast<struct watch_handler *>(data);
DBusDispatchStatus status;
unsigned int flags = 0;
dbus_connection_ref(io_handler->dbus_cnx);
if (evutil_socket_geterror(fd) != 0)
flags |= DBUS_WATCH_ERROR;
if (event & EV_READ)
flags |= DBUS_WATCH_READABLE;
if (event & EV_WRITE)
flags |= DBUS_WATCH_WRITABLE;
dbus_watch_handle(io_handler->watch, flags);
status = dbus_connection_get_dispatch_status(io_handler->dbus_cnx);
if (status == DBUS_DISPATCH_DATA_REMAINS)
throw_libevent_dispatch_dbus(io_handler->dbus_cnx);
dbus_connection_unref(io_handler->dbus_cnx);
}
static void watch_handler_free(void *data)
{
struct watch_handler *io_handler = reinterpret_cast<struct watch_handler *>(data);
if (io_handler == nullptr)
return;
if (io_handler->ev != nullptr) {
event_del(io_handler->ev);
event_free(io_handler->ev);
}
dbus_connection_unref(io_handler->dbus_cnx);
free(io_handler);
}
static dbus_bool_t libevent_dbus_watch_add(DBusWatch *watch, void *data)
{
DBusConnection *dbus_cnx = reinterpret_cast<DBusConnection *>(data);
struct watch_handler *io_handler;
unsigned int flags;
short io_condition;
int io_fd;
if (dbus_watch_get_enabled(watch) == FALSE)
return TRUE;
io_handler = reinterpret_cast<struct watch_handler *>(calloc(1, sizeof(struct watch_handler)));
if (io_handler == nullptr)
return FALSE;
io_handler->dbus_cnx = dbus_connection_ref(dbus_cnx);
io_handler->watch = watch;
dbus_watch_set_data(watch, io_handler, watch_handler_free);
flags = dbus_watch_get_flags(watch);
io_condition = EV_PERSIST;
if (flags & DBUS_WATCH_READABLE)
io_condition |= EV_READ;
if (flags & DBUS_WATCH_WRITABLE)
io_condition |= EV_WRITE;
io_fd = dbus_watch_get_unix_fd(watch);
io_handler->ev = event_new(ev_base, io_fd, io_condition,
watch_handler_dispatch, io_handler);
event_add(io_handler->ev, nullptr);
return TRUE;
}
static void libevent_dbus_watch_remove(DBusWatch *watch, void *data)
{
if (dbus_watch_get_enabled(watch) == TRUE)
return;
dbus_watch_set_data(watch, nullptr, nullptr);
}
static void libevent_dbus_watch_toggled(DBusWatch *watch, void *data)
{
if (dbus_watch_get_enabled(watch) == TRUE)
libevent_dbus_watch_add(watch, data);
else
libevent_dbus_watch_remove(watch, data);
}
static void timeout_handler_dispatch(int fd, short event, void *data)
{
struct timeout_handler *to_handler = reinterpret_cast<struct timeout_handler *>(data);
dbus_timeout_handle(to_handler->timeout);
}
static inline void _set_timer(struct timeval *timer, long int milliseconds)
{
timer->tv_sec = milliseconds / 1000;
timer->tv_usec = (milliseconds % 1000) * 1000;
}
static dbus_bool_t libevent_dbus_timeout_add(DBusTimeout *timeout, void *data)
{
struct timeout_handler *to_handler;
struct timeval timer;
if (dbus_timeout_get_enabled(timeout) == FALSE)
return TRUE;
to_handler = reinterpret_cast<struct timeout_handler *>(calloc(1, sizeof(struct timeout_handler)));
if (to_handler == nullptr)
return FALSE;
dbus_timeout_set_data(timeout, to_handler, timeout_handler_free);
_set_timer(&timer, dbus_timeout_get_interval(timeout));
to_handler->ev = evtimer_new(ev_base, timeout_handler_dispatch, to_handler);
evtimer_add(to_handler->ev, (const struct timeval *) &timer);
return TRUE;
}
static void libevent_dbus_timeout_remove(DBusTimeout *timeout, void *data)
{
dbus_timeout_set_data(timeout, nullptr, nullptr);
}
static void libevent_dbus_timeout_toggled(DBusTimeout *timeout, void *data)
{
if (dbus_timeout_get_enabled(timeout) == TRUE)
libevent_dbus_timeout_add(timeout, data);
else
libevent_dbus_timeout_remove(timeout, data);
}
static void libevent_dbus_dispatch_status(DBusConnection *dbus_cnx,
DBusDispatchStatus new_status, void *data)
{
DBusDispatchStatus status;
if (dbus_connection_get_is_connected(dbus_cnx) == FALSE)
return;
status = dbus_connection_get_dispatch_status(dbus_cnx);
if (status == DBUS_DISPATCH_DATA_REMAINS)
throw_libevent_dispatch_dbus(dbus_cnx);
}
static dbus_bool_t setup_dbus_in_libevent_mainloop(DBusConnection *dbus_cnx)
{
DBusDispatchStatus status;
if (dbus_connection_set_watch_functions(dbus_cnx,
libevent_dbus_watch_add, libevent_dbus_watch_remove,
libevent_dbus_watch_toggled, dbus_cnx, nullptr) == FALSE)
return FALSE;
if (dbus_connection_set_timeout_functions(dbus_cnx,
libevent_dbus_timeout_add, libevent_dbus_timeout_remove,
libevent_dbus_timeout_toggled, dbus_cnx, nullptr) == FALSE)
return FALSE;
dbus_connection_set_dispatch_status_function(dbus_cnx,
libevent_dbus_dispatch_status, dbus_cnx, nullptr);
status = dbus_connection_get_dispatch_status(dbus_cnx);
if (status == DBUS_DISPATCH_DATA_REMAINS)
throw_libevent_dispatch_dbus(dbus_cnx);
return TRUE;
}
int setup_event_loop_for_dbus(DBusConnection *dbus_cnx)
{
if (ev_base == nullptr)
ev_base = event_base_new();
if (ev_base == nullptr)
return -1;
if (setup_dbus_in_libevent_mainloop(dbus_cnx) == FALSE) {
dbus_connection_unref(dbus_cnx);
event_base_free(ev_base);
return -1;
}
return 0;
}
int libevent_run_loop_dbus(void)
{
return event_base_loop(ev_base, 0);
}
void dbus_cleanup_event_loop(DBusConnection *dbus_cnx)
{
if (dbus_cnx == nullptr)
return;
dbus_connection_set_watch_functions(dbus_cnx,
nullptr, nullptr, nullptr, nullptr, nullptr);
dbus_connection_set_timeout_functions(dbus_cnx,
nullptr, nullptr, nullptr, nullptr, nullptr);
dbus_connection_set_dispatch_status_function(dbus_cnx,
nullptr, nullptr, nullptr);
}

Resources