libSystem/src/appinterface.c
2005-09-24 01:09:06 +00:00

449 lines
9.5 KiB
C

/* appinterface.c */
#include <stdarg.h>
#include <stdint.h>
#include <stdlib.h>
#ifdef DEBUG
# include <stdio.h>
#endif
#include <dlfcn.h>
#include "string.h"
#include "appinterface.h"
/* AppInterface */
/* private */
/* types */
typedef enum _AppInterfaceCallType {
AICT_VOID, AICT_BOOL,
AICT_INT8, AICT_UINT8,
AICT_INT16, AICT_UINT16,
AICT_INT32, AICT_UINT32,
AICT_INT64, AICT_UINT64,
AICT_STRING, AICT_BUFFER
} AppInterfaceCallType;
typedef struct _AppInterfaceCall
{
char * name;
AppInterfaceCallType type;
AppInterfaceCallType * args;
int args_cnt;
void * func;
} AppInterfaceCall;
struct _AppInterface
{
AppInterfaceCall * calls;
int calls_cnt;
};
/* public */
/* functions */
static int _new_append(AppInterface * appinterface, AppInterfaceCallType type,
char const * function, int args_cnt, ...);
static int _new_session(AppInterface * appinterface);
static int _new_hello(AppInterface * appinterface);
AppInterface * appinterface_new(char const * app)
{
AppInterface * appinterface;
struct iface { char * name; int (* func)(AppInterface *); } ifaces[] = {
{ "Session", _new_session },
{ "Hello", _new_hello }
};
size_t i;
#ifdef DEBUG
fprintf(stderr, "%s%s%s", "appinterface_new(", app, ");\n");
#endif
if((appinterface = malloc(sizeof(AppInterface))) == NULL)
return NULL;
appinterface->calls = NULL;
appinterface->calls_cnt = 0;
for(i = 0; i < sizeof(ifaces) / sizeof(struct iface); i++)
{
if(string_compare(app, ifaces[i].name) != 0)
continue;
#ifdef DEBUG
fprintf(stderr, "%s%s%s", "AppInterface \"", app, "\"\n");
#endif
if(ifaces[i].func(appinterface) != 0)
i = sizeof(ifaces) / sizeof(struct iface);
break;
}
if(i == sizeof(ifaces) / sizeof(struct iface))
{
#ifdef DEBUG
fprintf(stderr, "%s", "AppInterface creation error\n");
#endif
free(appinterface);
return NULL;
}
return appinterface;
}
static int _new_append(AppInterface * ai, AppInterfaceCallType type,
char const * function, int args_cnt, ...)
{
AppInterfaceCall * p;
va_list args;
int i;
int j;
#ifdef DEBUG
fprintf(stderr, "%s%s%s%d%s", "AppInterface supports ", function, "(",
args_cnt, ")\n");
#endif
for(i = 0; i < ai->calls_cnt; i++)
if(string_compare(ai->calls[i].name, function) == 0)
return 1;
if((p = realloc(ai->calls, sizeof(AppInterfaceCall) * (i + 1)))
== NULL)
{
/* FIXME */
return 1;
}
ai->calls = p;
ai->calls_cnt++;
ai->calls[i].type = type;
ai->calls[i].name = string_new(function);
ai->calls[i].args = malloc(sizeof(AppInterfaceCallType) * args_cnt);
ai->calls[i].args_cnt = args_cnt;
va_start(args, args_cnt);
for(j = 0; j < args_cnt; j++)
ai->calls[i].args[j] = va_arg(args, AppInterfaceCallType);
va_end(args);
return 0;
}
static int _new_session(AppInterface * appinterface)
{
int ret = 0;
ret += _new_append(appinterface, AICT_UINT16, "port", 1, AICT_STRING);
ret += _new_append(appinterface, AICT_VOID, "list", 0);
ret += _new_append(appinterface, AICT_BOOL, "start", 1, AICT_STRING);
ret += _new_append(appinterface, AICT_BOOL, "stop", 1, AICT_STRING);
return ret;
}
static int _new_hello(AppInterface * appinterface)
{
return _new_append(appinterface, AICT_VOID, "hello", 0);
}
/* appinterface_new_server */
/* FIXME */
extern void * handle;
AppInterface * appinterface_new_server(char const * app)
{
AppInterface * appinterface;
void * handle;
int i;
#ifdef DEBUG
char * error;
#endif
if((handle = dlopen(NULL, RTLD_LAZY)) == NULL)
return NULL;
if((appinterface = appinterface_new(app)) == NULL)
return NULL;
for(i = 0; i < appinterface->calls_cnt; i++)
{
#ifdef DEBUG
dlerror();
#endif
appinterface->calls[i].func = dlsym(handle,
appinterface->calls[i].name);
#ifdef DEBUG
if((error = dlerror()) != NULL)
fprintf(stderr, "%s%s\n", "AppServer: ", error);
#endif
}
dlclose(handle);
return appinterface;
}
/* appinterface_delete */
void appinterface_delete(AppInterface * appinterface)
{
int i;
for(i = 0; i < appinterface->calls_cnt; i++)
{
free(appinterface->calls[i].name);
free(appinterface->calls[i].args);
}
free(appinterface->calls);
free(appinterface);
}
/* useful */
/* appinterface_call */
static int _send_buffer(char * data, int datalen, char * buf, int buflen,
int * pos);
static int _send_string(char * string, char * buf, int buflen, int * pos);
int appinterface_call(AppInterface * appinterface, char * call, char buf[],
int buflen, void ** args)
{
AppInterfaceCall * aic;
int pos = 0;
int i;
int size;
#ifdef DEBUG
fprintf(stderr, "%s%s%s", "appinterface_call(", call, ");\n");
#endif
for(i = 0; i < appinterface->calls_cnt; i++)
if(string_compare(appinterface->calls[i].name, call) == 0)
break;
if(i == appinterface->calls_cnt)
return -1;
aic = &appinterface->calls[i];
if(_send_string(call, buf, buflen, &pos) != 0)
return -1;
for(i = 0; i < aic->args_cnt; i++)
{
switch(aic->args[i])
{
case AICT_BOOL:
case AICT_INT8:
case AICT_UINT8:
size = sizeof(int8_t);
break;
case AICT_INT16:
case AICT_UINT16:
size = sizeof(int16_t);
break;
case AICT_INT32:
case AICT_UINT32:
size = sizeof(int32_t);
break;
case AICT_INT64:
case AICT_UINT64:
size = sizeof(int64_t);
break;
case AICT_STRING:
_send_string(args[i], buf, buflen, &pos);
continue;
default:
/* FIXME */
#ifdef DEBUG
fprintf(stderr, "%s, %d: %s", __FILE__,
__LINE__,
"Should not happen\n");
#endif
return -1;
}
if(_send_buffer(args[i], size, buf, buflen, &pos) != 0)
return -1;
}
return pos;
}
static int _send_buffer(char * data, int datalen, char * buf, int buflen,
int * pos)
{
if(*pos + datalen > buflen)
return 1;
memcpy(&buf[*pos], data, datalen);
*pos += datalen;
return 0;
}
static int _send_string(char * string, char buf[], int buflen, int * pos)
{
int i = 0;
#ifdef DEBUG
fprintf(stderr, "%s%s%s", "send_string(", string, ");\n");
#endif
while(*pos < buflen)
{
buf[*pos] = string[i];
(*pos)++;
if(string[i++] == '\0')
return 0;
}
return 1;
}
/* appinterface_receive */
static char * _read_string(char buf[], int buflen, int * pos);
static int _receive_args(AppInterfaceCall * calls, char buf[], int buflen,
int * pos);
int appinterface_receive(AppInterface * appinterface, char buf[], int buflen,
int * ret)
{
int pos = 0;
char * func;
int i;
#ifdef DEBUG
fprintf(stderr, "%s", "appinterface_receive();\n");
#endif
if((func = _read_string(buf, buflen, &pos)) == NULL)
return -1;
for(i = 0; i < appinterface->calls_cnt; i++)
if(string_compare(appinterface->calls[i].name, func) == 0)
break;
string_delete(func);
if(i == appinterface->calls_cnt)
return -1;
/* FIXME give a way to catch errors if any */
*ret = _receive_args(&appinterface->calls[i], buf, buflen, &pos);
return pos;
}
static char * _read_string(char buf[], int buflen, int * pos)
{
for(; *pos < buflen && buf[*pos] != '\0'; (*pos)++);
if(*pos == buflen)
return NULL;
(*pos)++;
return string_new(buf);
}
static int _read_buffer(char ** data, int datalen, char buf[], int buflen,
int * pos);
static int _receive_exec(AppInterfaceCall * calls, char ** args);
static int _receive_args(AppInterfaceCall * calls, char buf[], int buflen,
int * pos)
{
int i;
char ** args;
size_t size;
int j;
int ret;
if((args = malloc(sizeof(char*) * calls->args_cnt)) == NULL)
return 1;
for(i = 0; i < calls->args_cnt; i++)
{
#ifdef DEBUG
fprintf(stderr, "%s%d%s", "_receive_args() reading arg ", i+1,
"\n");
#endif
switch(calls->args[i])
{
case AICT_VOID:
continue;
case AICT_BOOL:
case AICT_INT8:
case AICT_UINT8:
size = sizeof(int8_t);
break;
case AICT_INT16:
case AICT_UINT16:
size = sizeof(int16_t);
break;
case AICT_INT32:
case AICT_UINT32:
size = sizeof(int32_t);
break;
case AICT_INT64:
case AICT_UINT64:
size = sizeof(int64_t);
break;
case AICT_STRING:
args[i] = _read_string(buf, buflen, pos);
continue;
}
if(sizeof(char*) < size)
{
if((args[i] = malloc(size)) == NULL)
break;
if(_read_buffer(args[i], size, buf, buflen, pos) != 0)
break;
}
else if(_read_buffer(&args[i], size, buf, buflen, pos) != 0)
break;
}
ret = _receive_exec(calls, args);
/* FIXME free everything allocated */
for(j = 0; j < i; j++)
{
#ifdef DEBUG
fprintf(stderr, "%s%d%s", "_receive_args() freeing arg ", j+1,
"\n");
#endif
switch(calls->args[j])
{
case AICT_VOID:
continue;
case AICT_BOOL:
case AICT_INT8:
case AICT_UINT8:
size = sizeof(int8_t);
break;
case AICT_INT16:
case AICT_UINT16:
size = sizeof(int16_t);
break;
case AICT_INT32:
case AICT_UINT32:
size = sizeof(int32_t);
break;
case AICT_INT64:
case AICT_UINT64:
size = sizeof(int64_t);
break;
case AICT_STRING:
free(args[j]);
continue;
}
if(sizeof(char*) < size)
free(args[i]);
}
free(args);
return ret;
}
static int _read_buffer(char ** data, int datalen, char buf[], int buflen,
int * pos)
{
if(datalen > buflen - *pos)
return 1;
memcpy(data, buf, datalen);
(*pos)+=datalen;
return 0;
}
static int _receive_exec(AppInterfaceCall * calls, char ** args)
{
int (*func0)(void);
int (*func1)(char *);
int (*func2)(char *, char *);
/* FIXME */
switch(calls->args_cnt)
{
case 0:
func0 = calls->func;
return func0();
case 1:
func1 = calls->func;
return func1(args[0]);
case 2:
func2 = calls->func;
return func2(args[0], args[1]);
default:
#ifdef DEBUG
fprintf(stderr, "%s%d%s",
"AppInterface: functions with ",
calls->args_cnt,
" arguments are not supported\n");
#endif
return -1;
}
return -1;
}