/* FARGOS Development, LLC Sample Programs Copyright (C) 1999 - 2002 FARGOS Development, LLC. All rights reserved. mailto:support@fargos.net for assistance. */ #include #include #include #include #ifdef _WIN32 /* NOTE: in gdbm library, file gdbmopen.c, all calls to open() function need _O_BINARY added to mask to prevent CR/LF translations */ #include #define GDBM_STATIC #include #define USE_GDBM_EQUIVALENTS #else /* Unix */ #include #include #include #include #include #if linux || sun // Linux doesn't have a good ndbm.h, so use gdbm.h // Solaris ndbm doesn't handle large objects #include #define USE_GDBM_EQUIVALENTS #else // probably *BSD #include static DBM *PDdbHandle; #endif #endif /* end Unix variants */ #ifdef USE_GDBM_EQUIVALENTS static GDBM_FILE PDdbHandle; #define DBM_REPLACE GDBM_REPLACE #define dbm_open(fn, flags, mode) gdbm_open(fn, 0, GDBM_WRCREAT | GDBM_SYNC | GDBM_NOLOCK, mode, 0) #define dbm_close(d) gdbm_close(d) #define dbm_store(d, k, c, f) gdbm_store(d, k, c, f) #define dbm_fetch(d, k) gdbm_fetch(d, k) #define dbm_delete(d, k) gdbm_delete(d, k) #define dbm_firstkey(d) gdbm_firstkey(d) // "key" is taken from variable used in doListObjects() routine #define dbm_nextkey(d) gdbm_nextkey(d, key) #endif #ifdef _WIN32 extern "C" int flock(int fd, int modeBits) { // NOTE: never called, so a stub is good enough /* BIT FLAGS: one of: LOCK_SH (shared) LOCK_EX (exclusive) LOCK_UN (unlock) modified by: LOCK_NB (nonblocking) */ // Closest Win32-equivalent: LockFileEx(), UnlockFileEx() // flock returns 0 ==> success return (0); } extern "C" int fsync(int fd) { // FlushFileBuffers((HANDLE) fd); // Win32 _commit(fd); return (0); } #endif #if sun extern "C" int flock(int fd, int modeBits) { // NOTE: never called, so a stub is good enough // mode: F_LOCK, F_ULOCK // lockf(fd, mode, 0); return (0); } #endif static char srcID[] = "$Id$"; #define OBJECT_PAGER_SERVICE "/ObjectPager" #define REGISTERED_AS "/PersistentObjectDatabase" static OMEapi *api; static OMEtype connectionUserInfo; static OMEtype replyMethodName; static char addr[256]; static const char *dbFileName; static char pagerServiceName[256]; static char thisServiceName[256]; // flag settings from clPersistentObj.oil #define ALWAYS_RESTORE 0 #define RESTORE_ON_DEMAND 1 #define TEMPORARY 2 #ifdef _WIN32 #include "../ome/winServ.cpp" #endif #ifdef _WIN32 int initWinsock() { WORD verRequested; WSADATA data; int rc; verRequested = MAKEWORD(2, 0); rc = WSAStartup(verRequested, &data); return (rc); } #endif static int doSaveObject(OMEtype &args, OMEtype &fromObj, OMEtype &context, OMEtype &user) { int rc, len; datum keyData, objData; OMEstring *newKey; OMEtype &objectName = args[(uint32) 0]; if (objectName.type != OME_STRING) { std::cerr << "bad type for object name\n"; return (-1); } OMEtype &objectData = args[(uint32) 1]; if (objectData.type != OME_STRING) { std::cerr << "bad type for object data\n"; return (-1); } keyData.dptr = (char *) (*objectName.value.s); keyData.dsize = objectName.value.s->length(); objData.dptr = (char *) (*objectData.value.s); objData.dsize = objectData.value.s->length(); rc = dbm_store(PDdbHandle, keyData, objData, DBM_REPLACE); #ifdef USE_GDBM_EQUIVALENTS gdbm_sync(PDdbHandle); #else fsync(dbm_dirfno(PDdbHandle)); fsync(dbm_pagfno(PDdbHandle)); #endif return (rc); } static int doRemoveObject(OMEtype &args, OMEtype &fromObj, OMEtype &context, OMEtype &user) { int rc; datum keyData; OMEtype &objectName = args[(uint32) 0]; if (objectName.type != OME_STRING) { std::cerr << "bad type for object name\n"; return (-1); } keyData.dptr = (char *) (*objectName.value.s); keyData.dsize = objectName.value.s->length(); rc = dbm_delete(PDdbHandle, keyData); #ifdef USE_GDBM_EQUIVALENTS gdbm_sync(PDdbHandle); #endif return (rc); } static int doRestoreObject(OMEtype &resultVec, OMEtype &args, OMEtype &fromObj, OMEtype &context, OMEtype &user) { datum keyData, resultData; unsigned char *ucp; OMEtype &objectName = args[(uint32) 0]; if (objectName.type != OME_STRING) { std::cerr << "bad type for object name\n"; return (-1); } keyData.dptr = (char *) (*objectName.value.s); keyData.dsize = objectName.value.s->length(); resultData = dbm_fetch(PDdbHandle, keyData); if (resultData.dptr == 0) { // failed... std::cerr << "object not found\n"; return (-1); } ucp = (unsigned char *) (resultData.dptr); // return object data, skip 4-byte flag prefix OMEstring *data = new OMEstring(ucp + sizeof(uint32), resultData.dsize - sizeof(uint32)); resultVec[(uint32) 0] = data; // take ownership... return (0); } static int doListObjects(OMEtype &result, OMEtype &args, OMEtype &fromObj, OMEtype &context, OMEtype &user) { uint32 count, delCount; datum key; // "key" is used by dbm_nextkey macro result.initializeAsType(OME_ARRAY); delCount = count = 0; // NOTE: must use "key" as variable for GDBM-based macro key = dbm_firstkey(PDdbHandle); while (key.dptr != 0) { OMEarray rec; uint32 flag; datum resultData; unsigned char *ucp; // fetch flags... resultData = dbm_fetch(PDdbHandle, key); if (resultData.dptr == 0) { // failed... continue; } ucp = (unsigned char *) (resultData.dptr); memcpy(&flag, ucp, sizeof(uint32)); flag = ntohl(flag); if (flag == TEMPORARY) { // delete dbm_delete(PDdbHandle, key); ++delCount; } else { OMEstring *data = new OMEstring((unsigned char *) (key.dptr), key.dsize); rec[0] = data; // take ownership... rec[1] = flag; result[count++] = rec; } // NOTE: must use "key" as variable for GDBM-based macro key = dbm_nextkey(PDdbHandle); } if (OMEdebugFlag & OMEdebugLogLevel3) { std::cout << count << " active objects in database\n"; if (delCount != 0) std::cout << "Deleted " << delCount << " temporary objects\n"; std::cout.flush(); } return (count); } static int PDopenDB(const char *fileName) { PDdbHandle = dbm_open((char *) fileName, O_CREAT | O_RDWR, 0600); if (PDdbHandle == 0) return (-1); return (0); } static int PDcloseDB() { dbm_close(PDdbHandle); return (0); } static int OMEobjDBloop() { OMEtype mess, dest, nil; OMEtype methodName, args, fromObj, targetObj, context, user; OMEassoc acl; int rc, count; rc = PDopenDB(dbFileName); if (rc != 0) { std::cerr << "OMEpersistd: could not open database " << dbFileName << "\n"; return (rc); // exit... } count = 0; while (1) { api = new OMEapi(acl, addr); rc = api->establishConnection(connectionUserInfo); if (rc == 0) break; // success.. delete api; api = 0; if (count == 3) { std::cerr << "OMEpersistd: could not connect to " << addr << "\n"; return (2); } ++count; #ifdef _WIN32 SleepEx(3 * 1000, FALSE); #else sleep(3); #endif } // send "createTemporaryObject"("PersistenceTemporaryService", acl, // thisServiceName, thisObject, pagerServiceName, thisServiceName) // to peerObject; api->getPeerObject(dest); methodName = "createTemporaryObject"; args.initializeAsType(OME_ARRAY); args[(uint32) 0] = "PersistenceTemporaryService"; args[(uint32) 1].initializeAsType(OME_NIL); // nil == default ACL args[(uint32) 2] = thisServiceName; api->getThisObject(args[(uint32) 3]); // name of PersistenceService args[(uint32) 4] = pagerServiceName; // how this process is registered using databaseConnected method below args[(uint32) 5] = thisServiceName; rc = api->invokeMethod(dest, methodName, args); if (rc != 0) { std::cerr << "OMEpersistd: could not invoke method " << methodName << "\n"; delete api; return (3); } do { rc = api->importInvocation(methodName, args, &fromObj, &targetObj, &context, &user); if (rc != 0) { std::cerr << "OMEpersistd: could not retrieve registration oid\n"; delete api; return (3); } // NOTE: we might get unexpected messages from other objects, // such as AnnounceServices, so watch for our "reply" before // proceeding and invoking databaseConnected. //std::cout << "Imported method=" << methodName << "\n"; } while (methodName != "reply"); methodName = "databaseConnected"; args.initializeAsType(OME_ARRAY); args[(uint32) 0] = thisServiceName; dest = pagerServiceName; rc = api->invokeMethod(dest, methodName, args); if (rc != 0) { std::cerr << "OMEpersistd: could invoke method " << methodName << "\n"; delete api; return (3); } // perform service... do { rc = api->importInvocation(methodName, args, &fromObj, &targetObj, &context, &user); if (rc != 0) break; // validity check: could verify if targetObj == thisObject if (OMEdebugFlag & OMEdebugLogLevel1) { std::cerr << "methodName=" << methodName << "\n"; std::cerr.flush(); } if (*methodName.value.s == "saveObject") { rc = doSaveObject(args, fromObj, context, user); args.initializeAsType(OME_ARRAY); args[(uint32) 0] = rc; rc = api->invokeMethod(fromObj, replyMethodName, args); } else if ((*methodName.value.s == "restoreObject") || (*methodName.value.s == "objectFault")) { OMEtype resultVec(OME_ARRAY); rc = doRestoreObject(resultVec, args, fromObj, context, user); rc = api->invokeMethod(fromObj, replyMethodName, resultVec); } else if (*methodName.value.s == "removeObject") { rc = doRemoveObject(args, fromObj, context, user); args.initializeAsType(OME_ARRAY); args[(uint32) 0] = rc; rc = api->invokeMethod(fromObj, replyMethodName, args); } else if (*methodName.value.s == "stopService") { args.initializeAsType(OME_ARRAY); args[(uint32) 0] = 1; rc = api->invokeMethod(fromObj, replyMethodName, args); rc = 1; } else if (*methodName.value.s == "listObjects") { OMEtype resultVec(OME_ARRAY); rc = doListObjects(resultVec[(uint32) 0], args, fromObj, context, user); rc = api->invokeMethod(fromObj, replyMethodName, resultVec); } else { std::cerr << "unrecognized methodName=" << methodName << "\n"; std::cerr.flush(); } if (rc != 0) break; } while (OMEstopFlag.value.ui == 0); delete api; // always close open database... PDcloseDB(); if ((rc != 1) && (OMEstopFlag.value.ui == 0)) { std::cerr << "OMEpersistd: error, rc=" << rc << "\n"; return (rc); } return (0); } static void usageMess(char *argv[]) { std::cerr << "usage: " << argv[0] << " [-s] [-n serviceName][-domain vistaDomain -secret secretPhrase] tcp:addr:port [dbFile=vistaObjects.vdb]\n"; } int main(int argc, char *argv[]) { int i, rc, runAsService; if (argc < 2) { usageMess(argv); return (1); } strcpy(pagerServiceName, OBJECT_PAGER_SERVICE); strcpy(thisServiceName, REGISTERED_AS); OMEinitDebugFlag(); runAsService = 0; for(i=1;i= argc) break; OMEsetDebugFlag(argv[i], 0); } else if (strcmp(argv[i], "+d") == 0) { if (++i >= argc) break; OMEsetDebugFlag(argv[i], 1); } else if (strcmp(argv[i], "-domain") == 0) { if (++i >= argc) break; if (connectionUserInfo.type != OME_ARRAY) { connectionUserInfo.initializeAsType(OME_ARRAY); } connectionUserInfo[(uint32) 0] = argv[i]; // VISTA domain name } else if (strcmp(argv[i], "-secret") == 0) { if (++i >= argc) break; if (connectionUserInfo.type != OME_ARRAY) { connectionUserInfo.initializeAsType(OME_ARRAY); } connectionUserInfo[(uint32) 1] = argv[i]; // secret // blank argument memset(argv[i], '\0', strlen(argv[i])); } else if (strcmp(argv[i], "-name") == 0) { if (++i >= argc) break; if ((strlen(argv[i]) + strlen(pagerServiceName)) > (sizeof(pagerServiceName) - 16)) { std::cerr << "service name too long\n"; return (2); } strcat(pagerServiceName, "/"); strcat(pagerServiceName, argv[i]); strcat(thisServiceName, ":"); strcat(thisServiceName, argv[i]); } else break; } if (i == argc) { usageMess(argv); return (1); } if (OMEdebugFlag & OMEdebugLogLevel3) { std::cerr << "FARGOS/VISTA OME Persistent Object Database Daemon\n"; std::cerr << "Copyright (C) 2001 - 2002 FARGOS Development, LLC. All rights reserved.\n"; std::cerr << "Using " << pagerServiceName << " registered as " << thisServiceName << "\n"; } #ifdef _WIN32 initWinsock(); #endif OMEloadVersion1Encodings(); OMEregisterStandardSocketSchemes(); addr[sizeof(addr) - 2] = '\0'; // save space for ",c" strncpy(addr, argv[i], sizeof(addr) - 3); strcat(addr, ",c"); ++i; if (argc > i) { dbFileName = argv[i]; } else { dbFileName = "vistaObjects.vdb"; } replyMethodName = "reply"; if (runAsService == 0) { OMEobjDBloop(); return (0); } // run as a service... #ifdef _WIN32 OMErunAsWindowsService("OMEpersistd", OMEobjDBloop); ExitProcess(0); #else OMEobjDBloop(); #endif return (0); // normal stop... }