/** * Sample object echoing back all parameters * * @param properties [IN] See description in VXIobjectExecute() * or VXIobjectValidate() * @param parameters [IN] See description in VXIobjectExecute() * or VXIobjectValidate() * @param execute [IN] Specifies whether the object should be * executed (true) or simply validated (false) * @param result [OUT] See description in VXIobjectExecute() * or VXIobjectValidate() * * @result VXIobj_RESULT_SUCCESS on success */ static VXIobjResult ProcessComSpeechworksEchoObject (struct VXIobjectInterface *pThis, const VXIMap *properties, const VXIMap *parameters, VXIbool execute, VXIValue **result) { static const wchar_t func[] = L"ProcessComSpeechworksEchoObject"; GET_VXIOBJECT (pThis, sbObject, log, rc); if((execute) && (result == NULL)) return VXIobj_RESULT_INVALID_ARGUMENT; if((! properties) || (! parameters)) return VXIobj_RESULT_INVALID_ARGUMENT; if(execute) { // Create the result object VXIMap *resultObj = VXIMapCreate(); if(resultObj == NULL) { Error(log, 100, NULL); return VXIobj_RESULT_OUT_OF_MEMORY; } *result = reinterpret_cast<VXIValue *>(resultObj); // Simply add the input properties and parameters to the result object VXIMapSetProperty(resultObj, L"attributes", VXIValueClone((VXIValue *)properties)); VXIMapSetProperty(resultObj, L"parameters", VXIValueClone((VXIValue *)parameters)); } return VXIobj_RESULT_SUCCESS; }
/** * Sample object setting the defaults document for subsequent calls * * @param properties [IN] See description in VXIobjectExecute() * or VXIobjectValidate() * @param parameters [IN] See description in VXIobjectExecute() * or VXIobjectValidate() * @param execute [IN] Specifies whether the object should be * executed (true) or simply validated (false) * @param result [OUT] See description in VXIobjectExecute() * or VXIobjectValidate() * * @result VXIobj_RESULT_SUCCESS on success */ static VXIobjResult ProcessComSpeechworksSetDefaultsObject (struct VXIobjectInterface *pThis, const VXIMap *properties, const VXIMap *parameters, VXIbool execute, VXIValue **result) { static const wchar_t func[] = L"ProcessComSpeechworksSetDefaults"; GET_VXIOBJECT (pThis, sbObject, log, rc); if((execute) && (result == NULL)) return VXIobj_RESULT_INVALID_ARGUMENT; if((! properties) || (! parameters)) return VXIobj_RESULT_INVALID_ARGUMENT; if(execute) { const VXIchar *defaults = NULL; const VXIValue *val = VXIMapGetProperty(parameters, L"defaults"); if (! val) { Error(log, 202, L"%s%s", L"parameter", L"defaults"); return VXIobj_RESULT_INVALID_PROP_VALUE; } else if (VXIValueGetType(val) != VALUE_STRING) { Error(log, 203, L"%s%s%s%d", L"parameter", L"defaults", L"type", VXIValueGetType(val)); return VXIobj_RESULT_INVALID_PROP_VALUE; } defaults = VXIStringCStr(reinterpret_cast<const VXIString *>(val)); if (! defaults[0]) { Error(log, 204, L"%s%s%s%s", L"parameter", L"defaults", L"value", defaults); return VXIobj_RESULT_INVALID_PROP_VALUE; } // Hack to set the defaults document VXIobjectAPI *objectAPI = (VXIobjectAPI *) pThis; if ( ! objectAPI ) { rc = VXIobj_RESULT_INVALID_ARGUMENT; return rc; } VXIplatform *plat = objectAPI->resources->platform; VXIMap *vxiProperties = VXIMapCreate(); VXIString * valstr = VXIStringCreate(defaults); VXIMapSetProperty(vxiProperties, VXI_PLATFORM_DEFAULTS, (VXIValue *) valstr); plat->VXIinterpreter->SetProperties(plat->VXIinterpreter, vxiProperties); // Create the result object VXIMap *resultObj = VXIMapCreate(); if(resultObj == NULL) { Error(log, 100, NULL); return VXIobj_RESULT_OUT_OF_MEMORY; } *result = reinterpret_cast<VXIValue *>(resultObj); // Set the result object's status field to 'success' VXIMapSetProperty(resultObj, L"status", reinterpret_cast<VXIValue *>(VXIStringCreate(L"success"))); } return VXIobj_RESULT_SUCCESS; }
inline void AddParamValue(VXIMapHolder & m, const vxistring & name, VXIflt32 value) { if (m.GetValue() == NULL) return; VXIFloat * val = VXIFloatCreate(value); if (val == NULL) throw VXIException::OutOfMemory(); VXIMapSetProperty(m.GetValue(), name.c_str(), reinterpret_cast<VXIValue *>(val)); }
inline void AddParamValue(VXIMapHolder & m, const vxistring & name, bool value) { if (m.GetValue() == NULL) return; VXIBoolean * val = VXIBooleanCreate((value ? TRUE : FALSE)); if (val == NULL) throw VXIException::OutOfMemory(); VXIMapSetProperty(m.GetValue(), name.c_str(), reinterpret_cast<VXIValue *>(val)); }
/** * Bridging Transfer. * */ static VXItelResult OSBtelTransferBridge(VXItelInterface * vxip, const VXIMap * prop, const VXIchar * transferDestination, const VXIMap * data, VXIMap **resp) { OSBtelImpl *impl = ToOSBtelImpl(vxip); Diag(impl, DIAG_TAG_SIGNALING, NULL, L"TransferBridge: %s", transferDestination); *resp = VXIMapCreate(); VXIchar* dest = 0; VXIchar* xaudio = 0; if (prop != NULL) { VXIString* vect =(VXIString*)VXIMapGetProperty(prop, L"Destination"); if (vect != NULL) dest = (VXIchar*) VXIStringCStr(vect); vect =(VXIString*)VXIMapGetProperty(prop, TEL_TRANSFER_AUDIO); if (vect != NULL) xaudio = (VXIchar*) VXIStringCStr(vect); } *resp = VXIMapCreate(); if (impl->callId && transferDestination) { vxistring dest = transferDestination; if (! dest.empty()) { char* str = 0; int len = dest.length() + 1; if (len > 0) { str = new char [len + 1]; wcstombs(str, transferDestination, len); str[len] = 0; } if (str) { UtlString from(str); HttpMessage::unescape( from ); if (impl->live == 1) { impl->pCallMgr->connect((char*)impl->callId, from.data()); impl->transferred = 0; int state = 0; int status = VXItel_TRANSFER_UNKNOWN; int duration = 0; OsTime startTime; OsTime endTime; OsDateTimeBase::getCurTime(startTime); VXItelResult ret; do { ret = setTransferState(impl, prop, transferDestination, resp, &state, &status); } while (state != PtEvent::CONNECTION_DISCONNECTED && state != PtEvent::CONNECTION_FAILED && ret != VXItel_RESULT_TIMEOUT); OsDateTimeBase::getCurTime(endTime); duration = (endTime.cvtToMsecs() - startTime.cvtToMsecs())/1000; VXIMapSetProperty(*resp, TEL_TRANSFER_STATUS, (VXIValue *) VXIIntegerCreate(status)); VXIMapSetProperty(*resp, TEL_TRANSFER_DURATION, (VXIValue *)VXIIntegerCreate(duration)); } else { Diag(impl, DIAG_TAG_SIGNALING, NULL, L"Exiting called, live=%d, cancel TransferBridge: %s", impl->live, transferDestination); } } } } return VXItel_RESULT_SUCCESS; }
/** * Blind Transfer. */ static VXItelResult OSBtelTransferBlind(VXItelInterface * vxip, const VXIMap * prop, const VXIchar * transferDestination, const VXIMap * data, VXIMap ** resp) { OSBtelImpl *impl = ToOSBtelImpl(vxip); Diag(impl, DIAG_TAG_SIGNALING, NULL, L"TransferBlind: %s", transferDestination); VXIchar* best = (VXIchar *) calloc(128, sizeof(VXIchar)); if (prop != NULL) { VXIString* vect =(VXIString*)VXIMapGetProperty(prop, L"Destination"); if (vect != NULL) best = (VXIchar*) VXIStringCStr(vect); } *resp = VXIMapCreate(); if (impl->callId && transferDestination) { vxistring dest = transferDestination; if (! dest.empty()) { char* str = 0; int len = dest.length() + 1; if (len > 0) { str = new char [len + 1]; wcstombs(str, transferDestination, len); str[len] = 0; } if (str) { UtlString from(str); HttpMessage::unescape( from ); OsSysLog::add(FAC_MEDIASERVER_VXI, PRI_DEBUG, "OSBtelTransferBlind from = '%s'", from.data()); if (impl->live == 1) { if (PT_SUCCESS == impl->pCallMgr->transfer_blind((char*)impl->callId, from.data(), // to url 0, // target call id 0, // target connect addr false // no remote hold first ) ) { impl->transferred = 0; int state = 0; int status = VXItel_TRANSFER_UNKNOWN; int duration = 0; OsTime startTime; OsTime endTime; OsDateTimeBase::getCurTime(startTime); setTransferState(impl, prop, transferDestination, resp, &state, &status); OsDateTimeBase::getCurTime(endTime); duration = (endTime.cvtToMsecs() - startTime.cvtToMsecs())/1000; VXIMapSetProperty(*resp, TEL_TRANSFER_STATUS, (VXIValue *) VXIIntegerCreate(status)); VXIMapSetProperty(*resp, TEL_TRANSFER_DURATION, (VXIValue *)VXIIntegerCreate(duration)); } } else { Diag(impl, DIAG_TAG_SIGNALING, NULL, L"Exiting called, live=%d, cancel TransferBlind: %s", impl->live, transferDestination); } } } } return VXItel_RESULT_SUCCESS; }
// Open an entry VXIcacheResult SBcacheManager::Open(VXIlogInterface *log, const SBcacheString &moduleName, const SBcacheKey &key, VXIcacheOpenMode mode, VXIint32 flags, const VXIMap *properties, VXIMap *streamInfo, VXIcacheStream **stream) { VXIcacheResult rc = VXIcache_RESULT_SUCCESS; // Big loop where we attempt to open and re-open the cache entry for // as long as we get recoverable errors VXIcacheOpenMode finalMode; do { finalMode = mode; rc = VXIcache_RESULT_SUCCESS; if ( _entryTableMutex.StartRead( ) != VXItrd_RESULT_SUCCESS ) { Error (log, 110, L"%s%s", L"mutex", L"entry table mutex"); return VXIcache_RESULT_SYSTEM_ERROR; } // Find the entry and open it, only need read permission bool entryOpened = false; SBcacheEntry entry; SBcacheEntryTable::iterator vi = _entryTable.find (key); if ( vi == _entryTable.end( ) ) { rc = VXIcache_RESULT_NOT_FOUND; } else { entry = (*vi).second; finalMode = (mode == CACHE_MODE_READ_CREATE ? CACHE_MODE_READ : mode); } if ( _entryTableMutex.EndRead( ) != VXItrd_RESULT_SUCCESS ) { Error (log, 111, L"%s%s", L"mutex", L"entry table mutex"); rc = VXIcache_RESULT_SYSTEM_ERROR; } // For write and read/create mode, create the entry if not found if (( rc == VXIcache_RESULT_NOT_FOUND ) && ( mode != CACHE_MODE_READ )) { rc = VXIcache_RESULT_SUCCESS; // Get write permission if ( _entryTableMutex.Lock( ) != VXItrd_RESULT_SUCCESS ) { Error (log, 110, L"%s%s", L"mutex", L"entry table mutex"); rc = VXIcache_RESULT_SYSTEM_ERROR; } else { // Try to find the entry again, it may have been created by now vi = _entryTable.find (key); if ( vi != _entryTable.end( ) ) { // Found it this time entry = (*vi).second; finalMode = (mode == CACHE_MODE_READ_CREATE ? CACHE_MODE_READ : mode); } else { // Create and open the entry for write rc = entry.Create (GetLog( ), GetDiagBase( ), _refCntMutexPool.GetMutex( )); if ( rc == VXIcache_RESULT_SUCCESS ) { finalMode = (mode == CACHE_MODE_READ_CREATE ? CACHE_MODE_WRITE : mode); // Note entry lock obtained while entrytable lock is held! We // can get away with this, because the lock isn't visible to // anyone else yet. rc = entry.Open (log, moduleName, key, GetNewEntryPath (moduleName, key), finalMode, flags, _entryMaxSizeBytes, properties, streamInfo, stream); } // Insert the entry if ( rc == VXIcache_RESULT_SUCCESS ) { entryOpened = true; SBcacheEntryTable::value_type tableEntry (key, entry); if ( !InsertEntry(entry)) { Error (log, 100, NULL); (*stream)->Close (true); *stream = NULL; rc = VXIcache_RESULT_OUT_OF_MEMORY; } } } if ( _entryTableMutex.Unlock( ) != VXItrd_RESULT_SUCCESS ) { Error (log, 111, L"%s%s", L"mutex", L"entry table mutex"); rc = VXIcache_RESULT_SYSTEM_ERROR; } } } // Open pre-existing entry. Note that this may return // VXIcache_RESULT_FAILURE in some cases where we then need to // retry the entire process of opening the entry -- that occurs // when a writer opens the entry, we attempt to open for read // access here before the writer finishes writing the entry, then // the writer invalidates the entry on us. When that happens, if // we're attempting MODE_READ_CREATE we want to get that invalid // entry out of the table and create the entry ourselves returning // in WRITE mode, for MODE_READ we just want to see if another // writer has created a new entry that is valid for us to use // otherwise we bail out with the normal RESULT_NOT_FOUND. if (( rc == VXIcache_RESULT_SUCCESS ) && ( ! entryOpened )) { // If this is a write over an existing entry, wipe the previous entry // accounting from the cache. if (finalMode == CACHE_MODE_WRITE) _curSizeBytes.Decrement(entry.GetSizeBytes(false)); rc = entry.Open (log, moduleName, key, entry.GetPath( ), finalMode, flags, _entryMaxSizeBytes, properties, streamInfo, stream); // Don't let a corrupt entry persist if (( rc != VXIcache_RESULT_SUCCESS ) && ( rc != VXIcache_RESULT_FAILURE )) Delete (log, key); } // Accessed, so move it to the top of the LRU list if ( _entryTableMutex.Lock( ) != VXItrd_RESULT_SUCCESS ) { Error (log, 110, L"%s%s", L"mutex", L"entry table mutex"); rc = VXIcache_RESULT_SYSTEM_ERROR; } else { if (rc == VXIcache_RESULT_SUCCESS) TouchEntry(entry); if ( _entryTableMutex.Unlock( ) != VXItrd_RESULT_SUCCESS ) { Error (log, 111, L"%s%s", L"mutex", L"entry table mutex"); rc = VXIcache_RESULT_SYSTEM_ERROR; } } } while ( rc == VXIcache_RESULT_FAILURE ); // Finish up returning the stream information if (( rc == VXIcache_RESULT_SUCCESS ) && ( streamInfo ) && ( VXIMapSetProperty (streamInfo, CACHE_INFO_FINAL_KEY, (VXIValue *) VXIStringCreate(key.c_str( ))) != VXIvalue_RESULT_SUCCESS )) { Error (log, 100, NULL); (*stream)->Close (true); *stream = NULL; rc = VXIcache_RESULT_OUT_OF_MEMORY; } if (( rc == VXIcache_RESULT_SUCCESS ) && ( mode == CACHE_MODE_READ_CREATE ) && ( finalMode == CACHE_MODE_WRITE )) rc = VXIcache_RESULT_ENTRY_CREATED; // Maybe do cleanup, ignore all but fatal errors VXIcacheResult rc2 = Cleanup (false, key); if ( rc2 < VXIcache_RESULT_SUCCESS ) { (*stream)->Close (true); *stream = NULL; rc = rc2; } Diag (log, SBCACHE_MGR_TAGID, L"Open", L"%s: rc = %d", key.c_str( ), rc); return rc; }
/** * Sample object to save a recording to a file * * @param properties [IN] See description in VXIobjectExecute() * or VXIobjectValidate() * @param parameters [IN] See description in VXIobjectExecute() * or VXIobjectValidate() * @param execute [IN] Specifies whether the object should be * executed (true) or simply validated (false) * @param result [OUT] See description in VXIobjectExecute() * or VXIobjectValidate() * * @result VXIobj_RESULT_SUCCESS on success */ static VXIobjResult ProcessComSpeechworksSaveRecordingObject (struct VXIobjectInterface *pThis, const VXIMap *properties, const VXIMap *parameters, VXIbool execute, VXIValue **result) { static const wchar_t func[] = L"ProcessComSpeechworksSaveRecordingObject"; GET_VXIOBJECT (pThis, sbObject, log, rc); if((execute) && (result == NULL)) return VXIobj_RESULT_INVALID_ARGUMENT; if((! properties) || (! parameters)) return VXIobj_RESULT_INVALID_ARGUMENT; // Get the recording, MIME type, size, and destination path const VXIbyte *recording = NULL; const VXIchar *type = NULL, *dest = NULL; VXIulong size = 0; const VXIValue *val = VXIMapGetProperty(parameters, L"recording"); if (! val) { Error(log, 202, L"%s%s", L"parameter", L"recording"); return VXIobj_RESULT_INVALID_PROP_VALUE; } else if (VXIValueGetType(val) != VALUE_CONTENT) { Error(log, 203, L"%s%s%s%d", L"parameter", L"recording", L"type", VXIValueGetType(val)); return VXIobj_RESULT_INVALID_PROP_VALUE; } if (VXIContentValue(reinterpret_cast<const VXIContent *>(val), &type, &recording, &size) != VXIvalue_RESULT_SUCCESS) { Error(log, 204, L"%s%s", L"parameter", L"recording"); return VXIobj_RESULT_INVALID_PROP_VALUE; } else if (size < 1) { Error(log, 204, L"%s%s%s%d", L"parameter", L"recording.size", L"value", L"size"); return VXIobj_RESULT_INVALID_PROP_VALUE; } val = VXIMapGetProperty(parameters, L"dest"); if (! val) { Error(log, 202, L"%s%s", L"parameter", L"dest"); return VXIobj_RESULT_INVALID_PROP_VALUE; } else if (VXIValueGetType(val) != VALUE_STRING) { Error(log, 203, L"%s%s%s%d", L"parameter", L"dest", L"type", VXIValueGetType(val)); return VXIobj_RESULT_INVALID_PROP_VALUE; } dest = VXIStringCStr(reinterpret_cast<const VXIString *>(val)); if (! dest[0]) { Error(log, 204, L"%s%s%s%s", L"parameter", L"dest", L"value", dest); return VXIobj_RESULT_INVALID_PROP_VALUE; } if(execute) { // Convert the destination to narrow characters, use an upside // down question mark for unsupported Unicode characters size_t len = wcslen(dest); char *ndest = new char [len + 1]; if (! ndest) { Error(log, 100, NULL); return VXIobj_RESULT_OUT_OF_MEMORY; } for (size_t i = 0; i <= len; i++) ndest[i] = (dest[i] & 0xff00 ? '\277' : static_cast<char>(dest[i])); // Open the destination and save the file size_t totWritten = 0; #ifdef VXIOBJECT_PERMIT_FILE_WRITES FILE *fp = fopen(ndest, "wb"); delete [] ndest; if (fp) { do { size_t w = fwrite(&recording[totWritten], 1, ((size_t) size) - totWritten, fp); totWritten += w; } while ((totWritten < (size_t) size) && (! ferror(fp))); fclose(fp); } else { Error(log, 205, L"%s%s%s%d", L"file", dest, L"errno", errno); } #else Error(log, 206, L"%s%s", L"file", dest); #endif // Create the result object VXIMap *resultObj = VXIMapCreate(); if(resultObj == NULL) { Error(log, 100, NULL); return VXIobj_RESULT_OUT_OF_MEMORY; } *result = reinterpret_cast<VXIValue *>(resultObj); // Set the result object's status field to 'success' or 'failure' if (totWritten == (size_t) size) VXIMapSetProperty(resultObj, L"status", reinterpret_cast<VXIValue *>(VXIStringCreate(L"success"))); else VXIMapSetProperty(resultObj, L"status", reinterpret_cast<VXIValue *>(VXIStringCreate(L"failure"))); } return VXIobj_RESULT_SUCCESS; }
/** * Sample diagnostic logging object * * @param properties [IN] See description in VXIobjectExecute() * or VXIobjectValidate() * @param parameters [IN] See description in VXIobjectExecute() * or VXIobjectValidate() * @param execute [IN] Specifies whether the object should be * executed (true) or simply validated (false) * @param result [OUT] See description in VXIobjectExecute() * or VXIobjectValidate() * * @result VXIobj_RESULT_SUCCESS on success */ static VXIobjResult ProcessComSpeechworksDiagObject (struct VXIobjectInterface *pThis, const VXIMap *properties, const VXIMap *parameters, VXIbool execute, VXIValue **result) { static const wchar_t func[] = L"ProcessComSpeechworksDiagObject"; GET_VXIOBJECT (pThis, sbObject, log, rc); if((execute) && (result == NULL)) return VXIobj_RESULT_INVALID_ARGUMENT; if((! properties) || (! parameters)) return VXIobj_RESULT_INVALID_ARGUMENT; // Get the tag ID const VXIValue *val = VXIMapGetProperty(parameters, L"tag"); if(val == NULL) { Error(log, 202, L"%s%s", L"parameter", L"tag"); return VXIobj_RESULT_INVALID_PROP_VALUE; } VXIint tag; switch (VXIValueGetType(val)) { case VALUE_INTEGER: tag = VXIIntegerValue((VXIInteger *)val); break; case VALUE_STRING: { wchar_t *ptr; tag = ::wcstol(VXIStringCStr((VXIString *)val), &ptr, 10); } break; default: Error(log, 203, L"%s%s%s%d", L"parameter", L"tag", L"type", VXIValueGetType(val)); return VXIobj_RESULT_INVALID_PROP_VALUE; } // Get the message string val = VXIMapGetProperty(parameters, L"message"); if(val == NULL) { Error(log, 202, L"%s%s", L"parameter", L"message"); return VXIobj_RESULT_INVALID_PROP_VALUE; } // Check whether the message was sent in "data" or "ref" format. // If it is "ref", we need to retrieve it in the embedded map. const VXIchar *messageStr = NULL; switch (VXIValueGetType(val)) { case VALUE_MAP: { const VXIValue *val2 = VXIMapGetProperty((const VXIMap *)val, OBJECT_VALUE); if (VXIValueGetType(val2) == VALUE_STRING) messageStr = VXIStringCStr((VXIString *)val2); } break; case VALUE_STRING: messageStr = VXIStringCStr((VXIString *)val); break; default: Error(log, 203, L"%s%s%s%d", L"parameter", L"message", L"type", VXIValueGetType(val)); return VXIobj_RESULT_INVALID_PROP_VALUE; } if ((! messageStr) || (! messageStr[0])) { Error(log, 204, L"%s%s", L"parameter", L"message"); return VXIobj_RESULT_INVALID_PROP_VALUE; } if(execute) { // Print a diagnostic message using the retrieved arguments. // To see this message, you must enable client.log.diagTag.xxx // in your VXIclient configuration file, where 'xxx' is the // value of client.object.diagLogBase defined in the same file. VXIlogResult rc = Diag (log, tag, NULL, messageStr); // Create the result object VXIMap *resultObj = VXIMapCreate(); if(resultObj == NULL) { Error(log, 100, NULL); return VXIobj_RESULT_OUT_OF_MEMORY; } *result = reinterpret_cast<VXIValue *>(resultObj); // Set the result object's status field to 'success' or 'failure' if(rc == VXIlog_RESULT_SUCCESS) VXIMapSetProperty(resultObj, L"status", reinterpret_cast<VXIValue *>(VXIStringCreate(L"success"))); else VXIMapSetProperty(resultObj, L"status", reinterpret_cast<VXIValue *>(VXIStringCreate(L"failure"))); } return VXIobj_RESULT_SUCCESS; }
// Open the entry VXIcacheResult SBcacheEntryDetails::Open(VXIlogInterface *log, const SBcacheString &moduleName, const SBcacheKey &key, const SBcachePath &path, VXIcacheOpenMode mode, VXIint32 flags, VXIulong maxSizeBytes, const VXIMap *properties, VXIMap *streamInfo, VXIcacheStream **stream) { VXIcacheResult rc = VXIcache_RESULT_SUCCESS; FILE *filePtr = NULL; // Lock and copy input data switch ( mode ) { case CACHE_MODE_WRITE: if ( _rwMutex.Lock( ) != VXItrd_RESULT_SUCCESS ) { Error (log, 110, L"%s%s", L"mutex", L"cache entry rw mutex, writer"); rc = VXIcache_RESULT_SYSTEM_ERROR; } else { // If the open fails due to directory not existing, call // path.CreateDirectories( ) to create the dir tree then open // again if ( ! _invalidated ) { filePtr = fopen (path.c_str( ), "wb"); int retries = 10; // work around possible race condition w/ rmdir while ((retries-- > 0) && ( ! filePtr ) && ( path.CreateDirectories( ) == VXIcache_RESULT_SUCCESS )) filePtr = fopen (path.c_str( ), "wb"); } if ( ! filePtr ) { if ( _invalidated ) { // Invalidated or another thread attempted an open for write // and failed, we only got here due to a race condition // where we were waiting on the mutex to start our write // before the failure/invalidation happened by the previous // writer rc = VXIcache_RESULT_FAILURE; } else { // File open error LogIOError (log, 213, path); rc = VXIcache_RESULT_IO_ERROR; } _fileExists = false; _rwMutex.Unlock( ); } else { _fileExists = true; _creationCost = CACHE_CREATION_COST_DEFAULT; _flags = flags; _sizeBytes = 0; // Only set the path and key if they differ if (path != _path || key != _key) { _path = path; _key = key; } // Load properties if ( properties ) { const VXIValue *value = VXIMapGetProperty (properties, CACHE_CREATION_COST); if ( value ) { if ( VXIValueGetType(value) == VALUE_INTEGER ) _creationCost = (VXIcacheCreationCost) VXIIntegerValue ((const VXIInteger *) value); else Error (log, 301, L"%s%d", L"VXIValueType", VXIValueGetType(value)); } } } } break; case CACHE_MODE_READ: if ( _rwMutex.StartRead( ) != VXItrd_RESULT_SUCCESS ) { Error (log, 110, L"%s%s", L"mutex", L"cache entry rw mutex, reader"); rc = VXIcache_RESULT_SYSTEM_ERROR; } else { if (( _fileExists ) && ( ! _invalidated )) { filePtr = fopen (_path.c_str( ), "rb"); if ( ! filePtr ) { _fileExists = false; LogIOError (log, 214, _path); _rwMutex.EndRead( ); rc = VXIcache_RESULT_IO_ERROR; } } else { // Invalidated or another thread attempted an open for write // and failed, we only got here due to a race condition where // we were waiting on the mutex to start our read before the // failure/invalidation happened by the writer _rwMutex.EndRead( ); rc = VXIcache_RESULT_FAILURE; } } break; default: Error (log, 215, L"%s%d", L"mode", mode); rc = VXIcache_RESULT_UNSUPPORTED; } if ( rc == VXIcache_RESULT_SUCCESS ) { // Update the accessed time _lastAccessed = time(0); if (mode == CACHE_MODE_WRITE) _lastModified = _lastAccessed; // Return stream information if ( streamInfo ) { if (( VXIMapSetProperty (streamInfo, CACHE_INFO_LAST_MODIFIED, (VXIValue *) VXIIntegerCreate(_lastModified)) != VXIvalue_RESULT_SUCCESS ) || ( VXIMapSetProperty (streamInfo, CACHE_INFO_SIZE_BYTES, (VXIValue *) VXIIntegerCreate (_sizeBytes)) != VXIvalue_RESULT_SUCCESS )) { Error (log, 100, NULL); rc = VXIcache_RESULT_OUT_OF_MEMORY; } } } // Return the stream if ( rc == VXIcache_RESULT_SUCCESS ) { SBcacheEntry entry(this); *stream = new SBcacheStream (log, GetDiagBase( ), moduleName, key, entry, mode, ((flags & CACHE_FLAG_NONBLOCKING_IO) == 0), maxSizeBytes, filePtr); if ( ! *stream ) { Error (log, 100, NULL); fclose (filePtr); Close (log, mode, 0, true); rc = VXIcache_RESULT_OUT_OF_MEMORY; } } Diag (log, SBCACHE_ENTRY_TAGID, L"Open", L"%s, %S, 0x%x, 0x%x: rc = %d", key.c_str( ), path.c_str( ), mode, flags, rc); return rc; }
VXIinetResult SBinetFileStream::Open(VXIint32 flags, const VXIMap *properties, VXIMap *streamInfo) { VXIinetResult returnValue = VXIinet_RESULT_SUCCESS; /* Get the flag to determine whether to open local files. Also check the validator to see if it contains INET_INFO_VALIDATOR and if it does contain the modified time. */ SBinetValidator validator(GetLog(), GetDiagBase()); const VXIValue *validatorVal = NULL; if (properties) { const VXIValue *val = VXIMapGetProperty(properties, INET_OPEN_LOCAL_FILE); if (val != NULL) { if (VXIValueGetType(val) == VALUE_INTEGER) { if (VXIIntegerValue((const VXIInteger *) val) == FALSE) returnValue = VXIinet_RESULT_LOCAL_FILE; } else { Diag(MODULE_SBINET_STREAM_TAGID, L"SBinetFileStream::Open", L"Passed invalid type for INET_OPEN_LOCAL_FILE property"); } } // SBinetValidator::Create() logs errors for us validatorVal = VXIMapGetProperty(properties, INET_OPEN_IF_MODIFIED); if((validatorVal != NULL) && (validator.Create(validatorVal) != VXIinet_RESULT_SUCCESS)) validatorVal = NULL; } Diag(MODULE_SBINET_STREAM_TAGID, L"SBinetFileStream::Open", _url->getAbsolute( )); // Stat the file to make sure it exists and to get the length and // last modified time VXIStatStruct statInfo; if (VXIStat(SBinetNString(_url->getPath()).c_str(), &statInfo) != 0) { Error(222, L"%s%s", L"File", _url->getPath()); return(VXIinet_RESULT_NOT_FOUND); } _content_length = statInfo.st_size; // If there is a conditional open using a validator, see if the // validator is still valid (no need to re-read and re-process) if (validatorVal) { if (! validator.isModified(statInfo.st_mtime, statInfo.st_size)) { Diag(MODULE_SBINET_STREAM_TAGID, L"SBinetFileStream::Open", L"Validator OK, returning NOT_MODIFIED"); returnValue = VXIinet_RESULT_NOT_MODIFIED; } else { Diag(MODULE_SBINET_STREAM_TAGID, L"SBinetFileStream::Open", L"Validator modified, must re-fetch"); } } if (returnValue != VXIinet_RESULT_LOCAL_FILE) { // Use fopen for now. Note: Open support reads for now _pFile = ::fopen( SBinetNString(_url->getPath()).c_str(), "rb" ); if(!_pFile){ Error(223, L"%s%s", L"File", _url->getPath()); return(VXIinet_RESULT_NOT_FOUND); } _ReadSoFar = 0; } if (streamInfo != NULL) { // Set FILE data source information VXIMapSetProperty(streamInfo, INET_INFO_DATA_SOURCE, (VXIValue*) VXIIntegerCreate(INET_DATA_SOURCE_FILE)); // Use extension mapping algorithm to determine MIME content type VXIString *guessContent = _url->getContentTypeFromUrl(); if (guessContent == NULL) { guessContent = VXIStringCreate(_channel->getDefaultMimeType()); // This error message is useful, but unfortunately it gets printed // for all the grammar files etc. whose extensions are unknown... //Error (303, L"%s%s", L"URL", _url->getPath()); } VXIMapSetProperty(streamInfo, INET_INFO_MIME_TYPE, (VXIValue*) guessContent); // Set the absolute path, any file:// prefix and host name is // already stripped prior to this method being invoked VXIMapSetProperty(streamInfo, INET_INFO_ABSOLUTE_NAME, (VXIValue*)VXIStringCreate( _url->getPath() )); // Set the validator property VXIValue *newValidator = NULL; if (returnValue == VXIinet_RESULT_NOT_MODIFIED) { newValidator = VXIValueClone(validatorVal); } else { SBinetValidator validator(GetLog(), GetDiagBase()); if (validator.Create(_url->getPath(), statInfo.st_size, statInfo.st_mtime) == VXIinet_RESULT_SUCCESS) { newValidator = (VXIValue *) validator.serialize(); } } if (newValidator) VXIMapSetProperty(streamInfo, INET_INFO_VALIDATOR, newValidator); else { Error(103, NULL); returnValue = VXIinet_RESULT_OUT_OF_MEMORY; } // Set the size VXIMapSetProperty(streamInfo, INET_INFO_SIZE_BYTES, (VXIValue*)VXIIntegerCreate( _content_length)); } if (!validatorVal && (returnValue == VXIinet_RESULT_NOT_MODIFIED)) return VXIinet_RESULT_SUCCESS; return returnValue; }