As I stated earlier, here's a "cleaned" up version of libInSim, with a brief example of how it works;
http://svn.theangryangel.co.uk/LFS/libInSim/tags/
It doesn't demonstrate how to use the hooks properly though. The general gist is that you create a number of functions which are passed into a struct, which is registered against the library. The library then fires each of the functions as necessary.
There are 5 "events" (or functions);
create - typically you'd use this to allocate any memory into the "ctx" - which is a unique pointer for your set of hooks
connection - occurs on connection - you might want to send an IS_TINY asking for all the players here for isntance
receive - triggered whenever a packet is received - you'd use this to distribute to your other functions
disconnection - connection tracking clear up and other stuff probably
close - deallocating any memory
For instance a hook could be as follows;
void rx_create(struct insim_t *I, void **ctx)
{
*ctx = malloc(sizeof(struct rx_info_t));
memset(*ctx, 0, sizeof(struct rx_info_t));
struct rx_info_t *t = *ctx;
t->version = 0.1;
t->name = malloc(strlen(rx_FULL_NAME) + 1);
memset(t->name, 0, strlen(rx_FULL_NAME) + 1);
memcpy(t->name, rx_FULL_NAME, strlen(rx_FULL_NAME));
printf("%s v%.1f\n", t->name, t->version);
return;
}
void rx_connected(struct insim_t *I, void *ctx)
{
struct rx_info_t *i = ctx;
/*
struct IS_MST t;
memset(&t, 0, sizeof(struct IS_MST));
t.size = sizeof(struct IS_MST);
t.type = ISP_MST;
strncpy(t.Msg, rx_FULL_NAME " started", strlen(rx_FULL_NAME " started"));
insim_send(I, (const char *)&t, sizeof(t));
*/
struct IS_TINY p;
memset(&p, 0, sizeof(struct IS_TINY));
p.size = sizeof(struct IS_TINY);
p.type = ISP_TINY;
p.reqI = 1;
p.subT = TINY_NCN;
insim_send(I, (const char *)&p, sizeof(p));
p.subT = TINY_NPL;
insim_send(I, (const char *)&p, sizeof(p));
return;
}
void rx_recv(struct insim_t *I, void *ctx, void *data, unsigned int size)
{
char *p = data;
unsigned char type = *(p + 1);
switch(type)
{
case ISP_III:
rx_III(I, ctx, (struct IS_III *)p);
break;
case ISP_NCN:
rx_NCN(I, ctx, (struct IS_NCN *)p);
break;
case ISP_CNL:
rx_CNL(I, ctx, (struct IS_CNL *)p);
break;
case ISP_NPL:
rx_NPL(I, ctx, (struct IS_CNL *)p);
break;
case ISP_PLL:
rx_PLL(I, ctx, (struct IS_CNL *)p);
break;
case ISP_RES:
rx_RES(I, ctx, (struct IS_RES *)p);
break;
default:
printf("Unknown packet %d\n", type);
break;
}
return;
}
void rx_disconnected(struct insim_t *I, void *ctx)
{
struct rx_info_t *t = ctx;
list_destroy(&(t->connections));
return;
}
void rx_close(struct insim_t *I, void *ctx)
{
struct rx_info_t *t = ctx;
if (t->name != NULL)
free(t->name);
if (t != NULL)
free(t);
ctx = NULL;
printf("Memory freed\n");
return;
}
Then in main.c you'd create a struct, populating it with all the function pointers
struct hooks_t hook_rx;
memset(&hook_rx, 0, sizeof(struct hooks_t));
strcpy(hook_rx.name, rx_NAME);
hook_rx.fp_create = rx_create;
hook_rx.fp_connected = rx_connected;
hook_rx.fp_recv = rx_recv;
hook_rx.fp_disconnected = rx_disconnected;
hook_rx.fp_close = rx_close;
And add it into the hooks linked list;
list_add(&(I->hooks), (void *)&hook_rx)
Granted that's not perfect and will give you some "interesting" compile warnings, but it'll work in most circumstances.
I told you it was "complex"
You'll notice that the create functions use a double indirection for the ctx pointer - this is so that you can allocate the memory correctly and might be the biggest thing to get your head around