I just thought I'd mention that with my nascent OpenSSL plugin, I brought the execution of my app (which decrypts an AES-encrypted file) down from 80-90 seconds to 0.7-1.4 seconds, 60% of which is file I/O.
Thanks for everyone's help. I want to reorg my code a little bit now and flush out the tests. As soon as I have code I'd be willing to show my mother (you laugh, but my mom actually does have a CS degree ;-) ), I'll put it on SqueakMap - maybe next week.
It looks like dlopen() may not be the panacea I'd hoped it would be since it's apparently not supported on Mac OS X. But cross-platform maintenance of the OpenSSL plugin via header files and linking to dll/so files should be very minimal.
Since my code will replace some (perhaps eventually all) of the functionality in the Cryptography package, does anyone have any suggestions WRT namespace issues? Package names and Class names? I wanted to keep the interfaces the same as the existing package to the point where my package could be a drop-in replacement, but my interface ends up being a level higher than what's in the Cryptography package (and the lower level stuff is down in the primitive itself), so that plan won't work after all.
On Fri, 2004-05-21 at 18:12, Jason Dufair wrote:
It looks like dlopen() may not be the panacea I'd hoped it would be since it's apparently not supported on Mac OS X. But cross-platform maintenance of the OpenSSL plugin via header files and linking to dll/so files should be very minimal.
This can be worked around. Here's a bit of code stolen from Nebula Device that wraps around dll handling code for linux, win32, and Mac OSX. I've only actually used the code on Linux so can't confirm that the other two work. I'm confident the Win32 code does since there are commercial projects released for Win32 using this code and the Mac OSX code should be close at least.
#if defined(__LINUX__) static void *_dlopen_wrapper(const char *name, bool prefix) { char dll_name[N_MAXPATH]; if (prefix) { strcpy(dll_name,"lib"); strcat(dll_name,name); } else { strcpy(dll_name,name); } strcat(dll_name,".so"); void *dll = dlopen(dll_name,RTLD_NOW|RTLD_GLOBAL); // Caller will handle printing error return dll; } void *n_dllopen(const char *name) { void *dll = _dlopen_wrapper(name, true); if (!dll) { char *err1 = n_strdup(dlerror()); dll = _dlopen_wrapper(name, false); if (!dll) { const char *err2 = dlerror(); n_printf("Could not load dll for '%s'\n", name); n_printf("Error was:\n"); n_printf("%s\n", err1); n_printf("%s\n", err2); n_free(err1); } } return dll; } #elif defined(__WIN32__) void *n_dllopen(const char *name) { HINSTANCE dll; dll = LoadLibrary((LPCSTR) name); if (!dll) { // Find out why we failed LPVOID lpMsgBuf; FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL );
// Display the string. n_printf("Could not load dll '%s'\nError was:\n%s\n", name, lpMsgBuf);
// Free the buffer. LocalFree( lpMsgBuf ); } return (void *) dll; } #elif defined(__MACOSX__) void *n_dllopen(const char *name) { void* result = 0;
const int kBundleAnyType = 0; const int kBundleNoSubdir = 0;
CFBundleRef mainBundle = CFBundleGetMainBundle();
// put the name of the bundle we want in a CFString std::string bundleName( name ); bundleName += ".bundle"; CFStringRef cfBundleName = CFStringCreateWithCString( NULL,
bundleName.c_str(),
kCFStringEncodingASCII );
CFURLRef bundleURL = CFBundleCopyResourceURL( mainBundle, cfBundleName, kBundleAnyType, kBundleNoSubdir );
if ( bundleURL ) { CFBundleRef myBundle = CFBundleCreate( kCFAllocatorDefault, bundleURL ); Boolean loaded = CFBundleLoadExecutable( myBundle ); if ( loaded ) result = myBundle; } return result; } #else void *n_dllopen(const char *name) { n_error("nClass::dll_load() not implemented!"); return NULL; } #endif
This can be worked around. Here's a bit of code stolen from Nebula Device that wraps around dll handling code for linux, win32, and Mac OSX. I've only actually used the code on Linux so can't confirm that the other two work. I'm confident the Win32 code does since there are commercial projects released for Win32 using this code and the Mac OSX code should be close at least.
And that code looks suspiciosly like InterpreterProxy>>ioLoadFunction:From: ;-)
Cheers, - Andreas
Jason Dufair jase@dufair.org wrote:
I just thought I'd mention that with my nascent OpenSSL plugin, I brought the execution of my app (which decrypts an AES-encrypted file) down from 80-90 seconds to 0.7-1.4 seconds, 60% of which is file I/O.
Good news.
It looks like dlopen() may not be the panacea I'd hoped it would be since it's apparently not supported on Mac OS X. But cross-platform maintenance of the OpenSSL plugin via header files and linking to dll/so files should be very minimal.
That's hardly portable - some of us have utterly different mechanisms for this sort of stuff.
Consider something like:- primitiveAESEncryptCBC: plainText ciphertext: cipherText key: aKey iv: anInitializationVector "Encrypt aByteArray using the AES (Rijndael) algorithm in CBC mode"
self cCode: '' inSmalltalk: [^nil]. "tpr add return for trivial support of simulator"
self primitive: 'primitiveAESEncryptCBC' parameters: #(#ByteArray #ByteArray #ByteArray #ByteArray). self encrypt: plaintext to: ciphertext key: aKey iv: anInitthingy
note that encrypttokeyiv() will be generated by the CCodeGen and then implement it in a platform specific file. You could also implement encrypt:to:key:iv: in a simulator class for the benefit of InterpreterSimulator users, dropping the ^nil at the top.
In each supported platform's file you then deal with its quirks. I would imagine the windows version would be a trivial transposing of the original contents of your prim?
As long as a platform can do openSSL compatible munging based on the four parameters, you're ok. Oh, consider implementing initialiseModule in a similar manner such that each platform can do what it needs. See various othe plugins for examples.
Since my code will replace some (perhaps eventually all) of the functionality in the Cryptography package, does anyone have any suggestions WRT namespace issues? Package names and Class names? I wanted to keep the interfaces the same as the existing package to the point where my package could be a drop-in replacement, but my interface ends up being a level higher than what's in the Cryptography package (and the lower level stuff is down in the primitive itself), so that plan won't work after all.
Bridges. Have the high level stuff talk to a translator class that can pass off to openSSL or whatever is already there. Choose the translator class by appropriate means at runtime.
tim -- Tim Rowledge, tim@sumeru.stanford.edu, http://sumeru.stanford.edu/tim Strange OpCodes: WRTJ: Who Reads This Junk?
this is a good idea, just wrapping some platform specific load library code in the plugin.
i have used the link strategy before and it does work very well on windows/mac/linux, including headers and linking with the dll/framework/so . the plugin code itself is very portable if u have the headers in the right place and the right paths set up. the source for the plugin requires no changes at all across platforms. there are slight differences in how it is compiled, but no more than how the current makefiles for the vm differ for each platform. i did all of this straight in c though, without slang.
however, if this is something that eventually would be distributed as part of vm source files and such, then u run into trouble, as it requires the headers for OpenSSL to be compiled obviously, and i am sure this is what tim is referring to. if u can get those functions loaded dynamically instead of linking u would be better off.
i tried to use ioLoadFunctionFrom to connect to an external library initially and no dice. i was told that it was not really meant to load functions from non squeak plugin dlls/so and such ( there are certain entry points it needs to look for, mainly setting the interpreterProxy i believe if i remember correctly).
anyways, just thought i would let u know since i have done this on all three major platforms before and it is easy to maintain and port, but only if it is completely separate from the vm.
jamie
Tim Rowledge wrote:
Bridges. Have the high level stuff talk to a translator class that can
pass off to openSSL or whatever is already there. Choose the translator class by appropriate means at runtime.
This is exactly what I've ended up doing. In fact the only Win32 specific thing at all is the Makefile that explicitly links to the pre-existing DLL. Even the header file and the included OpenSSL header files should compile regardless of the platform, as long as it can do dynamic linking. I think it should be in good shape for extension to other platforms, though I don't have a Mac or Acorn or PocketPC to build makefiles for those platforms. As long as the APIs I use don't change, it should be a matter of dropping in new dll/so/whatever-acorn-uses as they become available.
squeak-dev@lists.squeakfoundation.org