Skip to main content
gamedev.net
🔒 Locked

modulation sensation

Started by Thetan Sep 4, 2006 at 4:10 PM 4 replies 850+ views
Original Post
Thetan
Thetan
ok, im working on an irc bot system that runs almost entirely off of customizable modules. I want it to be set up so that whenever you want to add another module or change a previous one you dont have to recompile the whole bot. My intent is to build something that works similar to the way firefox extensions work. So instinctively i turn to dynamic linking, but i remembered that i have 0 experience in working with dynamic linking. My problem is that all of the external functions i try to call from my modules are undefined (this makes perfect sense to me, but i dont get how to make it work like i want it to). here, code talks best a simple module:

#include "../khook.h"

void hookAct(struct ircHandle *ih, struct ircHeader *ph)
{
	if(ph->message[0] == '+' && strncmp(&(ph->message[1]), "act", 3) == 0)
		IRCAction(ih, ph->channel, &(ph->message[5])); // the function that exists in the program loading this module
}

khook.h (my pathetic attempt to solve the problem)

struct ircHandle
{
	int port, sock;
	char nick[50];
};

struct ircHeader
{
	char *raw;
	char *nick;
	char *name;
	char *vhost;
	char *channel;
	char *type;
	char *target;
	char *message;
};

// me attempting to extern the outside functions
void IRCUser(struct ircHandle*, char*);
void IRCNick(struct ircHandle*, char*);
int IRCOpen(struct ircHandle*, char*, int, char*);
char IRCGetChar(struct ircHandle*);
char* IRCGetHeader(struct ircHandle*);
struct ircHeader* IRCGetParsedHeader(struct ircHandle*);
void IRCHeaderFree(struct ircHeader*);
int IRCPing(struct ircHandle*, struct ircHeader*);
void IRCNotice(struct ircHandle*, char*, char*);
void IRCKick(struct ircHandle*, char*, char*, char*);
void IRCPrivmsg(struct ircHandle*, char*, char*);
void IRCAction(struct ircHandle*, char*, char*);
void IRCJoin(struct ircHandle*, char*);
void IRCQuit(struct ircHandle*, char*);

The failure:

[r3d@localhost PRIVMSG]$ gcc -fPIC Act.c
/usr/lib/gcc-lib/i386-redhat-linux/3.3.3/../../../crt1.o(.text+0x18): In function `_start':
: undefined reference to `main'
/tmp/ccsuf1o1.o(.text+0x55): In function `hookAct':
: undefined reference to `IRCAction'
collect2: ld returned 1 exit status
[r3d@localhost PRIVMSG]$

ideas, sugestions, and bitch slaps of obvious truth are all welcome <3 Thetan
___#define ever (;;)for ever delete (void *) rand();
Nypyren
Nypyren
I have no experience in *nix, but in Windows, the procedure looks like this:

- In your main app, you define function pointers so that the linker doesn't think the functions are actually supposed to exist yet.
- You write functions in the DLL that match the function signature that the main app's pointers use.
- Back in the main app, you load the DLL into your process (LoadLibrary).
- You get a void* to the function by name and assign it to a proper pointer (GetProcAddress)

There must be some *nix steps that are similar to these.
Thetan
Thetan
right i know all the steps for dynamic linking, but my problem is a design issue or so i think.

let me try to illustrate the problem.
bot core:             module:-------------        ------------------|IRCAction()|        |hookAct(){      ||IRCMsg()   |  <---> |    IRCAction();||IRCJoin()  |        |}               ||...        |        -------------------------------

How do i get the compiler to realize that i want the module to call a function from the botcore?
___#define ever (;;)for ever delete (void *) rand();
TheAdmiral
TheAdmiral
Wow. This sounds like it will make an excellent trojan [wink].

[Edit: In future, I need to pay more attention. Most of this has already been established [rolleyes]]

Dynamic module handling can easily be performed using kernel32 (indirectly, ntdll)'s usual image-loading functions:

LoadLibraryA() will import a DLL into your applications address space at runtime. All it needs is a path to the DLL. The entry function (DLLMain) will be called automatically, so perhaps if your application creates a mutex, you could have the plugins 'sign in' by populating some global structure with their exported functions.

Once the image is loaded, you can access its exported functions by name (if you prefer) using the GetProcAddress() kernel32 function. Of course, this is unnecessary if you know the exported functions at compile-time. Pass it the DLL's module-base and the string name of the function and it will return a function pointer. Keeping your C++ compiler happy here will probably be a pain, so if you don't mind the hack, you could implement some inline assembly to take care of the function calls.

When you're finished with a DLL, you can free up the memory using FreeLibraryA.

Edit: More on what you wanted:

You don't know the function prototypes at compile-time, so there will be trouble implementing the plugins in advance. One idea would be to create your own 'variant' data type, which encapsulates any other data type you need to communicate. This way, you could write all the plugin functions so that they pass (and possibly return) a pointer to an array/vector of variants. This way, your parameters are flexible in type and quantity, but the prototype is always the same. This does, however, put extra work on the plugin author.

Ultimately, the core application will not be able to use the plugins unless it knows something about what they do, so perhaps if you give us more details on how the plugins interact with the core then we can provide a more suitable solution.

Regards
Admiral
Ring3 Circus - Diary of a programmer, journal of a hacker.
Thetan
Thetan
Quote:
Original post by TheAdmiral
You don't know the function prototypes at compile-time, so there will be trouble implementing the plugins in advance. One idea would be to create your own 'variant' data type, which encapsulates any other data type you need to communicate. This way, you could write all the plugin functions so that they pass (and possibly return) a pointer to an array/vector of variants. This way, your parameters are flexible in type and quantity, but the prototype is always the same. This does, however, put extra work on the plugin author.

actually my way around that was to set 2 standardized parameters for each module.
1.) An "IRC Handle"
2.) A parsed IRC Header
ontop of that the botcore knows the name of the function to load due to the fact that the name of the function should always be hook(module-filename-without-extension-here)

Quote:
Original post by TheAdmiral
Ultimately, the core application will not be able to use the plugins unless it knows something about what they do, so perhaps if you give us more details on how the plugins interact with the core then we can provide a more suitable solution.

ok, i got that far on my own, but my speedbump isnt how do i get the botcore to use the module. My speed bump is how do i get the module to utilize the botcore (or atleast the botcore functions)
___#define ever (;;)for ever delete (void *) rand();
TheAdmiral
TheAdmiral
Perhaps the easiest way to do this would be to put all of your core functions in a 'core' DLL which both the app and the plugins use. This way everything is known in advance and you won't have to tell the core to export all of its functions.

Regards
Admiral
Ring3 Circus - Diary of a programmer, journal of a hacker.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.