Admin Panel
/*
* Copyright (C) 2002 Hyperion Entertainment
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/*
** This file contains the runtime usable DLL functions, like LoadLibrary, GetProcAddress etc.
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include <dos/dostags.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include <clib/alib_protos.h>
#include "debug.h"
#include "dll.h"
#include "dll_intern.h"
struct List dllOpenedDLLs;
char dllError[256] = {0};
int errorclear = TRUE;
int cleanupflag = FALSE;
static void dllSetError(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vsnprintf(dllError, sizeof(dllError), fmt, ap);
va_end(ap);
errorclear = FALSE;
D(bug("[DLL] DLL error: %s\n", dllError));
}
static char *NameFromLockAlloc(BPTR lock)
{
LONG error = 0;
LONG size;
char *fullname;
for(size = 256; fullname == NULL && error == 0; size += 256)
{
fullname = malloc(size);
if (fullname)
{
if (!NameFromLock(lock, fullname, size))
{
error = IoErr();
if (error == ERROR_LINE_TOO_LONG)
{
error = 0;
FreeVec(fullname);
fullname = NULL;
}
}
}
else
{
error=IoErr();
}
}
return fullname;
}
void dllCleanup()
{
dll_tInstance *n;
D(bug("[DLL] dllCleanup()\n"));
while ((n = (dll_tInstance *)RemHead((struct List *)&dllOpenedDLLs)))
{
dllInternalFreeLibrary(n);
}
}
void *dllLoadLibrary(const char *filename, const char *portname)
{
D(bug("[DLL] dllLoadLibrary(%s, %s)\n", filename, portname));
return dllInternalLoadLibrary(filename, portname, 1);
}
void *dllInternalLoadLibrary(const char *filename, const char *portname, int raiseusecount)
{
struct MsgPort *myport = NULL;
dll_tInstance *n = NULL;
dll_tMessage msg, *reply;
BPTR handle;
//char buffer[1024];
char *buffer = NULL;
D(bug("[DLL] dllInternalLoadLibrary(%s, %s, %d)\n", filename, portname, raiseusecount));
if (!cleanupflag)
{
NewList(&dllOpenedDLLs);
dllOpenedDLLs.lh_Type = NT_USER;
if (atexit((void *)dllCleanup))
{
dllSetError("can't install exit handler");
goto failed;
}
else
{
cleanupflag = TRUE;
}
}
if (!filename)
{
dllSetError("empty file name");
goto failed;
}
if (!(handle = Open(filename, MODE_OLDFILE)))
{
char dosErrorMsg[80];
Fault(IoErr(), NULL, dosErrorMsg, sizeof(dosErrorMsg));
dllSetError("can't open %s: %s", filename, dosErrorMsg);
goto failed;
}
Close(handle);
if (!portname)
{
portname = filename;
}
// Search for already opened DLLs
if ((n = (dll_tInstance *)FindName(&dllOpenedDLLs, portname)))
{
if (raiseusecount)
{
if (n->node.ln_Pri < 127)
{
n->node.ln_Pri++;
D(bug("[DLL] increased internal open count of %s to %d\n", n->node.ln_Name, n->node.ln_Pri));
}
else
{
dllSetError("can't open %s: reached max usage count (127)", filename);
// we can't do a goto failed here, because it would free the node
return NULL;
}
}
D(bug("[DLL] found %s in dllOpenedDLLs\n", portname));
return n;
}
// Not opened yet, create a new node
if (!(n = malloc(sizeof(dll_tInstance) + strlen(portname))))
{
dllSetError("can't allocate %d bytes for a new dllOpenedDLL node", sizeof(dll_tInstance));
goto failed;
}
memset(n, 0, sizeof(dll_tInstance));
//strncpy(n->name, portname, sizeof(n->name));
strcpy(n->name, portname);
n->node.ln_Name = n->name;
n->node.ln_Pri = 1; // usecount
n->node.ln_Type = NT_USER;
// create a reply port
if (!(myport = CreateMsgPort()))
{
dllSetError("can't create the message port");
goto failed;
}
// if the DLL has not been started already...
if (!(n->dllPort = FindPort(portname)))
{
int i;
int bufsize;
D(bug("[DLL] launching '%s'\n", filename));
if (!(handle = Open("CON:0/0/800/600/DLL_OUTPUT/AUTO/CLOSE/WAIT", MODE_NEWFILE)))
//snprintf(buffer, sizeof(buffer), "CON:////%s output/AUTO/CLOSE/WAIT", FilePart(filename));
//if (!(handle = Open(buffer, MODE_NEWFILE)))
{
dllSetError("can't open output stream");
goto failed;
}
if (!(buffer = malloc(strlen(filename) + strlen(portname) + 6)))
{
dllSetError("can't allocate command line string");
goto failed;
}
//bufsize = sizeof(buffer);
//i = snprintf(buffer, sizeof(buffer), "\"%s\" \"%s\"", filename, portname);
bufsize = strlen(filename) + strlen(portname) + 6;
i = snprintf(buffer, strlen(filename) + strlen(portname) + 6, "\"%s\" \"%s\"", filename, portname);
// check if the string was truncated
if (!(i > 0 && i < bufsize))
{
dllSetError("command line string was truncated (%d - %d)", i, bufsize);
goto failed;
}
if (SystemTags(buffer,
SYS_Asynch, TRUE,
SYS_Output, handle,
SYS_Input, NULL, //FIXME: some dll's might need stdin
NP_StackSize, 10000, //Messagehandler doesn't need a big stack (FIXME: but DLL_(De)Init might)
TAG_DONE) < 0)
{
dllSetError("SystemTags failed");
goto failed;
}
// wait for 10 secs, and check every half sec
for (i = 0; i < 20; i++)
{
if ((n->dllPort = FindPort(portname)))
{
break;
}
D(bug("[DLL] Delaying...\n"));
Delay(25);
}
}
if (!n->dllPort)
{
dllSetError("can't find the message port: %s", portname);
goto failed;
}
memset(&msg, 0, sizeof(msg));
msg.dllMessageType = DLLMTYPE_Open;
msg.dllMessageData.dllOpen.StackType = DLLSTACK_DEFAULT;
msg.Message.mn_ReplyPort = myport;
PutMsg(n->dllPort, (struct Message *)&msg);
WaitPort(myport);
if (!(reply = (dll_tMessage *)GetMsg(myport)))
{
dllSetError("didn't get a reply message");
//FIXME: Must/Can I send a Close message here ??
goto failed;
}
if (reply->dllMessageData.dllOpen.ErrorCode != DLLERR_NoError)
{
// this shouldn't happen
dllSetError("DLL initialization error");
goto failed;
}
DeleteMsgPort(myport);
AddTail(&dllOpenedDLLs, (struct Node *)n);
D(bug("[DLL] added a new node for %s\n", portname));
return n;
failed:
if (myport)
{
DeleteMsgPort(myport);
}
if (n)
{
free(n);
}
if (buffer)
{
free(buffer);
}
return NULL;
}
int dllFreeLibrary(void *hinst)
{
dll_tInstance *n;
D(bug("[DLL] dllFreeLibrary()\n"));
if (!(n = (dll_tInstance *)hinst))
{
dllSetError("NULL DLL instance");
return 1;
}
n->node.ln_Pri--;
D(bug("[DLL] decreased internal open count of %s to %d\n", n->node.ln_Name, n->node.ln_Pri));
if (n->node.ln_Pri <= 0)
{
Remove((struct Node *)n);
return dllInternalFreeLibrary(n);
}
return 0;
}
int dllInternalFreeLibrary(dll_tInstance *n)
{
dll_tMessage msg, *reply;
struct MsgPort *myport;
D(bug("[DLL] dllInternalFreeLibrary()\n"));
if (!(myport = CreateMsgPort()))
{
dllSetError("can't create the message port");
return 1;
}
D(bug("[DLL] sending close message to %s\n", n->node.ln_Name));
memset(&msg, 0, sizeof(msg));
msg.dllMessageType = DLLMTYPE_Close;
msg.Message.mn_ReplyPort = myport;
if (FindPort(n->node.ln_Name) == n->dllPort)
{
PutMsg(n->dllPort, (struct Message *)&msg);
/*WaitPort(myport);*/
while(!(reply = (dll_tMessage *)GetMsg(myport)))
{
Delay(2);
if (FindPort(n->node.ln_Name) != n->dllPort)
{
break;
}
}
}
else
{
dllSetError("can't find message port: %s", n->node.ln_Name);
DeleteMsgPort(myport);
return 1;
}
DeleteMsgPort(myport);
free(n);
return 0;
}
void *dllGetProcAddress(void *hinst, const char *name)
{
dll_tMessage msg, *reply;
struct MsgPort *myport;
dll_tInstance *n;
void *sym;
D(bug("[DLL] dllGetProcAddress()\n"));
if (!(n = (dll_tInstance *)hinst))
{
dllSetError("NULL DLL instance");
return NULL;
}
if (!name)
{
dllSetError("empty symbol name");
return NULL;
}
// TODO: some safety measure, someone else might have closed the DLL
/*while ((myport = FindPort(n->node.ln_Name)))
{
if (myport == n->dllPort)
break;
}*/
if (!(myport = CreateMsgPort()))
{
dllSetError("can't create the message port");
return NULL;
}
memset(&msg, 0, sizeof(msg));
msg.dllMessageType = DLLMTYPE_SymbolQuery;
msg.dllMessageData.dllSymbolQuery.StackType = DLLSTACK_DEFAULT;
msg.dllMessageData.dllSymbolQuery.SymbolName = (char *)name;
msg.dllMessageData.dllSymbolQuery.SymbolPointer = &sym;
msg.Message.mn_ReplyPort = myport;
PutMsg(n->dllPort, (struct Message *)&msg);
WaitPort(myport);
reply = (dll_tMessage *)GetMsg(myport);
DeleteMsgPort(myport);
if (reply)
{
return(sym);
}
dllSetError("can't find symbol: %s", name);
return NULL;
}
char *dllGetLastError(void)
{
if (errorclear)
{
return NULL;
}
errorclear = TRUE;
return dllError;
}
#if 0
int dllKillLibrary(char *portname)
{
dll_tMessage msg, *reply;
struct MsgPort *myport;
struct MsgPort *dllport;
if (!(myport = CreateMsgPort()))
{
dllSetError("can't create the message port");
return 0;
}
memset(&msg, 0, sizeof(msg));
msg.dllMessageType = DLLMTYPE_Kill;
msg.Message.mn_ReplyPort = myport;
if ((dllport = FindPort(portname)))
{
PutMsg(dllport, (struct Message *)&msg);
//WaitPort(myport);
while (!(reply = (dll_tMessage *)GetMsg(myport)))
{
Delay(2);
if (FindPort(portname) != dllport)
{
break;
}
}
}
DeleteMsgPort(myport);
return (dllport ? 1 : 0);
}
#endif