#ifdef WIN32 #include #else #ifdef USEPTHREADS #include #endif #include #include #endif #include #include #include #define ERR_MAX 179 //number of error codes. Increment, if you add a new error code ErrorMessage g_ddocErrorStrings[ERR_MAX] = { /* ERR_OK */ {"No errors", NO_ERRORS}, /* ERR_UNSUPPORTED_DIGEST */ {"Digest type is not supported", LIBRARY}, /* ERR_FILE_READ */ {"Could not open file for reading", USER}, /* ERR_FILE_WRITE */ {"Could not open file for writing", USER}, /* ERR_DIGEST_LEN */ {"Wrong digest length", LIBRARY}, /* ERR_BUF_LEN */ {"Insufficient target buffer length", LIBRARY}, /* ERR_SIGNATURE_LEN */ {"Wrong signature length", LIBRARY}, /* ERR_PRIVKEY_READ */ {"Failed to read the private key", TECHNICAL}, /* ERR_PUBKEY_READ */ {"Failed to read the public key", TECHNICAL}, /* ERR_CERT_READ */ {"Failed to read certificate", USER}, /* ERR_SIGNEDINFO_CREATE */ {"Could not create SignedInfo object", LIBRARY}, /* ERR_SIGNEDINFO_DATA */ {"Could not create SignedInfo object", LIBRARY}, /* ERR_SIGNEDINFO_FINAL */ {"Could not create SignedInfo object", LIBRARY}, /* ERR_UNSUPPORTED_FORMAT */ {"Wrong signed document format", TECHNICAL}, /* ERR_BAD_INDEX */ {"Bad index", LIBRARY}, /* ERR_TIMESTAMP_DECODE */ {"Failed to decode timestamp", TECHNICAL}, /* ERR_DIGIDOC_PARSE */ {"Error in document parsing", USER}, /* ERR_UNSUPPORTED_SIGNATURE */ {"Signature type is not supported", LIBRARY}, /* ERR_CERT_STORE_READ */ {"Could not read read certificate from certificate store", TECHNICAL}, /* ERR_SIGPROP_DIGEST */ {"Wrong signature properties digest", TECHNICAL}, /* ERR_COMPARE */ {"Wrong signature", USER}, /* ERR_DOC_DIGEST */ {"Wrong document digest", USER}, /* ERR_MIME_DIGEST */ {"Wrong document mime digest", TECHNICAL}, /* ERR_SIGNATURE */ {"Wrong signature", TECHNICAL}, /* ERR_CERT_INVALID */ {"Invalid certificate", TECHNICAL}, /* ERR_OCSP_UNSUCCESSFUL */ {"OCSP request unsuccessful", TECHNICAL}, /* ERR_OCSP_UNKNOWN_TYPE */ {"Unknown OCSP type", TECHNICAL}, /* ERR_OCSP_NO_BASIC_RESP */ {"No OCSP basic responce", TECHNICAL}, /* ERR_OCSP_WRONG_VERSION */ {"Wrong OCSP version", TECHNICAL}, /* ERR_OCSP_WRONG_RESPID */ {"Wrong OCSP response id", TECHNICAL}, /* ERR_OCSP_ONE_RESPONSE */ {"Incorrect OCSP response count", TECHNICAL}, /* ERR_OCSP_RESP_STATUS */ {"Incorrect OCSP response status", USER}, /* ERR_OCSP_NO_SINGLE_EXT */ {"No single OCSP responce", TECHNICAL}, /* ERR_OCSP_NO_NONCE */ {"NONCE is missing", LIBRARY}, /* ERR_NOTARY_NO_SIGNATURE */ {"Missing signature for Notary", TECHNICAL}, /* ERR_NOTARY_SIG_MATCH */ {"Notary signature mismatch", USER}, /* ERR_SIGNERS_CERT_NOT_TRUSTED */ {"Signers cert not trusted, missing CA cert!", USER}, /* ERR_WRONG_CERT */ {"Wrong certificate", USER}, /* ERR_NULL_POINTER */ {"Null pointer exception", LIBRARY}, /* ERR_NULL_CERT_POINTER */ {"Certificate pointer is null", LIBRARY}, /* ERR_NULL_SER_NUM_POINTER */ {"Certificate Number pointer is null", LIBRARY}, /* ERR_NULL_KEY_POINTER */ {"Key pointer is null", LIBRARY}, /* ERR_EMPTY_STRING */ {"Empty string", LIBRARY}, /* ERR_BAD_DATAFILE_INDEX */ {"Datafile index out of range", LIBRARY}, /* ERR_BAD_DATAFILE_COUNT */ {"Datafile count is out of sync", LIBRARY}, /* ERR_BAD_ATTR_COUNT */ {"Attribute counter is out of sync", LIBRARY}, /* ERR_BAD_ATTR_INDEX */ {"Attribute index is out of range", LIBRARY}, /* ERR_BAD_SIG_INDEX */ {"Signature index is out of range", LIBRARY}, /* ERR_BAD_SIG_COUNT */ {"Signature count is out of sync", LIBRARY}, /* ERR_BAD_ROLE_INDEX */ {"Role index is out of range", LIBRARY}, /* ERR_BAD_DOCINFO_COUNT */ {"Document info count is out of sync", LIBRARY}, /* ERR_BAD_DOCINFO_INDEX */ {"Document info index is out of range", LIBRARY}, /* ERR_BAD_NOTARY_INDEX */ {"Notary index is out of range", LIBRARY}, /* ERR_BAD_NOTARY_ID */ {"Bad notary ID", LIBRARY}, /* ERR_BAD_NOTARY_COUNT */ {"Notary count is out of sync", LIBRARY}, /* ERR_X509_DIGEST */ {"X509 digest creation failed", LIBRARY}, /* ERR_CERT_LENGTH */ {"Wrong certificate length", LIBRARY}, /* ERR_PKCS_LIB_LOAD */ {"PKCS #11 DLL load failed", TECHNICAL}, /* ERR_PKCS_SLOT_LIST */ {"Getting PKCS #11 slot list failed", TECHNICAL}, /* ERR_PKCS_WRONG_SLOT */ {"No such PKCS #11 slot", TECHNICAL}, /* ERR_PKCS_LOGIN */ {"No EstID card, wrong PIN or PIN blocked", USER}, /* ERR_PKCS_PK */ {"Locating private key from EstID failed", TECHNICAL}, /* ERR_PKCS_CERT_LOC */ {"Reading certificate from EstID failed", TECHNICAL}, /* ERR_PKCS_CERT_DECODE */ {"Decoding certificate failed", LIBRARY}, /* ERR_PKCS_SIGN_DATA */ {"Signing data with EstID failed", USER}, /* ERR_PKCS_CARD_READ */ {"Reading EstID card failed", USER}, /* ERR_CSP_NO_CARD_DATA */ {"No EstID card, or card can not be read", USER}, /* ERR_CSP_OPEN_STORE */ {"Can not open system store", TECHNICAL}, /* ERR_CSP_CERT_FOUND*/ {"Certificate not found from store, probably cetificate not registered", USER}, /* ERR_CSP_SIGN */ {"CSP signing failed", USER}, /* ERR_CSP_NO_HASH_START */ {"Can not start CSP hashing", TECHNICAL}, /* ERR_CSP_NO_HASH */ {"CSP hash failed", LIBRARY}, /* ERR_CSP_NO_HASH_RESULT */ {"Can not read CSP's hashing result", LIBRARY}, /* ERR_CSP_OPEN_KEY */ {"Can not open key", TECHNICAL}, /* ERR_CSP_READ_KEY */ {"Can not read key", TECHNICAL}, /* ERR_OCSP_SIGN_NOT_SUPPORTED */ {"Requuested OCSP sign method not suported", LIBRARY}, /* ERR_OCSP_SIGN_CSP_NAME */ {"Can not add Signer's name to requst", LIBRARY}, /* ERR_CSP_CERT_DECODE */ {"Decoding certificate failed", TECHNICAL}, /* ERR_OCSP_SIGN_PKCS_NAME */ {"Can not add Signer's name to requst", TECHNICAL}, /* ERR_OCSP_SIGN_OSLL_CERT */ {"Cannot add cert to OCSP request", TECHNICAL}, /* ERR_OCSP_SIGN */ {"Can not sign OCSP request", USER}, /* ERR_CERT_ISSUER */ {"Cert not issued by this CA, or wrong cert signature", USER}, /* ERR_OCSP_PKCS12_CONTAINER */ {"Can not open pkcs12 container", USER}, /* ERR_MODIFY_SIGNED_DOC */ {"Cannot modify signed doc. Remove signatures first.", USER}, /* ERR_NOTARY_EXISTS */ {"Cannot remove signature if notary exists", USER}, /* ERR_UNSUPPORTED_CERT_SEARCH */ {"Unsuported CERT_SEARCH method", LIBRARY}, /* ERR_INCORRECT_CERT_SEARCH */ {"Incorrct CERT_SEARCH pattern", LIBRARY}, /* ERR_BAD_OCSP_RESPONSE_DIGEST */{"Incorrect Notary signature digest", USER}, /* ERR_LAST_ESTID_CACHED */ {"Wrong certificate in cache. Please try again.", USER}, /* ERR_BAD_DATAFILE_XML */ {"XML content cannot contain the first XML line", USER}, /* ERR_UNSUPPORTED_VERSION */ {"Unsupported SK-XML version. Please upgrade!", TECHNICAL}, /* ERR_UNSUPPORTED_CHARSET */ {"Unsupported charset", TECHNICAL}, /* ERR_PKCS12_EXPIRED */ {"PKCS#12 certificate has expired. Please get a new onew from www.sk.ee", USER}, /* ERR_CSP_USER_CANCEL */ {"User canceled certificate selection", USER}, /* ERR_CSP_NODEFKEY_CONTAINER */ {"Can't find default key container", TECHNICAL}, /* ERR_CONNECTION_FAILURE */ {"Connection error", USER}, /* ERR_WRONG_URL_OR_PROXY */ {"Wrong URL or Proxy", USER}, /* ERR_NULL_PARAM */ {"Mandatory parameter is NULL", LIBRARY}, /* ERR_BAD_ALLOC */ {"Memory allocation error", LIBRARY}, /* ERR_CONF_FILE */ {"Error opening configuration file", USER}, /* ERR_CONF_LINE */ {"Error in configuration file", USER}, /* ERR_OCSP_CERT_REVOKED */ { "Certificate has been revoked!", USER}, /* ERR_OCSP_CERT_UNKNOWN */ { "Certificate status unknow! Not supported by this CA?", USER}, /* ERR_OCSP_PKCS12_NO_FILE */ { "PKCS#12 token file not defined!", USER}, /* ERR_OCSP_PKCS12_NO_PASSWD */ { "PKCS#12 token file password not defined!", USER}, /* ERR_BAD_DATAFILE_CONTENT_TYPE */ { "Invalid DataFile content type!", TECHNICAL}, /* ERR_OCSP_WRONG_URL */ { "Wrong OCSP responder URL!", USER}, /* ERR_OCSP_MALFORMED */ { "Malformed OCSP request!", TECHNICAL}, /* ERR_OCSP_INTERNALERR */ { "Internal error in OCSP responder!", USER}, /* ERR_OCSP_TRYLATER */ { "Try later! OCSP responder is busy", USER}, /* ERR_OCSP_SIGREQUIRED */ { "Must sign OCSP requests!", USER}, /* ERR_OCSP_UNAUTHORIZED */ { "Unauthorized OCSP request!", USER}, /* ERR_UNKNOWN_CA */ { "Unknown Certificate issuer!", USER}, /* ERR_DENC_ENC_METHOD */ { "Invalid encryption method!", TECHNICAL}, /* ERR_DENC_ENC_XMLNS */ { "Invalid xml namespace!", TECHNICAL}, /* ERR_DENC_BAD_PROP_IDX */ { "Invalid EncryptionProperty index!", TECHNICAL}, /* ERR_DENC_BAD_KEY_IDX */ { "Invalid EncryptedKey index!", TECHNICAL}, /* ERR_DENC_KEY_STATUS */ { "Transport key not ready!", USER}, /* ERR_DENC_DATA_STATUS */ { "Invalid data status for this operation!", USER}, /* ERR_DENC_DECRYPT */ { "Failed to decrypt the data!", USER}, /* ERR_CHARSET_CONVERT */ { "Error converting charsets!", TECHNICAL }, /* ERR_COMPRESS */ { "Error compressing the data!", TECHNICAL }, /* ERR_DECOMPRESS */ { "Error decompressing the data!", TECHNICAL }, /* ERR_OCSP_CERT_NOTFOUND */ { "OCSP Responders cetificate not found!", USER }, /* ERR_INVALID_CONTENT */ { "Invalid characters in manifest or addres!", USER }, /* ERR_DENC_NO_KEY_FOUND */ { "No transport key for this smartcard!", USER }, /* ERR_OCSP_RESP_NOT_TRUSTED */ { "OCSP responder is not trusted! No certificate for this responder in local certstore!", USER }, /* ERR_PRIV_CERT_NOT_FOUND */ { "Certificate not found!", USER }, /* ERR_NO_OCSP */ { "Signature has no OCSP confirmation!", USER }, /* ERR_OCSP_WRONG_SIGNATURE */ { "OCSP signature is wrong!", USER }, /* ERR_BAD_PARAM */ { "Invalid parameter!", TECHNICAL }, /* ERR_GENERIC_SOAP_ERR */ { "Generic SOAP error", TECHNICAL }, /* ERR_TS_TIMESTAMPINFO_TYPE */ { "Invalid Timestamp type", TECHNICAL }, /* ERR_TS_BAD_INCLUDEINFO_IDX */ { "Invalid Include index", TECHNICAL }, /* ERR_TS_BAD_TIMESTAMPINFO_IDX */ { "Invalid TimestampInfo index", TECHNICAL }, /* ERR_TS_CREATE_TS_REQ */ { "Error creating timestamp request", TECHNICAL }, /* ERR_CREATE_NONCE */ { "Error creating nonce", TECHNICAL }, /* ERR_TXT2OID */ { "Error converting text to OID", TECHNICAL }, /* ERR_HTTP_ERR */ { "Invalid HTTP response code", TECHNICAL }, /* ERR_BAD_CERTID_IDX */ { "Invalid Include index", TECHNICAL }, /* ERR_BAD_CERTVALUE_IDX */ { "Invalid Include index", TECHNICAL }, /* ERR_TS_VERIFY */ { "Timestamp verification error", USER }, /* ERR_TS_REQUEST */ { "Error getting timestamp", USER }, /* ERR_TSA_NOT_TRUSTED */ { "TSA is not trusted! No certificate for this TSA in local certstore!", USER }, /* ERR_ORPHONED_SIGNATURE */ { "Incomplete or orphoned signature!", TECHNICAL }, /* ERR_WPKI_UNKNOWN_USER */ { "Unknown WPKI user!", USER }, /* ERR_WPKI_INVALID_PHONE_NO */ { "Invalid phone number for this WPKI user!", USER }, /* ERR_WPKI_UNTRUSTED_SRVICE */ { "WPKI service is not trusted!", USER }, /* ERR_WPKI_UNTRUSTED_USER */ { "Service demands customer authentication!", USER }, /* ERR_WPKI_UNUSABLE_PHONE */ { "Error signing with customers mobile phone! Unusable phone type?", USER }, /* ERR_WPKI_TIMEOUT */ { "Timeout during mobile signing!", USER }, /* ERR_WPKI_CANCELLED */ { "User cancelled mobile signing!", USER }, /* ERR_WPKI_MID_NOT_READY */ { "MID not ready!", USER }, /* ERR_WPKI_PHONE_NOT_REACHABLE */ { "Users phone is not reachable!", USER }, /* ERR_WPKI_SENDING_ERROR */ { "Error sending signing request to users mobile phone!", USER }, /* ERR_WPKI_SIM_ERROR */ { "SIM card error!", USER }, /* ERR_WPKI_SERVICE_ERR */ { "Mobile signing service internal error!", USER }, //AM 18.03.08 /* ERR_ZIP_FILE_READ */ { "File not found in BDOC!", USER }, /* ERR_ZIP */ { "Error in BDocZip!", USER }, /* ERR_MANIFEST */ { "Can't parse manifest!", USER }, /* ERR_DATAFILE_NOT_MANIFEST */ { "Datafile is not described in manifest.xml!", USER }, /* ERR_SIG_INVALID_PROFILE */ { "Signature does not correspond to profile in manifest.xml!", USER }, /* ERR_SIGNERS_CERT_NON_REPU */ { "Signers cert does not have non-repudiation bit set!", USER }, /* ERR_OCSP_NONCE_SIGVAL_NOMATCH */ { "Calculated signature hash doesn't match to OCSP responder nonce field!", USER }, /* ERR_VALIDATE */ { "Validation error! Invalid ddoc or cdoc document.", USER }, /* ERR_OCSP_NONCE_INVALID */ { "Invalid nonce length!", TECHNICAL }, /* ERR_SIGVAL_ASN1 */ { "Invalid signature value! Missing or wrong asn.1 signature structure", TECHNICAL }, /* ERR_MAX_1_ROLES */ { "Currently supports no more than 1 ClaimedRoles!", USER }, /* ERR_DF_NAME */ { "Failed to parse DataFile name. Invalid file name!", USER }, /* ERR_DF_WRONG_DIG */ { "Invalid DataFile digest! Alternate digest matches.", USER }, /* ERR_ISSUER_XMLNS */ { "X509IssuerName or X509IssuerSerial missing xmlns atribute", USER }, /* ERR_OLD_VERSION */ { "SK-XML 1.0 and DIGIDOC-XML 1.1 and 1.2 are old signature formats and schould not be used for new documents", USER }, /* ERR_TEST_SIGNATURE */ { "Test signature!", USER }, /* ERR_UNKNOWN_ERROR */ { "Multiple errors. Check the error list!", USER }, /* ERR_TRANSFORM_UNSUPPORTED */ { "Transform elements are currently not supported!", USER }, /* ERR_NETWORK_SYNC */ { "Error writing file! Network synchronize timeout.", USER }, /* ERR_XML_VALIDATION */ { "Signature xml structure validation error", USER }, /* */ {"", NO_ERRORS} }; //==========< global variables >==================== //int g_ddocLastError = ERR_OK; #define INITIAL_MAX_THREADS 1 #define NOT_FOUND -1 #if defined(WIN32) #define THREAD_ID DWORD #elif defined(USEPTHREADS) #define THREAD_ID pthread_t #else #define THREAD_ID pid_t #endif typedef struct ThreadErrors_st { THREAD_ID tid; int currentErrorIdx; int readErrorIdx; ErrorInfo ddocLastErrors[ERROR_BUF_LENGTH]; } ThreadErrors; static int g_threads = 0; static ThreadErrors **ddocErrors = NULL; // Following mutual exclusion objects are here to // protect access to ddocErrors and g_threads; whenever we access these variables // we have to use lock/unlock. #if defined(USEPTHREADS) pthread_mutex_t m_ddocErrors = PTHREAD_MUTEX_INITIALIZER; #elif defined(WIN32) //My bad, no static initializer for critical sections; initialized in DigiDocLib.c CRITICAL_SECTION cs_ddocErrors; #endif // Returns unique thread identifier static THREAD_ID getTid(void) { #if defined(WIN32) return GetCurrentThreadId(); #elif defined(USEPTHREADS) return pthread_self(); #else return getpid(); #endif } static void lock(void) { #if defined WIN32 EnterCriticalSection(&cs_ddocErrors); #elif defined USEPTHREADS pthread_mutex_lock(&m_ddocErrors); #else // Hope it will be optimized away.. #endif } static void unlock(void) { #if defined WIN32 LeaveCriticalSection(&cs_ddocErrors); #elif defined USEPTHREADS pthread_mutex_unlock(&m_ddocErrors); #else // Hope it will be optimized away.. #endif } // Grows or creates the array of pointers to ThreadErrors // Will be always called with locked mutex. static int growErrorTable(void) { int slotsToAllocate; int i; ThreadErrors **tmpErrors; // printf("growErrorTable init : g_threads=%d, ddocErrors=%p\n", g_threads, ddocErrors); if (g_threads == 0) slotsToAllocate = INITIAL_MAX_THREADS; // We have no table so far at all else slotsToAllocate = g_threads * 2; // We'll double the table size everytime tmpErrors = (ThreadErrors**)realloc(ddocErrors, slotsToAllocate * sizeof(ThreadErrors *)); // MEMLEAK: ??? if (tmpErrors == NULL) return ERR_BAD_ALLOC; ddocErrors = tmpErrors; for (i = g_threads; i < slotsToAllocate; i++) // Initialize new entries; ddocErrors[i] = NULL; g_threads = slotsToAllocate; // printf("growErrorTable leave : g_threads=%d, ddocErrors=%p\n", g_threads, ddocErrors); return ERR_OK; } static int isThreadEqual(THREAD_ID tid1, THREAD_ID tid2) { #if defined(WIN32) return tid1 == tid2; #elif defined(USETHREADS) return pthread_equal(tid1, tid2); #else return tid1 == tid2; #endif } // Finds slot number in ddocErrors[] whose pointer points to ThreadErrors belonging to threadID // or returns NOT_FOUND; static int findSlotByTid(THREAD_ID threadID) { int i; lock(); if (ddocErrors == NULL) { unlock(); return NOT_FOUND; } for (i = 0; i < g_threads; i++) if (ddocErrors[i] && isThreadEqual(ddocErrors[i]->tid,threadID)) { unlock(); return i; } unlock(); return NOT_FOUND; } // Finds thread's ThreadError structure address, returns NULL if the thread doesn't have it (yet). static ThreadErrors *findThreadErrorsByTid(THREAD_ID threadID) { ThreadErrors *tmpThreadErrors; int slot = findSlotByTid(threadID); if (slot == NOT_FOUND) return NULL; lock(); tmpThreadErrors = ddocErrors[slot]; unlock(); return tmpThreadErrors; } // Creates ThreadErrors structure for thread Tid, returns pointer to // created object; returns NULL if the object wasn't created. static ThreadErrors *addThreadErrorsByTid(THREAD_ID Tid) { int i, slot = NOT_FOUND; ThreadErrors *threadErrors = findThreadErrorsByTid(Tid); if (threadErrors != NULL) // Already present, do nothing return threadErrors; lock(); for (i = 0; i < g_threads; i++) { if (ddocErrors[i] == NULL) // Won't enter here if g_threads == 0 slot = i; // first free slot found } if (slot == NOT_FOUND) { if (growErrorTable() == ERR_OK) { for (i = 0; i < g_threads; i++) { //Try again... if (ddocErrors[i] == NULL) slot = i; } } else { unlock(); return NULL; } } threadErrors = (ThreadErrors*)malloc(sizeof(ThreadErrors)); // MEMLEAK: ??? if (threadErrors == NULL) { unlock(); return NULL; } memset(threadErrors, 0, sizeof(ThreadErrors)); threadErrors->tid = Tid; threadErrors->readErrorIdx = -1; threadErrors->currentErrorIdx = -1; ddocErrors[slot] = threadErrors; unlock(); return threadErrors; } // Releases memory allocated for ThreadError structure of thread threadID EXP_OPTION void freeThreadErrorsByTid(THREAD_ID threadID) { ThreadErrors *threadErrors; int slot = findSlotByTid(threadID); if (slot == NOT_FOUND) return; threadErrors = findThreadErrorsByTid(threadID); lock(); free(threadErrors); ddocErrors[slot] = NULL; unlock(); } //================< error handling functions> ================================= //returns textual explanation of the error code EXP_OPTION char* getErrorString(int code) { if(code < ERR_MAX && code >= 0) return g_ddocErrorStrings[code].errorMessage; else return "No error message defined for this error"; } EXP_OPTION ErrorClass getErrorClass(int code) { if(code < ERR_MAX && code >= 0) return g_ddocErrorStrings[code].errorClass; else return NO_ERRORS; } //returns the last EXP_OPTION ErrorInfo* getErrorInfo() { ErrorInfo *pErrInfo = 0; THREAD_ID Tid = getTid(); ThreadErrors *threadErrors = findThreadErrorsByTid(Tid); if (threadErrors == NULL) return 0; if(threadErrors->readErrorIdx >= 0 && threadErrors->ddocLastErrors[threadErrors->readErrorIdx].code != ERR_OK) { pErrInfo = &(threadErrors->ddocLastErrors[threadErrors->readErrorIdx]); threadErrors->readErrorIdx--; if(threadErrors->readErrorIdx < 0) //roll over threadErrors->readErrorIdx = ERROR_BUF_LENGTH - 1; } else pErrInfo = 0; return pErrInfo; } //returns 1, if all errors are read and 0 otherwise EXP_OPTION int hasUnreadErrors() { THREAD_ID Tid = getTid(); ThreadErrors *threadErrors = findThreadErrorsByTid(Tid); if (threadErrors == NULL) return 0; return (threadErrors->readErrorIdx >= 0 ? threadErrors->ddocLastErrors[threadErrors->readErrorIdx].code : ERR_OK); } //returns -1, if all errors are read and valid index otherwise EXP_OPTION int getLastErrorsIdx() { THREAD_ID Tid = getTid(); ThreadErrors *threadErrors = findThreadErrorsByTid(Tid); if (threadErrors == NULL) return -1; return threadErrors->readErrorIdx; } //returns NULL, if all errors are read and valid ErrorInfo structre pointer otherwise // does not mark error as read so it can be found again EXP_OPTION ErrorInfo* getErrorsInfo(int nIdx) { ErrorInfo *pErrInfo = 0; THREAD_ID Tid = getTid(); ThreadErrors *threadErrors = findThreadErrorsByTid(Tid); if (threadErrors == NULL) return 0; if(nIdx >= 0 && threadErrors->ddocLastErrors[nIdx].code != ERR_OK) { pErrInfo = &(threadErrors->ddocLastErrors[nIdx]); } else pErrInfo = 0; return pErrInfo; } EXP_OPTION void clearErrors() { THREAD_ID Tid = getTid(); ThreadErrors *threadErrors = findThreadErrorsByTid(Tid); if (threadErrors == NULL) return; memset(threadErrors->ddocLastErrors, 0, sizeof(ErrorInfo) * ERROR_BUF_LENGTH); threadErrors->readErrorIdx = -1; threadErrors->currentErrorIdx = -1; } EXP_OPTION void resetError(ErrorInfo *pErrInfo) { pErrInfo->code = ERR_OK; pErrInfo->fileName = ""; pErrInfo->line = 0; pErrInfo->assertion = ""; } EXP_OPTION void addError(int code, char *fileName, int line, char *assertion) { //no errors found yet. Set a trace-back mark to the end of array. //printf("Error : %d at %s line %d, assertion %s\n", code, fileName, line, assertion); ThreadErrors *threadErrors; THREAD_ID Tid = getTid(); //Find our identity threadErrors = findThreadErrorsByTid(Tid); // printf("addError init: tid=%ld, threadErrors=%p\n", Tid, threadErrors); if (threadErrors == NULL) { //This Tid has no entry in ThreadErrors table threadErrors = addThreadErrorsByTid(Tid); // MEMLEAK: ??? if (threadErrors == NULL) return; // What else can we do? } // printf("addError step 1 : tid=%ld, threadErrors=%p\n", Tid, threadErrors); if(threadErrors->currentErrorIdx < 0) resetError(&(threadErrors->ddocLastErrors[ERROR_BUF_LENGTH - 1])); threadErrors->currentErrorIdx++; //index at the end -> roll it over to the beginning if(threadErrors->currentErrorIdx == ERROR_BUF_LENGTH-1) threadErrors->currentErrorIdx = 0; //set the information ddocDebug(4, "addError", "Index: %d Error : %d at %s line %d, assertion %s", threadErrors->currentErrorIdx, code, fileName, line, assertion); threadErrors->ddocLastErrors[threadErrors->currentErrorIdx].code = code; threadErrors->ddocLastErrors[threadErrors->currentErrorIdx].fileName = fileName; threadErrors->ddocLastErrors[threadErrors->currentErrorIdx].line = line; threadErrors->ddocLastErrors[threadErrors->currentErrorIdx].assertion = assertion; //index at the end? Set the traceback mark to the beginning if(threadErrors->currentErrorIdx == ERROR_BUF_LENGTH - 1) resetError(&(threadErrors->ddocLastErrors[0])); else //set the traceback mark to the next position resetError(&(threadErrors->ddocLastErrors[threadErrors->currentErrorIdx + 1])); threadErrors->readErrorIdx = threadErrors->currentErrorIdx; } //-------------------------------------------------- // Checks DigiDoc library internal errors //-------------------------------------------------- EXP_OPTION int checkDigiDocErrors() { char *errorClass[] = {"NO_ERRORS", "TECHNICAL", "USER", "LIBRARY"}; int err = ERR_OK; while(hasUnreadErrors()) { ErrorInfo* pErr = getErrorInfo(); char* pErrStr = getErrorString(pErr->code); printf("Error: %d - %s; file: %s line: %d; failed condition: %s, error class : %s\n", pErr->code, pErrStr, pErr->fileName, pErr->line, pErr->assertion, errorClass[getErrorClass(pErr->code)]); err = pErr->code; } clearErrors(); return err; } EXP_OPTION int getLastError() { THREAD_ID Tid = getTid(); ThreadErrors *threadErrors = findThreadErrorsByTid(Tid); if (threadErrors == NULL) return 0; return (threadErrors->readErrorIdx >= 0 ? threadErrors->ddocLastErrors[threadErrors->readErrorIdx].code : ERR_OK); } EXP_OPTION int checkUnknownErr(SignedDoc* pSigDoc) { int n, m = getLastErrorsIdx(), err1 = 0, err2 = 0; ErrorInfo* pErr; // list all errors for(n = m; n >= 0; n--) { pErr = getErrorsInfo(n); if(!err1 && pErr) { err1 = pErr->code; } else if(!err2 && pErr && pErr->code != err1) err2 = pErr->code; } return ((err1 != err2 && err2) ? ERR_UNKNOWN_ERROR : err1); }