diff options
Diffstat (limited to 'vcore/src')
166 files changed, 21566 insertions, 3294 deletions
diff --git a/vcore/src/CMakeLists.txt b/vcore/src/CMakeLists.txt index 0772fc6..c982724 100644 --- a/vcore/src/CMakeLists.txt +++ b/vcore/src/CMakeLists.txt @@ -1,34 +1,44 @@ -INCLUDE(FindPkgConfig) +# compiler warning flags +ADD_DEFINITIONS("-Wall") +ADD_DEFINITIONS("-Wextra") +ADD_DEFINITIONS("-Werror") +IF(DEFINED TIZEN_FEAT_CERTSVC_OCSP_CRL) PKG_CHECK_MODULES(VCORE_DEPS - dpl-efl - dpl-db-efl - ecore - appcore-efl + REQUIRED + glib-2.0 libxml-2.0 - libsoup-2.4 - libpcre libpcrecpp openssl xmlsec1 + dlog secure-storage - REQUIRED) + icu-uc + libsoup-2.4 + db-util -IF(TIZEN_FEAT_PROFILE_CERT_SVC_OCSP_CRL) + sqlite3 + vconf + ) +ELSE(DEFINED TIZEN_FEAT_CERTSVC_OCSP_CRL) PKG_CHECK_MODULES(VCORE_DEPS - dpl-db-efl - ) -ENDIF(TIZEN_FEAT_PROFILE_CERT_SVC_OCSP_CRL) - -IF(TIZEN_FEAT_OSP_DISABLE EQUAL 1) -ADD_DEFINITIONS("-DTIZEN_FEATURE_OSP_DISABLE") -ENDIF(TIZEN_FEAT_OSP_DISABLE EQUAL 1) - -SET(LIBCRYPTSVC_DIR - ${PROJECT_SOURCE_DIR}/vcore + REQUIRED + glib-2.0 + libxml-2.0 + libpcrecpp + openssl + xmlsec1 + dlog + secure-storage + icu-uc + libsoup-2.4 + db-util ) +ENDIF(DEFINED TIZEN_FEAT_CERTSVC_OCSP_CRL) -INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/include) +ADD_DEFINITIONS(${VCORE_DEPS_CFLAGS}) +ADD_DEFINITIONS(${VCORE_DEPS_CFLAGS_OTHER}) +ADD_DEFINITIONS("-DSEPARATED_SINGLETON_IMPLEMENTATION") SET(VCORE_DIR ${PROJECT_SOURCE_DIR}/vcore @@ -38,6 +48,54 @@ SET(VCORE_SRC_DIR ${VCORE_DIR}/src/vcore ) +########### DPL SOURCES ########## +SET(VCORE_DPL_DIR + ${VCORE_DIR}/src/dpl + ) +SET(VCORE_DPL_CORE_SRC_DIR + ${VCORE_DPL_DIR}/core/src + ) +SET(VCORE_DPL_CORE_SOURCES + ${VCORE_DPL_CORE_SRC_DIR}/assert.cpp + ${VCORE_DPL_CORE_SRC_DIR}/binary_queue.cpp + ${VCORE_DPL_CORE_SRC_DIR}/char_traits.cpp + ${VCORE_DPL_CORE_SRC_DIR}/colors.cpp + ${VCORE_DPL_CORE_SRC_DIR}/errno_string.cpp + ${VCORE_DPL_CORE_SRC_DIR}/exception.cpp + ${VCORE_DPL_CORE_SRC_DIR}/file_input.cpp + ${VCORE_DPL_CORE_SRC_DIR}/noncopyable.cpp + ${VCORE_DPL_CORE_SRC_DIR}/singleton.cpp + ${VCORE_DPL_CORE_SRC_DIR}/string.cpp + ${VCORE_DPL_CORE_SRC_DIR}/type_list.cpp + ${VCORE_DPL_CORE_SRC_DIR}/thread.cpp + ${VCORE_DPL_CORE_SRC_DIR}/waitable_event.cpp + ${VCORE_DPL_CORE_SRC_DIR}/waitable_handle.cpp + ${VCORE_DPL_CORE_SRC_DIR}/waitable_handle_watch_support.cpp + ) + +SET(VCORE_DPL_DB_SRC_DIR + ${VCORE_DPL_DIR}/db/src + ) +SET(VCORE_DPL_DB_SOURCES + ${VCORE_DPL_DB_SRC_DIR}/naive_synchronization_object.cpp + ${VCORE_DPL_DB_SRC_DIR}/orm.cpp + ${VCORE_DPL_DB_SRC_DIR}/sql_connection.cpp + ${VCORE_DPL_DB_SRC_DIR}/thread_database_support.cpp + ) + +SET(VCORE_DPL_LOG_SRC_DIR + ${VCORE_DPL_DIR}/log/src + ) +SET(VCORE_DPL_LOG_SOURCES + ${VCORE_DPL_LOG_SRC_DIR}/abstract_log_provider.cpp + ${VCORE_DPL_LOG_SRC_DIR}/old_style_log_provider.cpp + ${VCORE_DPL_LOG_SRC_DIR}/dlog_log_provider.cpp + ${VCORE_DPL_LOG_SRC_DIR}/log.cpp + ) +########### DPL SOURCES ########## + + +########### VCORE SOURCES ######## SET(VCORE_SOURCES ${VCORE_SRC_DIR}/api.cpp ${VCORE_SRC_DIR}/Base64.cpp @@ -52,6 +110,7 @@ SET(VCORE_SOURCES ${VCORE_SRC_DIR}/ReferenceValidator.cpp ${VCORE_SRC_DIR}/RevocationCheckerBase.cpp ${VCORE_SRC_DIR}/SaxReader.cpp + ${VCORE_SRC_DIR}/SignatureData.cpp ${VCORE_SRC_DIR}/SignatureFinder.cpp ${VCORE_SRC_DIR}/SignatureReader.cpp ${VCORE_SRC_DIR}/TimeConversion.cpp @@ -61,141 +120,158 @@ SET(VCORE_SOURCES ${VCORE_SRC_DIR}/WrtSignatureValidator.cpp ${VCORE_SRC_DIR}/SignatureValidator.cpp ${VCORE_SRC_DIR}/XmlsecAdapter.cpp - ${VCORE_SRC_DIR}/pkcs12.c - ) + ${VCORE_SRC_DIR}/pkcs12.cpp + ${VCORE_SRC_DIR}/exception.cpp -IF(TIZEN_FEAT_PROFILE_CERT_SVC_OCSP_CRL) -SET(VCORE_SOURCES - ${VCORE_SRC_DIR}/api.cpp - ${VCORE_SRC_DIR}/Base64.cpp - ${VCORE_SRC_DIR}/Certificate.cpp - ${VCORE_SRC_DIR}/CertificateCollection.cpp - ${VCORE_SRC_DIR}/CertificateConfigReader.cpp - ${VCORE_SRC_DIR}/CertificateLoader.cpp - ${VCORE_SRC_DIR}/CertStoreType.cpp - ${VCORE_SRC_DIR}/Config.cpp - ${VCORE_SRC_DIR}/CryptoHash.cpp - ${VCORE_SRC_DIR}/OCSPCertMgrUtil.cpp - ${VCORE_SRC_DIR}/ReferenceValidator.cpp - ${VCORE_SRC_DIR}/RevocationCheckerBase.cpp - ${VCORE_SRC_DIR}/SaxReader.cpp - ${VCORE_SRC_DIR}/SignatureFinder.cpp - ${VCORE_SRC_DIR}/SignatureReader.cpp - ${VCORE_SRC_DIR}/TimeConversion.cpp - ${VCORE_SRC_DIR}/VerificationStatus.cpp - ${VCORE_SRC_DIR}/ValidatorFactories.cpp - ${VCORE_SRC_DIR}/VCore.cpp - ${VCORE_SRC_DIR}/DUID.cpp - ${VCORE_SRC_DIR}/WrtSignatureValidator.cpp - ${VCORE_SRC_DIR}/SignatureValidator.cpp - ${VCORE_SRC_DIR}/XmlsecAdapter.cpp - ${VCORE_SRC_DIR}/pkcs12.c - ${VCORE_SRC_DIR}/CachedCRL.cpp + ${VCORE_SRC_DIR}/utils.c + ${VCORE_SRC_DIR}/cert-svc-client.c + ) + +SET(VCORE_OCSP_CRL_SOURCES + ${VCORE_SRC_DIR}/CachedCRL.cpp ${VCORE_SRC_DIR}/CachedOCSP.cpp - ${VCORE_SRC_DIR}/CertificateCacheDAO.cpp - ${VCORE_SRC_DIR}/CertificateVerifier.cpp - ${VCORE_SRC_DIR}/CRL.cpp + ${VCORE_SRC_DIR}/CertificateCacheDAO.cpp + ${VCORE_SRC_DIR}/CertificateVerifier.cpp + ${VCORE_SRC_DIR}/CRL.cpp ${VCORE_SRC_DIR}/CRLImpl.cpp ${VCORE_SRC_DIR}/CRLCacheDAO.cpp - ${VCORE_SRC_DIR}/Database.cpp + ${VCORE_SRC_DIR}/Database.cpp ${VCORE_SRC_DIR}/OCSP.cpp ${VCORE_SRC_DIR}/OCSPImpl.cpp - ${VCORE_SRC_DIR}/SoupMessageSendBase.cpp + ${VCORE_SRC_DIR}/SoupMessageSendBase.cpp ${VCORE_SRC_DIR}/SoupMessageSendSync.cpp - ${VCORE_SRC_DIR}/SoupMessageSendAsync.cpp - ${VCORE_SRC_DIR}/OCSPUtil.c + ${VCORE_SRC_DIR}/OCSPUtil.c ) -ENDIF(TIZEN_FEAT_PROFILE_CERT_SVC_OCSP_CRL) -IF(TIZEN_FEAT_PROFILE_CERT_SVC_OCSP_CRL) SET(VCORE_INCLUDES ${VCORE_DEPS_INCLUDE_DIRS} ${VCORE_SRC_DIR} ${VCORE_DIR}/src - ${VCORE_DIR}/src/orm ${VCORE_DIR}/src/legacy - ${CMAKE_BINARY_DIR}/vcore/src ) -ELSE(TIZEN_FEAT_PROFILE_CERT_SVC_OCSP_CRL) -SET(VCORE_INCLUDES - ${VCORE_DEPS_INCLUDE_DIRS} - ${VCORE_SRC_DIR} - ${VCORE_DIR}/src - ${VCORE_DIR}/src/legacy - ${CMAKE_BINARY_DIR}/vcore/src + +SET(VCORE_INCLUDES_OCSP_CRL + ${VCORE_DIR}/src/orm ) -ENDIF(TIZEN_FEAT_PROFILE_CERT_SVC_OCSP_CRL) +########### VCORE SOURCES ######## -ADD_DEFINITIONS(${VCORE_DEPS_CFLAGS}) -ADD_DEFINITIONS(${VCORE_DEPS_CFLAGS_OTHER}) -ADD_DEFINITIONS("-DSEPARATED_SINGLETON_IMPLEMENTATION") -ADD_DEFINITIONS("-DDPL_LOGS_ENABLED") -ADD_DEFINITIONS("-DCERT_SVC_LOG") -IF(TIZEN_FEAT_PROFILE_CERT_SVC_OCSP_CRL) -ADD_DEFINITIONS("-DTIZENUCT_FEATURE_CERT_SVC_OCSP_CRL") -ENDIF(TIZEN_FEAT_PROFILE_CERT_SVC_OCSP_CRL) - -INCLUDE_DIRECTORIES(${VCORE_INCLUDES}) - -# cert-svc headers -INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/include) - -ADD_LIBRARY(${TARGET_VCORE_LIB} SHARED ${VCORE_SOURCES}) -SET_TARGET_PROPERTIES(${TARGET_VCORE_LIB} PROPERTIES - SOVERSION ${SO_VERSION} - VERSION ${VERSION}) -IF(TIZEN_FEAT_PROFILE_CERT_SVC_OCSP_CRL) +IF(DEFINED TIZEN_FEAT_CERTSVC_OCSP_CRL) +SET(VCORE_ALL_SOURCES + ${VCORE_SOURCES} + ${VCORE_DPL_CORE_SOURCES} + ${VCORE_DPL_DB_SOURCES} + ${VCORE_DPL_LOG_SOURCES} + ${VCORE_OCSP_CRL_SOURCES} + ) +SET(VCORE_ALL_INCLUDES + ${PROJECT_SOURCE_DIR}/include + ${VCORE_INCLUDES} + ${VCORE_DPL_DIR}/core/include + ${VCORE_DPL_DIR}/db/include + ${VCORE_DPL_DIR}/log/include + ${VCORE_INCLUDES_OCSP_CRL} + ) +ELSE(DEFINED TIZEN_FEAT_CERTSVC_OCSP_CRL) +SET(VCORE_ALL_SOURCES + ${VCORE_SOURCES} + ${VCORE_DPL_CORE_SOURCES} + ${VCORE_DPL_LOG_SOURCES} + ) +SET(VCORE_ALL_INCLUDES + ${PROJECT_SOURCE_DIR}/include + ${VCORE_INCLUDES} + ${VCORE_DPL_DIR}/core/include + ${VCORE_DPL_DIR}/log/include + ) +ENDIF(DEFINED TIZEN_FEAT_CERTSVC_OCSP_CRL) + +INCLUDE_DIRECTORIES(SYSTEM ${VCORE_ALL_INCLUDES}) + +ADD_LIBRARY(${TARGET_VCORE_LIB} SHARED ${VCORE_ALL_SOURCES}) + +# TODO: visibility needed to be hidden +SET_TARGET_PROPERTIES(${TARGET_VCORE_LIB} + PROPERTIES + COMPILE_FLAGS "-D_GNU_SOURCE -fPIC -fvisibility=default" + SOVERSION ${SO_VERSION} + VERSION ${VERSION}) + +IF(DEFINED TIZEN_FEAT_CERTSVC_OCSP_CRL) ADD_DEPENDENCIES(${TARGET_VCORE_LIB} Sqlite3DbWTF) -ENDIF(TIZEN_FEAT_PROFILE_CERT_SVC_OCSP_CRL) +ENDIF(DEFINED TIZEN_FEAT_CERTSVC_OCSP_CRL) -IF(TIZEN_FEAT_PROFILE_CERT_SVC_OCSP_CRL) -TARGET_LINK_LIBRARIES(${TARGET_VCORE_LIB} - ${VCORE_DEPS_LIBRARIES} - ${TARGET_CERT_SVC_LIB} - dpl-db-efl - ) -ELSE(TIZEN_FEAT_PROFILE_CERT_SVC_OCSP_CRL) TARGET_LINK_LIBRARIES(${TARGET_VCORE_LIB} ${VCORE_DEPS_LIBRARIES} ${TARGET_CERT_SVC_LIB} - ) -ENDIF(TIZEN_FEAT_PROFILE_CERT_SVC_OCSP_CRL) + ) + +########## cert-server ############# +PKG_CHECK_MODULES(CERT_SERVER_DEP + REQUIRED + dlog + sqlite3 + db-util + libsystemd-daemon + key-manager + ) + +SET(CERT_SERVER_DIR + ${PROJECT_SOURCE_DIR}/vcore/src/server + ) + +SET(CERT_SERVER_SRCS + ${CERT_SERVER_DIR}/src/cert-server-main.c + ${CERT_SERVER_DIR}/src/cert-server-logic.c + ) + +INCLUDE_DIRECTORIES( + SYSTEM + ${CERT_SERVER_DEP_INCLUDE_DIRS} + ${PROJECT_SOURCE_DIR}/include + ${VCORE_DIR}/src + ${CERT_SERVER_DIR}/include + ) + +SET_SOURCE_FILES_PROPERTIES( + ${CERT_SERVER_SRCS} + PROPERTIES + COMPILE_FLAGS "-D_GNU_SOURCE -fvisibility=hidden -fPIE" + ) + +ADD_EXECUTABLE(${TARGET_CERT_SERVER} ${CERT_SERVER_SRCS}) + +TARGET_LINK_LIBRARIES(${TARGET_CERT_SERVER} + ${CERT_SERVER_DEP_LIBRARIES} + -pie + ) + +INSTALL(TARGETS ${TARGET_CERT_SERVER} DESTINATION ${BINDIR}) + +######################################################## INSTALL(TARGETS ${TARGET_VCORE_LIB} - DESTINATION ${LIB_INSTALL_DIR} + DESTINATION ${LIBDIR} ) INSTALL(FILES - ${VCORE_SRC_DIR}/Base64.h - ${VCORE_SRC_DIR}/Certificate.h + ${VCORE_SRC_DIR}/VCore.h + ${VCORE_SRC_DIR}/WrtSignatureValidator.h + ${VCORE_SRC_DIR}/SignatureValidator.h + ${VCORE_SRC_DIR}/SignatureFinder.h + ${VCORE_SRC_DIR}/SignatureReader.h ${VCORE_SRC_DIR}/CertificateCollection.h - ${VCORE_SRC_DIR}/CertStoreType.h ${VCORE_SRC_DIR}/CryptoHash.h - ${VCORE_SRC_DIR}/IAbstractResponseCache.h + ${VCORE_SRC_DIR}/Base64.h + ${VCORE_SRC_DIR}/ParserSchema.h - ${VCORE_SRC_DIR}/ReferenceValidator.h ${VCORE_SRC_DIR}/SaxReader.h + + ${VCORE_SRC_DIR}/Certificate.h ${VCORE_SRC_DIR}/SignatureData.h - ${VCORE_SRC_DIR}/SignatureFinder.h - ${VCORE_SRC_DIR}/SignatureReader.h - ${VCORE_SRC_DIR}/WrtSignatureValidator.h - ${VCORE_SRC_DIR}/SignatureValidator.h - ${VCORE_SRC_DIR}/VerificationStatus.h - ${VCORE_SRC_DIR}/VCore.h + ${VCORE_SRC_DIR}/CertStoreType.h + ${VCORE_SRC_DIR}/exception.h DESTINATION ${INCLUDEDIR}/cert-svc/vcore ) -IF(TIZEN_FEAT_PROFILE_CERT_SVC_OCSP_CRL) -INSTALL(FILES - ${VCORE_SRC_DIR}/CachedCRL.h - ${VCORE_SRC_DIR}/CachedOCSP.h - ${VCORE_SRC_DIR}/CRL.h - ${VCORE_SRC_DIR}/CRLCacheInterface.h - ${VCORE_SRC_DIR}/OCSP.h - ${VCORE_SRC_DIR}/OCSPCertMgrUtil.h - DESTINATION ${INCLUDEDIR}/cert-svc/vcore - ) -ENDIF(TIZEN_FEAT_PROFILE_CERT_SVC_OCSP_CRL) - INSTALL(FILES ${VCORE_DIR}/src/cert-svc/ccert.h ${VCORE_DIR}/src/cert-svc/cinstance.h @@ -206,12 +282,22 @@ INSTALL(FILES DESTINATION ${INCLUDEDIR}/cert-svc/cert-svc ) -IF(TIZEN_FEAT_PROFILE_CERT_SVC_OCSP_CRL) +IF(DEFINED TIZEN_FEAT_CERTSVC_OCSP_CRL) INSTALL(FILES - ${VCORE_DIR}/src/cert-svc/ccrl.h - ${VCORE_DIR}/src/cert-svc/cocsp.h - DESTINATION ${INCLUDEDIR}/cert-svc/cert-svc - ) -ENDIF(TIZEN_FEAT_PROFILE_CERT_SVC_OCSP_CRL) + ${VCORE_SRC_DIR}/IAbstractResponseCache.h + ${VCORE_SRC_DIR}/VerificationStatus.h + ${VCORE_SRC_DIR}/CachedCRL.h + ${VCORE_SRC_DIR}/CachedOCSP.h + ${VCORE_SRC_DIR}/CRL.h + ${VCORE_SRC_DIR}/CRLCacheInterface.h + ${VCORE_SRC_DIR}/OCSP.h + ${VCORE_SRC_DIR}/OCSPCertMgrUtil.h + DESTINATION ${INCLUDEDIR}/cert-svc/vcore + ) -#FILE(MAKE_DIRECTORY %{TZ_SYS_SHARE}/cert-svc/pkcs12) +INSTALL(FILES + ${VCORE_DIR}/src/cert-svc/ccrl.h + ${VCORE_DIR}/src/cert-svc/cocsp.h + DESTINATION ${INCLUDEDIR}/cert-svc/cert-svc + ) +ENDIF(DEFINED TIZEN_FEAT_CERTSVC_OCSP_CRL) diff --git a/vcore/src/cert-svc/ccert.h b/vcore/src/cert-svc/ccert.h index d26837e..798d520 100644 --- a/vcore/src/cert-svc/ccert.h +++ b/vcore/src/cert-svc/ccert.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -41,6 +41,38 @@ typedef struct CertSvcCertificateList_t { CertSvcInstance privateInstance; } CertSvcCertificateList; +#define MAX_STORE_ENUMS 5 +typedef enum certImportType_t { + NONE_STORE = 0, + VPN_STORE = 1 << 0, + WIFI_STORE = 1 << 1, + EMAIL_STORE = 1 << 2, + SYSTEM_STORE = 1 << 3, + ALL_STORE = VPN_STORE | WIFI_STORE | EMAIL_STORE | SYSTEM_STORE +} CertStoreType; + +typedef struct CertSvcStoreCertList_t{ + char* gname; // keyfile group name + char* title; // common Name / Alias provided by the user + int status; // enabled / disabled + CertStoreType storeType; // Holds the storetype information + struct CertSvcStoreCertList_t *next; +}CertSvcStoreCertList; + +typedef enum certType_t { + PEM_CRT = 1 << 0, + P12_END_USER = 1 << 1, + P12_INTERMEDIATE = 1 << 2, + P12_TRUSTED = 1 << 3, + P12_PKEY = 1 << 4, + INVALID_DATA = 1 << 5, +} CertType; + +typedef enum certStatus_t { + DISABLED = 0, + ENABLED = 1, +} CertStatus; + typedef enum CertSvcCertificateForm_t { /* CERTSVC_FORM_PEM, */ CERTSVC_FORM_DER, @@ -79,6 +111,20 @@ typedef enum CertSvcVisibility_t { } CertSvcVisibility; /** + * This function will return certificate for the unique name identifier passed (gname). + * + * @param[in] instance CertSvcInstance object. + * @param[in] storeType Refers to the store (WIFI_STORE, VPN_STORE, EMAIL_STORE, SSL_STORE). + * @oaran[in] gname Refers to the unique name identifier associated for the certificate. + * @param[out] certificate Certificate for the gname passed. + * @return CERTSVC_SUCCESS, CERTSVC_BAD_ALLOC, CERTSVC_FAIL, CERTSVC_WRONG_ARGUMENT + */ +int certsvc_get_certificate(CertSvcInstance instance, + CertStoreType storeType, + char *gname, + CertSvcCertificate *certificate); + +/** * Read certificate from file. Certificate must be in PEM/CER/DER format. * * @param[in] instance CertSvcInstance object. @@ -365,6 +411,7 @@ int certsvc_certificate_verify_with_caflag( */ int certsvc_certificate_get_visibility(CertSvcCertificate certificate, int* visibility); + #ifdef __cplusplus } #endif diff --git a/vcore/src/cert-svc/cerror.h b/vcore/src/cert-svc/cerror.h index 0566152..b850b3c 100644 --- a/vcore/src/cert-svc/cerror.h +++ b/vcore/src/cert-svc/cerror.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,19 +27,21 @@ extern "C" { #endif -#define CERTSVC_TRUE (1) -#define CERTSVC_FALSE (0) +#define CERTSVC_TRUE (1) +#define CERTSVC_FALSE (0) -#define CERTSVC_SUCCESS (1) -#define CERTSVC_FAIL (0) /* Openssl internal error. */ -#define CERTSVC_BAD_ALLOC (-2) /* Memmory allcation error. */ -//#define CERTSVC_FILE_NOT_FOUND (-3) /* Certificate file does not exists. */ -#define CERTSVC_WRONG_ARGUMENT (-4) /* Function argumnet is wrong. */ -#define CERTSVC_INVALID_ALGORITHM (-5) /* Algorithm is not supported. */ -#define CERTSVC_INVALID_SIGNATURE (-6) /* Signature and message does not match. */ -#define CERTSVC_IO_ERROR (-7) /* Certificate file IO error. */ -#define CERTSVC_INVALID_PASSWORD (-8) /* Certificate container password mismatch. */ -#define CERTSVC_DUPLICATED_ALIAS (-9) /* User-provided alias is aleady taken. */ +#define CERTSVC_SUCCESS (1) +#define CERTSVC_FAIL (0) /* Openssl internal error. */ +#define CERTSVC_BAD_ALLOC (-2) /* Memmory allcation error. */ +#define CERTSVC_WRONG_ARGUMENT (-4) /* Function argumnet is wrong. */ +#define CERTSVC_INVALID_ALGORITHM (-5) /* Algorithm is not supported. */ +#define CERTSVC_INVALID_SIGNATURE (-6) /* Signature and message does not match. */ +#define CERTSVC_IO_ERROR (-7) /* Certificate file IO error. */ +#define CERTSVC_INVALID_PASSWORD (-8) /* Certificate container password mismatch. */ +#define CERTSVC_DUPLICATED_ALIAS (-9) /* User-provided alias is aleady taken. */ +#define CERTSVC_ALIAS_DOES_NOT_EXIST (-10) /* Alias no exist in store. */ +#define CERTSVC_INVALID_STORE_TYPE (-11) /* User-provided invalid import type for storing in system/email/wifi/vpn store. */ +#define CERTSVC_INVALID_STATUS (-12) /* User-provided invalid status while stetting the status for the store system/email/wifi/vpn store. */ #ifdef __cplusplus } diff --git a/vcore/src/cert-svc/cpkcs12.h b/vcore/src/cert-svc/cpkcs12.h index 328afd9..d779fa2 100644 --- a/vcore/src/cert-svc/cpkcs12.h +++ b/vcore/src/cert-svc/cpkcs12.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -48,7 +48,7 @@ int certsvc_pkcs12_alias_exists(CertSvcInstance instance, * @param[in] instance CertSvcInstance object. * @param[in] path Path to container file. * @param[in] password Container password (can be empty or NULL). - * @param[in] alias Logical name for certificate bundle idenification (can't be empty). + * @param[in] alias Logical name for certificate bundle identification (can't be empty). * @return CERTSVC_SUCCESS, CERTSVC_FAIL, CERTSVC_IO_ERROR, CERTSVC_INVALID_PASSWORD, CERTSVC_WRONG_ARGUMENT, CERTSVC_DUPLICATED_ALIAS */ int certsvc_pkcs12_import_from_file(CertSvcInstance instance, @@ -126,6 +126,215 @@ void certsvc_pkcs12_private_key_free(char *buffer); int certsvc_pkcs12_delete(CertSvcInstance instance, CertSvcString alias); +/** + * This function will load to memory private file content. This functin will + * not parse it in any way. + * This memory must be freed by certsvc_private_key_free. + * + * @param[in] instance CertSvcInstance object. + * @param[in] storeType Refers to VPN_STORE / WIFI_STORE / EMAIL_STORE / SYSTEM_STORE / ALL_STORE. + * @param[in] gname Container bundle identifier. + * @param[out] certBuffer Poiner to newly-allocated memory with private key data. + * @param[out] certsize Size of the newly-allocated buffer. Zero means there is no key. + * @return CERTSVC_SUCCESS, CERTSVC_FAIL, CERTSVC_IO_ERROR, CERTSVC_WRONG_ARGUMENT + */ +int certsvc_pkcs12_private_key_dup_from_store(CertSvcInstance instance, + CertStoreType storeType, + CertSvcString gname, + char **certBuffer, + size_t *certsize); + +/** + * This function will set the status for the specified certificate in a particular + * store to enabled / disabled. + * + * @param[in] instance CertSvcInstance object. + * @param[in] storeType Refers to VPN_STORE / WIFI_STORE / EMAIL_STORE / SYSTEM_STORE / ALL_STORE. + * @param[in] is_root_app Set to ENABLED/DISABLED. Should be ENABLED if master application is changing the status, else DISABLED for other applications. + * @param[in] gname Referred as group name, is the key for accessing the certificate. + * @param[in] status Allows to set the status of the certificate to enabled / disabled. + * @return CERTSVC_SUCCESS, CERTSVC_FAIL, CERTSVC_IO_ERROR, CERTSVC_WRONG_ARGUMENT, CERTSVC_INVALID_STORE_TYPE + */ +int certsvc_pkcs12_set_certificate_status_to_store(CertSvcInstance instance, + CertStoreType storeType, + int is_root_app, + CertSvcString gname, + CertStatus status); + +/** + * This function will get the status for the specified certificate in a particular + * store. + * + * @param[in] instance CertSvcInstance object. + * @param[in] storeType Refers to VPN_STORE / WIFI_STORE / EMAIL_STORE / SYSTEM_STORE / ALL_STORE. + * @param[in] gname Referred as group name, is the key for accessing the certificate. + * @param[out] status refers to weather the certificate is enabled/disabled. + * @return Disable=0, Enable=1, Fail=-1 + */ +int certsvc_pkcs12_get_certificate_status_from_store(CertSvcInstance instance, + CertStoreType storeType, + CertSvcString gname, + int *status); + +/** + * This function will get the Alias name, Path to certificate, Certificate status of all + * the certificates present in the specified certificate store. + * + * @param[in] instance CertSvcInstance object. + * @param[in] storeType Refers to VPN_STORE / WIFI_STORE / EMAIL_STORE / SYSTEM_STORE / ALL_STORE. + * @param[out] certList Linked-list having all the information about each certificate present in a store. + * @param[out] length Provides the length of the linked list. + * @return CERTSVC_SUCCESS, CERTSVC_FAIL, CERTSVC_IO_ERROR, CERTSVC_WRONG_ARGUMENT, CERTSVC_INVALID_STORE_TYPE + */ +int certsvc_pkcs12_get_certificate_list_from_store(CertSvcInstance instance, + CertStoreType storeType, + int is_root_app, + CertSvcStoreCertList** certList, + int* length); + +/** + * This function will get the Alias name, Path to certificate, Certificate status of all + * the end user certificates present in the specified certificate store. + * + * @param[in] instance CertSvcInstance object. + * @param[in] storeType Refers to VPN_STORE / WIFI_STORE / EMAIL_STORE / SYSTEM_STORE / ALL_STORE. + * @param[out] certList Linked-list having all the information about each certificate present in a store. + * @param[out] length Provides the length of the linked list. + * @return CERTSVC_SUCCESS, CERTSVC_FAIL, CERTSVC_IO_ERROR, CERTSVC_WRONG_ARGUMENT, CERTSVC_INVALID_STORE_TYPE + */ +int certsvc_pkcs12_get_end_user_certificate_list_from_store(CertSvcInstance instance, + CertStoreType storeType, + CertSvcStoreCertList** certList, + int* length); + +/** + * This function will get the Alias name, Path to certificate, Certificate status of all + * the root/trusted certificates present in the specified certificate store. + * + * @param[in] instance CertSvcInstance object. + * @param[in] storeType Refers to VPN_STORE / WIFI_STORE / EMAIL_STORE / SYSTEM_STORE / ALL_STORE. + * @param[out] certList Linked-list having all the information about each certificate present in a store. + * @param[out] length Provides the length of the linked list. + * @return CERTSVC_SUCCESS, CERTSVC_FAIL, CERTSVC_IO_ERROR, CERTSVC_WRONG_ARGUMENT, CERTSVC_INVALID_STORE_TYPE + */ +int certsvc_pkcs12_get_root_certificate_list_from_store(CertSvcInstance instance, + CertStoreType storeType, + CertSvcStoreCertList** certList, + int* length); + +/** + * This function will free all the linked list of data structure holding the information about + * all the certificates present in a store which was previously by calling the + * certsvc_get_certificate_list_from_store() function. + * + * @param[in] instance CertSvcInstance object. + * @param[in] certList The structure which need to be freed. + * @return CERTSVC_SUCCESS, CERTSVC_FAIL, CERTSVC_IO_ERROR, CERTSVC_WRONG_ARGUMENT, CERTSVC_INVALID_STORE_TYPE + */ +int certsvc_pkcs12_free_certificate_list_loaded_from_store(CertSvcInstance instance, + CertSvcStoreCertList** certList); + +/** + * This function will provide the certificate back for the gname provided. + * + * @param[in] instance CertSvcInstance object. + * @param[in] storeType Refers to VPN_STORE / WIFI_STORE / EMAIL_STORE / SYSTEM_STORE / ALL_STORE. + * @param[in[ gname Referred as group name, is the key for accessing the certificate. + * @param[out] certificate Certificate holding the information. + * @return CERTSVC_SUCCESS, CERTSVC_FAIL, CERTSVC_BAD_ALLOC + */ +int certsvc_pkcs12_get_certificate_from_store(CertSvcInstance instance, + CertStoreType storeType, + char *gname, + CertSvcCertificate *certificate); + +/** + * This function will give back the the encoded certificate buffer for the matching + * alias present in the specified store. + * + * @param[in] instance CertSvcInstance object. + * @param[in] storeType Refers to VPN_STORE / WIFI_STORE / EMAIL_STORE / SYSTEM_STORE / ALL_STORE. + * @param[in] gname Referred as group name, is the key for accessing the certificate. + * @param[out] certBuffer Buffer containing the encoded certificate. + * @param[out] certSize Size of the buffer. + * @return CERTSVC_SUCCESS, CERTSVC_FAIL, CERTSVC_IO_ERROR, CERTSVC_WRONG_ARGUMENT, CERTSVC_INVALID_STORE_TYPE + */ +int certsvc_pkcs12_get_certificate_info_from_store(CertSvcInstance instance, + CertStoreType storeType, + CertSvcString gname, + char** certBuffer, + size_t* certSize); + +/** + * This function will import a .pfx/.p12 file to specified store (WIFI, VPN, EMAIL). + * + * @param[in] instance CertSvcInstance object. + * @param[in] storeType Refers to VPN_STORE / WIFI_STORE / EMAIL_STORE / SYSTEM_STORE / ALL_STORE. + * @param[in] path Path of the certificate which needs to be imported. + * @param[in] password Password to open the pfx/p12 file. + * @param[in] alias Logical name for certificate bundle identification (can't be empty). + * @return CERTSVC_SUCCESS, CERTSVC_FAIL, CERTSVC_IO_ERROR, CERTSVC_WRONG_ARGUMENT, CERTSVC_INVALID_STORE_TYPE + */ +int certsvc_pkcs12_import_from_file_to_store(CertSvcInstance instance, + CertStoreType storeType, + CertSvcString path, + CertSvcString password, + CertSvcString alias); + +/** + * This function will delete the certificate from the path specified present in the specified store. + * + * @param[in] instance CertSvcInstance object. + * @param[in] storeType Refers to VPN_STORE / WIFI_STORE / EMAIL_STORE / SYSTEM_STORE / ALL_STORE. + * @param[in] gname Referred as group name, is the key for accessing the certificate. + * @return CERTSVC_SUCCESS, CERTSVC_FAIL, CERTSVC_IO_ERROR, CERTSVC_WRONG_ARGUMENT, CERTSVC_INVALID_STORE_TYPE + */ +int certsvc_pkcs12_delete_certificate_from_store(CertSvcInstance instance, + CertStoreType storeType, + CertSvcString gname); + +/** + * Query PKCS#12 storage to find out whenever new alias proposal is unique. + * + * @param[in] instance CertSvcInstance object. + * @param[in] storeType Refers to VPN_STORE / WIFI_STORE / EMAIL_STORE / SYSTEM_STORE / ALL_STORE. + * @param[in] proposal Desired alias name. + * @param[out] is_unique CERTSVC_TRUE (if there isn't such alias already) or CERTSVC_FALSE. + * @return CERTSVC_SUCCESS, CERTSVC_FAIL, CERTSVC_WRONG_ARGUMENT + */ +int certsvc_pkcs12_check_alias_exists_in_store(CertSvcInstance instance, + CertStoreType storeType, + CertSvcString alias, + int *is_unique); + +/** + * Get a list of certificates from PKCS#12 bundle. You may free this list by: + * certsvc_certificate_list_free. You may free certificates from list with: + * certsvc_certificate_free. + * + * @param[in] instance CertSvcInstance object. + * @param[in] pfxIdString Identification of pfx/pkcs file. + * @param[out] certificateList List of certificates. + * @return CERTSVC_SUCCESS, CERTSVC_BAD_ALLOC, CERTSVC_FAIL, CERTSVC_IO_ERROR + */ +int certsvc_pkcs12_load_certificate_list_from_store(CertSvcInstance instance, + CertStoreType storeType, + CertSvcString pfxIdString, + CertSvcCertificateList *certificateList); + +/** + * Gets the alias name for the gname passed. + * + * @param[in] instance CertSvcInstance object. + * @param[in] gname Certificate identification of pfx/pkcs file. + * @param[out] alias Alias name for the given gname. + * @return CERTSVC_SUCCESS, CERTSVC_FAIL, CERTSVC_WRONG_ARGUMENT + */ +int certsvc_pkcs12_get_alias_name_for_certificate_in_store(CertSvcInstance instance, + CertStoreType storeType, + CertSvcString gname, + char **alias); + #ifdef __cplusplus } #endif diff --git a/vcore/src/cert-svc/cprimitives.h b/vcore/src/cert-svc/cprimitives.h index da6fae6..d53b961 100644 --- a/vcore/src/cert-svc/cprimitives.h +++ b/vcore/src/cert-svc/cprimitives.h @@ -65,6 +65,22 @@ int certsvc_pkcs12_dup_evp_pkey(CertSvcInstance instance, CertSvcString alias, EVP_PKEY** pkey); +/** + * This will return pointer to EVP_PKEY base openssl struct. This struct must + * be release with function certsvc_pkcs12_free_evp_pkey + * + * @param[in] instance + * @param[in] storeType Refers to VPN_STORE / WIFI_STORE / EMAIL_STORE / SYSTEM_STORE / ALL_STORE. + * @param[in] gname Pkcs12 identificator. + * @param[out] pkey Duplicate of private key. + * @return CERTSVC_SUCCESS, CERT_FAIL + */ + +int certsvc_pkcs12_dup_evp_pkey_from_store(CertSvcInstance instance, + CertStoreType storeType, + CertSvcString gname, + EVP_PKEY** pkey); + void certsvc_pkcs12_free_evp_pkey(EVP_PKEY* pkey); #ifdef __cplusplus diff --git a/vcore/src/dpl/core/include/dpl/abstract_input.h b/vcore/src/dpl/core/include/dpl/abstract_input.h new file mode 100644 index 0000000..08a2733 --- /dev/null +++ b/vcore/src/dpl/core/include/dpl/abstract_input.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file abstract_input.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the header file of abstract input + */ +#ifndef DPL_ABSTRACT_INPUT_H +#define DPL_ABSTRACT_INPUT_H + +#include <dpl/exception.h> +#include <memory> + +namespace VcoreDPL { +class BinaryQueue; +typedef std::auto_ptr<BinaryQueue> BinaryQueueAutoPtr; + +class AbstractInput +{ + public: + class Exception + { + public: + DECLARE_EXCEPTION_TYPE(VcoreDPL::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, ReadFailed) + }; + + public: + virtual ~AbstractInput() {} + + /** + * Read binary data from input + * If no data is available method returns NULL buffer. + * In case connection was successfuly close, method returns empty buffer + * + * @param[in] size Maximum number of bytes to read from input + * @return Buffer containing read bytes + * @throw ReadFailed + */ + virtual BinaryQueueAutoPtr Read(size_t size) = 0; +}; +} // namespace VcoreDPL + +#endif // DPL_ABSTRACT_INPUT_H diff --git a/vcore/src/dpl/core/include/dpl/abstract_input_output.h b/vcore/src/dpl/core/include/dpl/abstract_input_output.h new file mode 100644 index 0000000..9d1f17c --- /dev/null +++ b/vcore/src/dpl/core/include/dpl/abstract_input_output.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file abstract_output.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the header file of abstract output + */ +#ifndef DPL_ABSTRACT_INPUT_OUTPUT_H +#define DPL_ABSTRACT_INPUT_OUTPUT_H + +#include <dpl/abstract_input.h> +#include <dpl/abstract_output.h> + +namespace VcoreDPL { +class AbstractInputOutput : + public AbstractInput, + public AbstractOutput +{ + public: + virtual ~AbstractInputOutput() {} +}; +} // namespace VcoreDPL + +#endif // DPL_ABSTRACT_INPUT_OUTPUT_H diff --git a/vcore/src/dpl/core/include/dpl/abstract_output.h b/vcore/src/dpl/core/include/dpl/abstract_output.h new file mode 100644 index 0000000..6b414eb --- /dev/null +++ b/vcore/src/dpl/core/include/dpl/abstract_output.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file abstract_output.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the header file of abstract output + */ +#ifndef DPL_ABSTRACT_OUTPUT_H +#define DPL_ABSTRACT_OUTPUT_H + +#include <dpl/exception.h> +#include <memory> + +namespace VcoreDPL { +class BinaryQueue; +typedef std::auto_ptr<BinaryQueue> BinaryQueueAutoPtr; + +class AbstractOutput +{ + public: + class Exception + { + public: + DECLARE_EXCEPTION_TYPE(VcoreDPL::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, WriteFailed) + }; + + public: + virtual ~AbstractOutput() {} + + /** + * Write binary data to output + * If output is blocked, Write returns zero, if instance is a type of + * WaitableAbstractOutput one can wait for writability then + * + * @param[in] buffer Input buffer with data to be written + * @param[in] bufferSize Maximum number of bytes to write from buffer + * @return Number of bytes success successfuly written or zero if output is + * blocked + * @throw WriteFailed + */ + virtual size_t Write(const BinaryQueue &buffer, size_t bufferSize) = 0; +}; +} // namespace VcoreDPL + +#endif // DPL_ABSTRACT_OUTPUT_H diff --git a/vcore/src/dpl/core/include/dpl/abstract_waitable_input.h b/vcore/src/dpl/core/include/dpl/abstract_waitable_input.h new file mode 100644 index 0000000..6447690 --- /dev/null +++ b/vcore/src/dpl/core/include/dpl/abstract_waitable_input.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file abstract_waitable_input.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the header file of abstract waitable input + */ +#ifndef DPL_ABSTRACT_WAITABLE_INPUT_H +#define DPL_ABSTRACT_WAITABLE_INPUT_H + +#include <dpl/waitable_handle.h> +#include <dpl/abstract_input.h> + +namespace VcoreDPL { +class AbstractWaitableInput : + public AbstractInput +{ + public: + virtual ~AbstractWaitableInput() {} + + virtual WaitableHandle WaitableReadHandle() const = 0; +}; +} // namespace VcoreDPL + +#endif // DPL_ABSTRACT_WAITABLE_INPUT_H diff --git a/vcore/src/dpl/core/include/dpl/assert.h b/vcore/src/dpl/core/include/dpl/assert.h new file mode 100644 index 0000000..b2cb426 --- /dev/null +++ b/vcore/src/dpl/core/include/dpl/assert.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file assert.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of assert + */ +#ifndef DPL_ASSERT_H +#define DPL_ASSERT_H + +namespace VcoreDPL { +// Assertion handler procedure +// Do not call directly +// Always use Assert macro +void AssertProc(const char *condition, + const char *file, + int line, + const char *function) __attribute__ ((__noreturn__)); +} // namespace VcoreDPL + +#define Assert(Condition) \ +do { \ + if (!(Condition)) { \ + VcoreDPL::AssertProc(#Condition, __FILE__, __LINE__, __FUNCTION__); \ + } \ +} while (0) + +#define AssertMsg(Condition, Msg) \ + do { \ + if (!(Condition)) { \ + VcoreDPL::AssertProc( \ + (std::string(std::string(#Condition)+" ") + Msg).c_str(), \ + __FILE__, __LINE__, __FUNCTION__); \ + } \ + } while (0) + +#endif // DPL_ASSERT_H diff --git a/vcore/src/dpl/core/include/dpl/availability.h b/vcore/src/dpl/core/include/dpl/availability.h new file mode 100644 index 0000000..0813892 --- /dev/null +++ b/vcore/src/dpl/core/include/dpl/availability.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file availability.h + * @author Jihoon Chung (jihoon.chung@samsung.com) + * @version 1.0 + */ +#ifndef DPL_AVAILABILITY_H +#define DPL_AVAILABILITY_H + +#define DPL_DEPRECATED __attribute__((deprecated)) +#define DPL_DEPRECATED_WITH_MESSAGE(msg) __attribute__((deprecated(msg))) + +#define DPL_UNUSED __attribute__((unused)) +#define DPL_UNUSED_PARAM(variable) (void)variable + +#endif // DPL_AVAILABILITY_H diff --git a/vcore/src/dpl/core/include/dpl/binary_queue.h b/vcore/src/dpl/core/include/dpl/binary_queue.h new file mode 100644 index 0000000..92d4e3f --- /dev/null +++ b/vcore/src/dpl/core/include/dpl/binary_queue.h @@ -0,0 +1,296 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file binary_queue.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the header file of binary queue + */ +#ifndef DPL_BINARY_QUEUE_H +#define DPL_BINARY_QUEUE_H + +#include <dpl/abstract_input_output.h> +#include <dpl/exception.h> +#include <dpl/noncopyable.h> +#include <memory> +#include <list> + +namespace VcoreDPL { +/** + * Binary stream implemented as constant size bucket list + * + * @todo Add optimized implementation for FlattenConsume + */ +class BinaryQueue : + public AbstractInputOutput +{ + public: + class Exception + { + public: + DECLARE_EXCEPTION_TYPE(VcoreDPL::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, OutOfData) + }; + + typedef void (*BufferDeleter)(const void *buffer, size_t bufferSize, + void *userParam); + static void BufferDeleterFree(const void *buffer, + size_t bufferSize, + void *userParam); + + class BucketVisitor + { + public: + /** + * Destructor + */ + virtual ~BucketVisitor(); + + /** + * Visit bucket + * + * @return none + * @param[in] buffer Constant pointer to bucket data buffer + * @param[in] bufferSize Number of bytes in bucket + */ + virtual void OnVisitBucket(const void *buffer, size_t bufferSize) = 0; + }; + + private: + struct Bucket : + private Noncopyable + { + const void *buffer; + const void *ptr; + size_t size; + size_t left; + + BufferDeleter deleter; + void *param; + + Bucket(const void *buffer, + size_t bufferSize, + BufferDeleter deleter, + void *userParam); + virtual ~Bucket(); + }; + + typedef std::list<Bucket *> BucketList; + BucketList m_buckets; + size_t m_size; + + static void DeleteBucket(Bucket *bucket); + + class BucketVisitorCall + { + private: + BucketVisitor *m_visitor; + + public: + BucketVisitorCall(BucketVisitor *visitor); + virtual ~BucketVisitorCall(); + + void operator()(Bucket *bucket) const; + }; + + public: + /** + * Construct empty binary queue + */ + BinaryQueue(); + + /** + * Construct binary queue via bare copy of other binary queue + * + * @param[in] other Other binary queue to copy from + * @warning One cannot assume that bucket structure is preserved during copy + */ + BinaryQueue(const BinaryQueue &other); + + /** + * Destructor + */ + virtual ~BinaryQueue(); + + /** + * Construct binary queue via bare copy of other binary queue + * + * @param[in] other Other binary queue to copy from + * @warning One cannot assume that bucket structure is preserved during copy + */ + BinaryQueue &operator=(const BinaryQueue &other); + + /** + * Append copy of @a bufferSize bytes from memory pointed by @a buffer + * to the end of binary queue. Uses default deleter based on free. + * + * @return none + * @param[in] buffer Pointer to buffer to copy data from + * @param[in] bufferSize Number of bytes to copy + * @exception std::bad_alloc Cannot allocate memory to hold additional data + * @see BinaryQueue::BufferDeleterFree + */ + void AppendCopy(const void *buffer, size_t bufferSize); + + /** + * Append @a bufferSize bytes from memory pointed by @a buffer + * to the end of binary queue. Uses custom provided deleter. + * Responsibility for deleting provided buffer is transfered to BinaryQueue. + * + * @return none + * @param[in] buffer Pointer to data buffer + * @param[in] bufferSize Number of bytes available in buffer + * @param[in] deleter Pointer to deleter procedure used to free provided + * buffer + * @param[in] userParam User parameter passed to deleter routine + * @exception std::bad_alloc Cannot allocate memory to hold additional data + */ + void AppendUnmanaged( + const void *buffer, + size_t bufferSize, + BufferDeleter deleter = + &BinaryQueue::BufferDeleterFree, + void *userParam = NULL); + + /** + * Append copy of other binary queue to the end of this binary queue + * + * @return none + * @param[in] other Constant reference to other binary queue to copy data + * from + * @exception std::bad_alloc Cannot allocate memory to hold additional data + * @warning One cannot assume that bucket structure is preserved during copy + */ + void AppendCopyFrom(const BinaryQueue &other); + + /** + * Move bytes from other binary queue to the end of this binary queue. + * This also removes all bytes from other binary queue. + * This method is designed to be as fast as possible (only pointer swaps) + * and is suggested over making copies of binary queues. + * Bucket structure is preserved after operation. + * + * @return none + * @param[in] other Reference to other binary queue to move data from + * @exception std::bad_alloc Cannot allocate memory to hold additional data + */ + void AppendMoveFrom(BinaryQueue &other); + + /** + * Append copy of binary queue to the end of other binary queue + * + * @return none + * @param[in] other Constant reference to other binary queue to copy data to + * @exception std::bad_alloc Cannot allocate memory to hold additional data + * @warning One cannot assume that bucket structure is preserved during copy + */ + void AppendCopyTo(BinaryQueue &other) const; + + /** + * Move bytes from binary queue to the end of other binary queue. + * This also removes all bytes from binary queue. + * This method is designed to be as fast as possible (only pointer swaps) + * and is suggested over making copies of binary queues. + * Bucket structure is preserved after operation. + * + * @return none + * @param[in] other Reference to other binary queue to move data to + * @exception std::bad_alloc Cannot allocate memory to hold additional data + */ + void AppendMoveTo(BinaryQueue &other); + + /** + * Retrieve total size of all data contained in binary queue + * + * @return Number of bytes in binary queue + */ + size_t Size() const; + + /** + * Remove all data from binary queue + * + * @return none + */ + void Clear(); + + /** + * Check if binary queue is empty + * + * @return true if binary queue is empty, false otherwise + */ + bool Empty() const; + + /** + * Remove @a size bytes from beginning of binary queue + * + * @return none + * @param[in] size Number of bytes to remove + * @exception BinaryQueue::Exception::OutOfData Number of bytes is larger + * than available bytes in binary queue + */ + void Consume(size_t size); + + /** + * Retrieve @a bufferSize bytes from beginning of binary queue and copy them + * to user supplied buffer + * + * @return none + * @param[in] buffer Pointer to user buffer to receive bytes + * @param[in] bufferSize Size of user buffer pointed by @a buffer + * @exception BinaryQueue::Exception::OutOfData Number of bytes to flatten + * is larger than available bytes in binary queue + */ + void Flatten(void *buffer, size_t bufferSize) const; + + /** + * Retrieve @a bufferSize bytes from beginning of binary queue, copy them + * to user supplied buffer, and remove from binary queue + * + * @return none + * @param[in] buffer Pointer to user buffer to receive bytes + * @param[in] bufferSize Size of user buffer pointed by @a buffer + * @exception BinaryQueue::Exception::OutOfData Number of bytes to flatten + * is larger than available bytes in binary queue + */ + void FlattenConsume(void *buffer, size_t bufferSize); + + /** + * Visit each buffer with data using visitor object + * + * @return none + * @param[in] visitor Pointer to bucket visitor + * @see BinaryQueue::BucketVisitor + */ + void VisitBuckets(BucketVisitor *visitor) const; + + /** + * IAbstractInput interface + */ + virtual BinaryQueueAutoPtr Read(size_t size); + + /** + * IAbstractOutput interface + */ + virtual size_t Write(const BinaryQueue &buffer, size_t bufferSize); +}; + +/** + * Binary queue auto pointer + */ +typedef std::auto_ptr<BinaryQueue> BinaryQueueAutoPtr; +} // namespace VcoreDPL + +#endif // DPL_BINARY_QUEUE_H diff --git a/vcore/src/dpl/core/include/dpl/char_traits.h b/vcore/src/dpl/core/include/dpl/char_traits.h new file mode 100644 index 0000000..a9d0bc0 --- /dev/null +++ b/vcore/src/dpl/core/include/dpl/char_traits.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file char_traits.h + * @author Piotr Marcinkiewicz (p.marcinkiew@samsung.com) + * @version 1.0 + * @brief Char traits are used to create basic_string extended with + * additional features + * Current char traits could be extended in feature to boost + * performance + */ +#ifndef DPL_CHAR_TRAITS +#define DPL_CHAR_TRAITS + +#include <cstring> +#include <string> +#include <ostream> +#include <algorithm> +#include <dpl/exception.h> + +namespace VcoreDPL { +typedef std::char_traits<wchar_t> CharTraits; +} // namespace VcoreDPL + +#endif // DPL_CHAR_TRAITS diff --git a/vcore/src/dpl/core/include/dpl/colors.h b/vcore/src/dpl/core/include/dpl/colors.h new file mode 100644 index 0000000..4c22139 --- /dev/null +++ b/vcore/src/dpl/core/include/dpl/colors.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file colors.h + * @author Lukasz Wrzosek (l.wrzosek@samsung.com) + * @version 1.0 + * @brief Some constants with definition of colors for Console + * and html output + */ + +#ifndef DPL_COLORS_H +#define DPL_COLORS_H + +namespace VcoreDPL { +namespace Colors { +namespace Text { +extern const char* BOLD_GREEN_BEGIN; +extern const char* BOLD_GREEN_END; +extern const char* PURPLE_BEGIN; +extern const char* PURPLE_END; +extern const char* RED_BEGIN; +extern const char* RED_END; +extern const char* GREEN_BEGIN; +extern const char* GREEN_END; +extern const char* CYAN_BEGIN; +extern const char* CYAN_END; +extern const char* BOLD_RED_BEGIN; +extern const char* BOLD_RED_END; +extern const char* BOLD_YELLOW_BEGIN; +extern const char* BOLD_YELLOW_END; +extern const char* BOLD_GOLD_BEGIN; +extern const char* BOLD_GOLD_END; +extern const char* BOLD_WHITE_BEGIN; +extern const char* BOLD_WHITE_END; +} //namespace Text + +namespace Html { +extern const char* BOLD_GREEN_BEGIN; +extern const char* BOLD_GREEN_END; +extern const char* PURPLE_BEGIN; +extern const char* PURPLE_END; +extern const char* RED_BEGIN; +extern const char* RED_END; +extern const char* GREEN_BEGIN; +extern const char* GREEN_END; +extern const char* CYAN_BEGIN; +extern const char* CYAN_END; +extern const char* BOLD_RED_BEGIN; +extern const char* BOLD_RED_END; +extern const char* BOLD_YELLOW_BEGIN; +extern const char* BOLD_YELLOW_END; +extern const char* BOLD_GOLD_BEGIN; +extern const char* BOLD_GOLD_END; +extern const char* BOLD_WHITE_BEGIN; +extern const char* BOLD_WHITE_END; +} //namespace Html +} //namespace Colors +} //namespace VcoreDPL + +#endif /* DPL_COLORS_H */ diff --git a/vcore/src/dpl/core/include/dpl/errno_string.h b/vcore/src/dpl/core/include/dpl/errno_string.h new file mode 100644 index 0000000..5ea55e5 --- /dev/null +++ b/vcore/src/dpl/core/include/dpl/errno_string.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file errno_string.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of errno string + */ +#ifndef DPL_ERRNO_STRING_H +#define DPL_ERRNO_STRING_H + +#include <dpl/exception.h> +#include <string> +#include <cerrno> + +namespace VcoreDPL { +DECLARE_EXCEPTION_TYPE(VcoreDPL::Exception, InvalidErrnoValue) + +std::string GetErrnoString(int error = errno); +} // namespace VcoreDPL + +#endif // DPL_ERRNO_STRING_H diff --git a/vcore/src/dpl/core/include/dpl/exception.h b/vcore/src/dpl/core/include/dpl/exception.h new file mode 100644 index 0000000..95ea4ac --- /dev/null +++ b/vcore/src/dpl/core/include/dpl/exception.h @@ -0,0 +1,390 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file exception.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief Header file for base exception + */ +#ifndef VcoreDPL_EXCEPTION_H +#define VcoreDPL_EXCEPTION_H + +#include <string> +#include <cstring> +#include <cstdio> +#include <exception> +#include <cstdlib> +#include <sstream> + +namespace VcoreDPL { +void LogUnhandledException(const std::string &str); +void LogUnhandledException(const std::string &str, + const char *filename, + int line, + const char *function); +} + +namespace VcoreDPL { +class Exception { +private: + static unsigned int m_exceptionCount; + static Exception* m_lastException; + static void (*m_terminateHandler)(); + + static void AddRef(Exception* exception) + { + if (!m_exceptionCount) { + m_terminateHandler = std::set_terminate(&TerminateHandler); + } + + ++m_exceptionCount; + m_lastException = exception; + } + + static void UnRef(Exception* e) + { + if (m_lastException == e) { + m_lastException = NULL; + } + + --m_exceptionCount; + + if (!m_exceptionCount) { + std::set_terminate(m_terminateHandler); + m_terminateHandler = NULL; + } + } + + static void TerminateHandler() + { + if (m_lastException != NULL) { + DisplayKnownException(*m_lastException); + abort(); + } else { + DisplayUnknownException(); + abort(); + } + } + + Exception *m_reason; + std::string m_path; + std::string m_function; + int m_line; + +protected: + std::string m_message; + std::string m_className; + +public: + static std::string KnownExceptionToString(const Exception &e) + { + std::ostringstream message; + message << + "\033[1;5;31m\n=== Unhandled DPL exception occurred ===\033[m\n\n"; + message << "\033[1;33mException trace:\033[m\n\n"; + message << e.DumpToString(); + message << "\033[1;31m\n=== Will now abort ===\033[m\n"; + + return message.str(); + } + + static std::string UnknownExceptionToString() + { + std::ostringstream message; + message << + "\033[1;5;31m\n=== Unhandled non-DPL exception occurred ===\033[m\n\n"; + message << "\033[1;31m\n=== Will now abort ===\033[m\n"; + + return message.str(); + } + + static void DisplayKnownException(const Exception& e) + { + LogUnhandledException(KnownExceptionToString(e).c_str()); + } + + static void DisplayUnknownException() + { + LogUnhandledException(UnknownExceptionToString().c_str()); + } + + Exception(const Exception &other) + { + // Deep copy + if (other.m_reason != NULL) { + m_reason = new Exception(*other.m_reason); + } else { + m_reason = NULL; + } + + m_message = other.m_message; + m_path = other.m_path; + m_function = other.m_function; + m_line = other.m_line; + + m_className = other.m_className; + + AddRef(this); + } + + const Exception &operator =(const Exception &other) + { + if (this == &other) { + return *this; + } + + // Deep copy + if (other.m_reason != NULL) { + m_reason = new Exception(*other.m_reason); + } else { + m_reason = NULL; + } + + m_message = other.m_message; + m_path = other.m_path; + m_function = other.m_function; + m_line = other.m_line; + + m_className = other.m_className; + + AddRef(this); + + return *this; + } + + Exception(const char *path, + const char *function, + int line, + const std::string &message) : + m_reason(NULL), + m_path(path), + m_function(function), + m_line(line), + m_message(message) + { + AddRef(this); + } + + Exception(const char *path, + const char *function, + int line, + const Exception &reason, + const std::string &message) : + m_reason(new Exception(reason)), + m_path(path), + m_function(function), + m_line(line), + m_message(message) + { + AddRef(this); + } + + virtual ~Exception() throw() + { + if (m_reason != NULL) { + delete m_reason; + m_reason = NULL; + } + + UnRef(this); + } + + void Dump() const + { + // Show reason first + if (m_reason != NULL) { + m_reason->Dump(); + } + + // Afterward, dump exception + const char *file = strchr(m_path.c_str(), '/'); + + if (file == NULL) { + file = m_path.c_str(); + } else { + ++file; + } + + printf("\033[0;36m[%s:%i]\033[m %s() \033[4;35m%s\033[m: %s\033[m\n", + file, m_line, + m_function.c_str(), + m_className.c_str(), + m_message.empty() ? "<EMPTY>" : m_message.c_str()); + } + + std::string DumpToString() const + { + std::string ret; + if (m_reason != NULL) { + ret = m_reason->DumpToString(); + } + + const char *file = strchr(m_path.c_str(), '/'); + + if (file == NULL) { + file = m_path.c_str(); + } else { + ++file; + } + + char buf[1024]; + snprintf(buf, + sizeof(buf), + "\033[0;36m[%s:%i]\033[m %s() \033[4;35m%s\033[m: %s\033[m\n", + file, + m_line, + m_function.c_str(), + m_className.c_str(), + m_message.empty() ? "<EMPTY>" : m_message.c_str()); + + buf[sizeof(buf) - 1] = '\n'; + ret += buf; + + return ret; + } + + Exception *GetReason() const + { + return m_reason; + } + + std::string GetPath() const + { + return m_path; + } + + std::string GetFunction() const + { + return m_function; + } + + int GetLine() const + { + return m_line; + } + + std::string GetMessage() const + { + return m_message; + } + + std::string GetClassName() const + { + return m_className; + } +}; +} // namespace VcoreDPL + +#define Try try + +#define Throw(ClassName) \ + throw ClassName(__FILE__, __FUNCTION__, __LINE__) + +#define ThrowMsg(ClassName, Message) \ + do \ + { \ + std::ostringstream dplLoggingStream; \ + dplLoggingStream << Message; \ + throw ClassName(__FILE__, __FUNCTION__, __LINE__, dplLoggingStream.str()); \ + } while (0) + +#define ReThrow(ClassName) \ + throw ClassName(__FILE__, __FUNCTION__, __LINE__, _rethrown_exception) + +#define ReThrowMsg(ClassName, Message) \ + throw ClassName(__FILE__, \ + __FUNCTION__, \ + __LINE__, \ + _rethrown_exception, \ + Message) + +#define Catch(ClassName) \ + catch (const ClassName &_rethrown_exception) + +#define DECLARE_EXCEPTION_TYPE(BaseClass, Class) \ + class Class : public BaseClass { \ + public: \ + Class(const char *path, \ + const char *function, \ + int line, \ + const std::string & message = std::string()) \ + : BaseClass(path, function, line, message) { \ + \ + BaseClass::m_className = #Class; \ + } \ + \ + Class(const char *path, \ + const char *function, \ + int line, \ + const VcoreDPL::Exception & reason, \ + const std::string & message = std::string()) \ + : BaseClass(path, function, line, reason, message) { \ + BaseClass::m_className = #Class; \ + } \ + }; + +#define UNHANDLED_EXCEPTION_HANDLER_BEGIN try + +#define UNHANDLED_EXCEPTION_HANDLER_END \ + catch (const VcoreDPL::Exception &exception) \ + { \ + std::ostringstream msg; \ + msg << VcoreDPL::Exception::KnownExceptionToString(exception); \ + VcoreDPL::LogUnhandledException(msg.str(), \ + __FILE__, \ + __LINE__, \ + __FUNCTION__); \ + abort(); \ + } \ + catch (std::exception& e) \ + { \ + std::ostringstream msg; \ + msg << e.what(); \ + msg << "\n"; \ + msg << VcoreDPL::Exception::UnknownExceptionToString(); \ + VcoreDPL::LogUnhandledException(msg.str(), \ + __FILE__, \ + __LINE__, \ + __FUNCTION__); \ + abort(); \ + } \ + catch (...) \ + { \ + std::ostringstream msg; \ + msg << VcoreDPL::Exception::UnknownExceptionToString(); \ + VcoreDPL::LogUnhandledException(msg.str(), \ + __FILE__, \ + __LINE__, \ + __FUNCTION__); \ + abort(); \ + } + +namespace VcoreDPL { +namespace CommonException { +/** + * Internal exception definitions + * + * These should normally not happen. + * Usually, exception trace with internal error includes + * important messages. + */ +DECLARE_EXCEPTION_TYPE(Exception, InternalError) ///< Unexpected error from + // underlying libraries or + // kernel +} +} + +#endif // VcoreDPL_EXCEPTION_H diff --git a/vcore/src/dpl/core/include/dpl/file_input.h b/vcore/src/dpl/core/include/dpl/file_input.h new file mode 100644 index 0000000..d982957 --- /dev/null +++ b/vcore/src/dpl/core/include/dpl/file_input.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file file_input.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of file input + */ +#ifndef DPL_FILE_INPUT_H +#define DPL_FILE_INPUT_H + +#include <dpl/noncopyable.h> +#include <dpl/exception.h> +#include <dpl/abstract_waitable_input.h> + +namespace VcoreDPL { +class FileInput : + private Noncopyable, + public AbstractWaitableInput +{ + public: + class Exception + { + public: + DECLARE_EXCEPTION_TYPE(VcoreDPL::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, OpenFailed) + DECLARE_EXCEPTION_TYPE(Base, CloseFailed) + }; + + protected: + int m_fd; + + public: + FileInput(); + FileInput(const std::string &fileName); + virtual ~FileInput(); + + void Open(const std::string &fileName); + void Close(); + + // AbstractInput + virtual BinaryQueueAutoPtr Read(size_t size); + + // AbstractWaitableInput + virtual WaitableHandle WaitableReadHandle() const; +}; +} // namespace VcoreDPL + +#endif // DPL_FILE_INPUT_H diff --git a/vcore/src/dpl/core/include/dpl/foreach.h b/vcore/src/dpl/core/include/dpl/foreach.h new file mode 100644 index 0000000..0a4485d --- /dev/null +++ b/vcore/src/dpl/core/include/dpl/foreach.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file foreach.h + * @author Bartosz Janiak (b.janiak@samsung.com) + * @author Lukasz Wrzosek (l.wrzosek@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of foreach macro for stl + * containers + */ +#ifndef DPL_FOREACH_H +#define DPL_FOREACH_H + +#include <dpl/preprocessor.h> + +namespace VcoreDPL { +namespace Private { +/* + * Used to detect type of valid reference to value object. + */ +template <typename T> +T& ValueReference(T& t) +{ + return(t); +} + +template <typename T> +const T& ValueReference(const T& t) +{ + return(t); +} +} //Private +} //DPL + +#define DPL_FOREACH_IMPL(temporaryName, iterator, container) \ + __typeof__ (VcoreDPL::Private::ValueReference((container))) & \ + temporaryName = (container); \ + for (__typeof__ (temporaryName.begin())iterator = \ + temporaryName.begin(); \ + (iterator) != temporaryName.end(); ++iterator) + +#define FOREACH(iterator, container) \ + DPL_FOREACH_IMPL( \ + DPL_MACRO_CONCAT(foreachContainerReference, __COUNTER__), \ + iterator, \ + container) + +#endif // DPL_FOREACH_H diff --git a/vcore/src/dpl/core/include/dpl/free_deleter.h b/vcore/src/dpl/core/include/dpl/free_deleter.h new file mode 100644 index 0000000..f3494f2 --- /dev/null +++ b/vcore/src/dpl/core/include/dpl/free_deleter.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file free_deleter.h + * @author Pawel Czajkowski (p.czajkowski@samsung.com) + * @version 1.0 + * @brief This file is the implementation file deleter with use std::free() + */ +#ifndef FREE_DELETER_H +#define FREE_DELETER_H + +#include <cstdlib> +namespace VcoreDPL +{ +struct free_deleter +{ + void operator()(void *p) { std::free(p); } +}; +}// DPL +#endif // FREE_DELETER_H diff --git a/vcore/src/dpl/core/include/dpl/lexical_cast.h b/vcore/src/dpl/core/include/dpl/lexical_cast.h new file mode 100644 index 0000000..b08f513 --- /dev/null +++ b/vcore/src/dpl/core/include/dpl/lexical_cast.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file lexical_cast.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief Header file for lexical cast + */ +#ifndef DPL_LEXICAL_CAST_H +#define DPL_LEXICAL_CAST_H + +#include <sstream> + +namespace VcoreDPL { +template<typename TargetType, typename SourceType> +TargetType lexical_cast(const SourceType &data) +{ + TargetType result; + + std::ostringstream out; + out << data; + + std::istringstream in(out.str()); + in >> result; + + return result; +} +} // namespace VcoreDPL + +#endif // DPL_LEXICAL_CAST_H diff --git a/vcore/src/dpl/core/include/dpl/noncopyable.h b/vcore/src/dpl/core/include/dpl/noncopyable.h new file mode 100644 index 0000000..89372d0 --- /dev/null +++ b/vcore/src/dpl/core/include/dpl/noncopyable.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file noncopyable + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of noncopyable + */ +#ifndef DPL_NONCOPYABLE_H +#define DPL_NONCOPYABLE_H + +namespace VcoreDPL { +class Noncopyable +{ + private: + Noncopyable(const Noncopyable &); + const Noncopyable &operator=(const Noncopyable &); + + public: + Noncopyable(); + virtual ~Noncopyable(); +}; +} // namespace VcoreDPL + +#endif // DPL_NONCOPYABLE_H diff --git a/vcore/src/dpl/core/include/dpl/optional.h b/vcore/src/dpl/core/include/dpl/optional.h new file mode 100644 index 0000000..2f37aa1 --- /dev/null +++ b/vcore/src/dpl/core/include/dpl/optional.h @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file optional_value.h + * @author Lukasz Wrzosek (l.wrzosek@samsung.com) + * @version 1.0 + */ + +#ifndef DPL_OPTIONAL_H +#define DPL_OPTIONAL_H + +#include <dpl/exception.h> +#include <dpl/availability.h> + +namespace VcoreDPL { +template <typename Type> +class Optional +{ + class Exception + { + public: + DECLARE_EXCEPTION_TYPE(VcoreDPL::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, NullReference) + }; + + public: + Optional() : + m_null(true), + m_value() + {} + + Optional(const Type& t) : + m_null(false), + m_value(t) + {} + + bool IsNull() const + { + return m_null; + } + + Type& operator*() + { + if (m_null) { + Throw(typename Exception::NullReference); + } + return m_value; + } + + const Type& operator*() const + { + if (m_null) { + Throw(typename Exception::NullReference); + } + return m_value; + } + + const Type* operator->() const + { + if (m_null) { + Throw(typename Exception::NullReference); + } + return &m_value; + } + + Type* operator->() + { + if (m_null) { + Throw(typename Exception::NullReference); + } + return &m_value; + } + + bool operator!() const + { + return m_null; + } + + Optional<Type>& operator=(const Type& other) + { + m_null = false; + m_value = other; + return *this; + } + + bool operator==(const Optional<Type>& aSecond) const + { + return LogicalOperator<true>(*this, aSecond, + std::equal_to<Type>(), std::equal_to<bool>()); + } + + bool operator==(const Type& aSecond) const + { + return Optional<Type>(aSecond) == *this; + } + + bool operator!=(const Optional<Type>& aSecond) const + { + return !(*this == aSecond); + } + + bool operator<(const Optional<Type>& aSecond) const + { + return LogicalOperator<false>(*this, aSecond, + std::less<Type>(), std::less<bool>()); + } + + bool operator>(const Optional<Type>& aSecond) const + { + return LogicalOperator<false>(*this, aSecond, + std::greater<Type>(), std::greater<bool>()); + } + + bool operator<=(const Optional<Type>& aSecond) const + { + return *this == aSecond || *this < aSecond; + } + + bool operator>=(const Optional<Type>& aSecond) const + { + return *this == aSecond || *this > aSecond; + } + + static Optional<Type> Null; + + private: + bool m_null; + Type m_value; + + template <bool taEquality, typename taComparator, typename taNullComparator> + static bool LogicalOperator(const Optional<Type>& aFirst, + const Optional<Type>& aSecond, + taComparator aComparator, + taNullComparator aNullComparator) + { + if (aFirst.m_null == aSecond.m_null) { + if (aFirst.m_null) { + return taEquality; + } else { + return aComparator(aFirst.m_value, aSecond.m_value); + } + } else { + return aNullComparator(aFirst.m_null, aSecond.m_null); + } + } +} DPL_DEPRECATED_WITH_MESSAGE("Use boost::optional instead"); + +template<typename Type> +Optional<Type> Optional<Type>::Null = Optional<Type>(); +} //namespace VcoreDPL + +template<typename Type> +std::ostream& operator<<(std::ostream& aStream, + const VcoreDPL::Optional<Type>& aOptional) +{ + if (aOptional.IsNull()) { + return aStream << "null optional"; + } else { + return aStream << *aOptional; + } +} + +#endif // DPL_OPTIONAL_VALUE_H diff --git a/vcore/src/dpl/core/include/dpl/optional_typedefs.h b/vcore/src/dpl/core/include/dpl/optional_typedefs.h new file mode 100644 index 0000000..bd411f2 --- /dev/null +++ b/vcore/src/dpl/core/include/dpl/optional_typedefs.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef DPL_OPTIONAL_TYPEDEFS_H +#define DPL_OPTIONAL_TYPEDEFS_H + +#include <string> +#include <dpl/string.h> +#include <boost/optional.hpp> + +namespace VcoreDPL { +typedef boost::optional<String> OptionalString; +typedef boost::optional<int> OptionalInt; +typedef boost::optional<unsigned int> OptionalUInt; +typedef boost::optional<bool> OptionalBool; +typedef boost::optional<float> OptionalFloat; +typedef boost::optional<std::string> OptionalStdString; +} //namespace VcoreDPL + +#endif /* DPL_OPTIONAL_TYPEDEFS_H */ + diff --git a/vcore/src/dpl/core/include/dpl/preprocessor.h b/vcore/src/dpl/core/include/dpl/preprocessor.h new file mode 100644 index 0000000..6fca34c --- /dev/null +++ b/vcore/src/dpl/core/include/dpl/preprocessor.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file preprocessor.h + * @author Lukasz Wrzosek (l.wrzosek@samsung.com) + * @version 1.0 + * @brief This file contains some usefull macros. + */ + +#ifndef DPL_PREPROCESSOR_H +#define DPL_PREPROCESSOR_H + +#define DPL_MACRO_CONCAT_IMPL(x, y) x##y +#define DPL_MACRO_CONCAT(x, y) DPL_MACRO_CONCAT_IMPL(x, y) + +#ifdef __COUNTER__ +#define DPL_ANONYMOUS_VARIABLE(name) DPL_MACRO_CONCAT(name, __COUNTER__) +#else +#define DPL_ANONYMOUS_VARIABLE(name) DPL_MACRO_CONCAT(name, __LINE__) +#endif + +#endif //DPL_PREPROCESSOR_H diff --git a/vcore/src/dpl/core/include/dpl/scoped_array.h b/vcore/src/dpl/core/include/dpl/scoped_array.h new file mode 100644 index 0000000..e117f33 --- /dev/null +++ b/vcore/src/dpl/core/include/dpl/scoped_array.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*! + * @file scoped_ptr.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of scoped array RAII + * + * This module is deprecated, please use standard C++11 feature: std::unique_ptr<Type[]> + */ +#ifndef DPL_SCOPED_ARRAY_H +#define DPL_SCOPED_ARRAY_H + +#include <cstddef> + +#include <dpl/assert.h> +#include <dpl/scoped_resource.h> +#include <dpl/availability.h> + +namespace VcoreDPL { +template<typename Class> +struct ScopedArrayPolicy +{ + typedef Class* Type; + static Type NullValue() + { + return NULL; + } + static void Destroy(Type ptr) + { + delete[] ptr; + } +}; + +template<typename Class> +class ScopedArray : public ScopedResource<ScopedArrayPolicy<Class> > +{ + typedef ScopedArrayPolicy<Class> Policy; + typedef ScopedResource<Policy> BaseType; + + public: + explicit ScopedArray(Class *ptr = Policy::NullValue()) : BaseType(ptr) { } + + Class &operator [](std::ptrdiff_t k) const + { + Assert(this->m_value != Policy::NullValue() && + "Dereference of scoped NULL array!"); + Assert(k >= 0 && "Negative array index"); + + return this->m_value[k]; + } +} DPL_DEPRECATED_WITH_MESSAGE("use standard C++11 feature: std::unique_ptr<Type[]>"); +} // namespace VcoreDPL + +#endif // DPL_SCOPED_PTR_H diff --git a/vcore/src/dpl/core/include/dpl/scoped_fclose.h b/vcore/src/dpl/core/include/dpl/scoped_fclose.h new file mode 100644 index 0000000..8813497 --- /dev/null +++ b/vcore/src/dpl/core/include/dpl/scoped_fclose.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*! + * @file scoped_fclose.h + * @author Piotr Marcinkiewicz (p.marcinkiew@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of scoped fclose RAII + */ +#ifndef DPL_SCOPED_FCLOSE_H +#define DPL_SCOPED_FCLOSE_H + +#include <unistd.h> +#include <cerrno> +#include <cstdio> +#include <string> +#include <dpl/log/vcore_log.h> +#include <dpl/scoped_resource.h> +#include <dpl/errno_string.h> + +namespace VcoreDPL { +struct ScopedFClosePolicy +{ + typedef FILE* Type; + static Type NullValue() + { + return NULL; + } + static void Destroy(Type file) + { + if (file != NULL) { + // Try to flush first + if (TEMP_FAILURE_RETRY(fflush(file)) != 0) { + std::string errString = GetErrnoString(); + VcoreLogD("Failed to fflush scoped fclose error: %s", + errString.c_str()); + } + + // fclose cannot be retried, try to close once + if (fclose(file) != 0) { + std::string errString = GetErrnoString(); + VcoreLogD("Failed scoped fclose error: %s", errString.c_str()); + } + } + } +}; + +class ScopedFClose : public ScopedResource<ScopedFClosePolicy> +{ + typedef ScopedFClosePolicy Policy; + typedef ScopedResource<Policy> BaseType; + + public: + explicit ScopedFClose(FILE* argFileStream = Policy::NullValue()) : + BaseType(argFileStream) + {} +}; +} // namespace VcoreDPL + +#endif // DPL_SCOPED_FCLOSE_H diff --git a/vcore/src/dpl/core/include/dpl/scoped_free.h b/vcore/src/dpl/core/include/dpl/scoped_free.h new file mode 100644 index 0000000..7f9685b --- /dev/null +++ b/vcore/src/dpl/core/include/dpl/scoped_free.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*! + * @file scoped_free.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of scoped free RAII + */ + +#ifndef DPL_SCOPED_FREE_H +#define DPL_SCOPED_FREE_H + +#include <malloc.h> +#include <cstddef> + +#include <dpl/scoped_resource.h> + +namespace VcoreDPL { +template<typename Class> +struct ScopedFreePolicy +{ + typedef Class* Type; + static Type NullValue() + { + return NULL; + } + static void Destroy(Type ptr) + { + free(ptr); + } +}; + +template<typename Memory> +class ScopedFree : public ScopedResource<ScopedFreePolicy<Memory> > +{ + typedef ScopedFreePolicy<Memory> Policy; + typedef ScopedResource<Policy> BaseType; + + public: + explicit ScopedFree(Memory *ptr = Policy::NullValue()) : BaseType(ptr) { } +}; +} // namespace VcoreDPL + +#endif // DPL_SCOPED_FREE_H diff --git a/vcore/src/dpl/core/include/dpl/scoped_resource.h b/vcore/src/dpl/core/include/dpl/scoped_resource.h new file mode 100644 index 0000000..ed034dd --- /dev/null +++ b/vcore/src/dpl/core/include/dpl/scoped_resource.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file scoped_resource.h + * @author Piotr Marcinkiewicz (p.marcinkiew@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of scoped resource pattern + */ +#ifndef DPL_SCOPED_RESOURCE_H +#define DPL_SCOPED_RESOURCE_H + +#include <dpl/noncopyable.h> + +namespace VcoreDPL { +template<typename ClassPolicy> +class ScopedResource : + private Noncopyable +{ + public: + typedef typename ClassPolicy::Type ValueType; + typedef ScopedResource<ClassPolicy> ThisType; + + protected: + ValueType m_value; + + public: + explicit ScopedResource(ValueType value) : m_value(value) { } + + ~ScopedResource() + { + ClassPolicy::Destroy(m_value); + } + + ValueType Get() const + { + return m_value; + } + + void Reset(ValueType value = ClassPolicy::NullValue()) + { + ClassPolicy::Destroy(m_value); + m_value = value; + } + + ValueType Release() + { + ValueType value = m_value; + m_value = ClassPolicy::NullValue(); + return value; + } + typedef ValueType ThisType::*UnknownBoolType; + + operator UnknownBoolType() const + { + return m_value == ClassPolicy::NullValue() ? + 0 : //0 is valid here because it converts to false + &ThisType::m_value; //it converts to true + } + + bool operator !() const + { + return m_value == ClassPolicy::NullValue(); + } +}; +} // namespace VcoreDPL + +#endif // DPL_SCOPED_RESOURCE_H diff --git a/vcore/src/dpl/core/include/dpl/singleton.h b/vcore/src/dpl/core/include/dpl/singleton.h new file mode 100644 index 0000000..4371f32 --- /dev/null +++ b/vcore/src/dpl/core/include/dpl/singleton.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file singleton.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of singleton + */ +#ifndef DPL_SINGLETON_H +#define DPL_SINGLETON_H + +#include <boost/optional.hpp> +#include <dpl/thread.h> +#include <dpl/assert.h> + +namespace VcoreDPL { +template<typename Class> +class Singleton : + private Class +{ + // + // Note: + // + // To remove posibility of instantiating directly Class, + // make Class' default constructor protected + // + + private: + Singleton() + {} + + typedef boost::optional<Thread *> OptionalThreadPtr; + + static Singleton &InternalInstance(); + + public: + virtual ~Singleton() + {} + + static Class &Instance(); +}; +} // namespace VcoreDPL + +#endif // DPL_SINGLETON_H diff --git a/vcore/src/dpl/core/include/dpl/singleton_impl.h b/vcore/src/dpl/core/include/dpl/singleton_impl.h new file mode 100644 index 0000000..fd70741 --- /dev/null +++ b/vcore/src/dpl/core/include/dpl/singleton_impl.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file singleton_impl.h + * @author Lukasz Wrzosek (l.wrzosek@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of singleton + */ +#ifndef DPL_SINGLETON_IMPL_H +#define DPL_SINGLETON_IMPL_H + +/* + * WARNING! + * + * If some singleton's implementation uses another singletons implementation, + * those templates make the second singleton a dubleton. Be warned. Try to use + * singleton_safe_impl.h if possible. + */ + +namespace VcoreDPL { +template<typename Class> +Singleton<Class>& Singleton<Class>::InternalInstance() +{ + static Singleton<Class> instance; + return instance; +} + +template<typename Class> +Class &Singleton<Class>::Instance() +{ + Singleton<Class>& instance = Singleton<Class>::InternalInstance(); + return instance; +} +} // namespace VcoreDPL + +#define IMPLEMENT_SINGLETON(Type) \ + template VcoreDPL::Singleton<Type>&VcoreDPL::Singleton<Type>::InternalInstance(); \ + template Type & VcoreDPL::Singleton<Type>::Instance(); \ + +#endif // DPL_SINGLETON_IMPL_H diff --git a/vcore/src/dpl/core/include/dpl/string.h b/vcore/src/dpl/core/include/dpl/string.h new file mode 100644 index 0000000..68d6a09 --- /dev/null +++ b/vcore/src/dpl/core/include/dpl/string.h @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file string.h + * @author Piotr Marcinkiewicz (p.marcinkiew@samsung.com) + * @version 1.0 + */ +#ifndef DPL_STRING +#define DPL_STRING + +#include <dpl/exception.h> +#include <dpl/char_traits.h> +#include <string> +#include <ostream> +#include <numeric> + +namespace VcoreDPL { +// @brief DPL string +typedef std::basic_string<wchar_t, CharTraits> String; + +// @brief String exception class +class StringException +{ + public: + DECLARE_EXCEPTION_TYPE(VcoreDPL::Exception, Base) + + // @brief Invalid init for UTF8 to UTF32 converter + DECLARE_EXCEPTION_TYPE(Base, IconvInitErrorUTF8ToUTF32) + + // @brief Invalid taStdContainerinit for UTF32 to UTF32 converter + DECLARE_EXCEPTION_TYPE(Base, IconvInitErrorUTF32ToUTF8) + + // @brief Invalid conversion for UTF8 to UTF32 converter + DECLARE_EXCEPTION_TYPE(Base, IconvConvertErrorUTF8ToUTF32) + + // @brief Invalid conversion for UTF8 to UTF32 converter + DECLARE_EXCEPTION_TYPE(Base, IconvConvertErrorUTF32ToUTF8) + + // @brief Invalid ASCII character detected in FromASCII + DECLARE_EXCEPTION_TYPE(Base, InvalidASCIICharacter) + + // @brief Invalid ASCII character detected in FromASCII + DECLARE_EXCEPTION_TYPE(Base, ICUInvalidCharacterFound) +}; + +//!\brief convert ASCII string to VcoreDPL::String +String FromASCIIString(const std::string& aString); + +//!\brief convert UTF32 string to VcoreDPL::String +String FromUTF32String(const std::wstring& aString); + +//@brief Returns String object created from UTF8 string +//@param[in] aString input UTF-8 string +String FromUTF8String(const std::string& aString); + +//@brief Returns String content as std::string +std::string ToUTF8String(const String& aString); + +//@brief Compare two unicode strings +int StringCompare(const String &left, + const String &right, + bool caseInsensitive = false); + +//@brief Splits the string into substrings. +//@param[in] str Input string +//@param[in] delimiters array or string containing a sequence of substring +// delimiters. Can be also a single delimiter character. +//@param[in] it InserterIterator that is used to save the generated substrings. +template<typename StringType, typename Delimiters, typename InserterIterator> +void Tokenize(const StringType& str, + const Delimiters& delimiters, + InserterIterator it, + bool ignoreEmpty = false) +{ + typename StringType::size_type nextSearchStart = 0; + typename StringType::size_type pos; + typename StringType::size_type length; + + while (true) { + pos = str.find_first_of(delimiters, nextSearchStart); + length = + ((pos == StringType::npos) ? str.length() : pos) - nextSearchStart; + + if (!ignoreEmpty || length > 0) { + *it = str.substr(nextSearchStart, length); + it++; + } + + if (pos == StringType::npos) { + return; + } + + nextSearchStart = pos + 1; + } +} + +namespace Utils { + +template<typename T> class ConcatFunc : public std::binary_function<T, T, T> +{ +public: + explicit ConcatFunc(const T & val) : m_delim(val) {} + T operator()(const T & arg1, const T & arg2) const + { + return arg1 + m_delim + arg2; + } +private: + T m_delim; +}; + +} + +template<typename ForwardIterator> +typename ForwardIterator::value_type Join(ForwardIterator begin, ForwardIterator end, typename ForwardIterator::value_type delim) +{ + typedef typename ForwardIterator::value_type value; + if(begin == end) return value(); + Utils::ConcatFunc<value> func(delim); + ForwardIterator init = begin; + return std::accumulate(++begin, end, *init, func); +} + +template<class StringType> void TrimLeft(StringType & obj, typename StringType::const_pointer separators) +{ + obj.erase(0, obj.find_first_not_of(separators)); +} + +template<class StringType> void TrimRight(StringType & obj, typename StringType::const_pointer separators) +{ + obj.erase(obj.find_last_not_of(separators)+1); +} + +template<class StringType> void Trim(StringType & obj, typename StringType::const_pointer separators) +{ + TrimLeft(obj, separators); + TrimRight(obj, separators); +} + + +} //namespace VcoreDPL + +std::ostream& operator<<(std::ostream& aStream, const VcoreDPL::String& aString); + +#endif // DPL_STRING diff --git a/vcore/src/dpl/core/include/dpl/thread.h b/vcore/src/dpl/core/include/dpl/thread.h new file mode 100644 index 0000000..d13740b --- /dev/null +++ b/vcore/src/dpl/core/include/dpl/thread.h @@ -0,0 +1,394 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file thread.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of thread + */ +#ifndef DPL_THREAD_H +#define DPL_THREAD_H + +#include <dpl/waitable_handle_watch_support.h> +#include <dpl/noncopyable.h> +#include <dpl/exception.h> +#include <dpl/assert.h> +#include <boost/optional.hpp> +#include <stdint.h> +#include <cstdlib> +#include <pthread.h> +#include <thread> +#include <vector> +#include <list> +#include <mutex> + +namespace VcoreDPL { +class Thread : + private Noncopyable, + public WaitableHandleWatchSupport +{ + public: + class Exception + { + public: + DECLARE_EXCEPTION_TYPE(VcoreDPL::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, CreateFailed) + DECLARE_EXCEPTION_TYPE(Base, DestroyFailed) + DECLARE_EXCEPTION_TYPE(Base, RunFailed) + DECLARE_EXCEPTION_TYPE(Base, QuitFailed) + DECLARE_EXCEPTION_TYPE(Base, UnmanagedThread) + }; + + typedef void (*EventDeleteProc)(void *event, void *userParam); + typedef void (*EventDispatchProc)(void *event, void *userParam); + + protected: + /** + * Main thread entry + * The method is intended to be overloaded with custom code. + * Default implementation just executes Exec method to process + * all thread exents + */ + virtual int ThreadEntry(); + + /** + * Start processing of thread events + */ + int Exec(); + + private: + struct InternalEvent + { + void *event; + void *userParam; + EventDispatchProc eventDispatchProc; + EventDeleteProc eventDeleteProc; + + InternalEvent(void *eventArg, + void *userParamArg, + EventDispatchProc eventDispatchProcArg, + EventDeleteProc eventDeleteProcArg) : + event(eventArg), + userParam(userParamArg), + eventDispatchProc(eventDispatchProcArg), + eventDeleteProc(eventDeleteProcArg) + {} + }; + + struct InternalTimedEvent : + InternalEvent + { + unsigned long dueTimeMiliseconds; + unsigned long registerTimeMiliseconds; + + InternalTimedEvent(void *eventArg, + void *userParamArg, + unsigned long dueTimeMilisecondsArg, + unsigned long registerTimeMilisecondsArg, + EventDispatchProc eventDispatchProcArg, + EventDeleteProc eventDeleteProcArg) : + InternalEvent(eventArg, + userParamArg, + eventDispatchProcArg, + eventDeleteProcArg), + dueTimeMiliseconds(dueTimeMilisecondsArg), + registerTimeMiliseconds(registerTimeMilisecondsArg) + {} + + bool operator<(const InternalTimedEvent &other) + { + return registerTimeMiliseconds + dueTimeMiliseconds > + other.registerTimeMiliseconds + other.dueTimeMiliseconds; + } + }; + + // Internal event list + typedef std::list<InternalEvent> InternalEventList; + + // Internal timed event list + typedef std::vector<InternalTimedEvent> InternalTimedEventVector; + + // State managment + std::thread m_thread; + volatile bool m_abandon; + volatile bool m_running; + std::mutex m_stateMutex; + WaitableEvent m_quitEvent; + + // Event processing + std::mutex m_eventMutex; + InternalEventList m_eventList; + WaitableEvent m_eventInvoker; + + // Timed events processing + std::mutex m_timedEventMutex; + InternalTimedEventVector m_timedEventVector; + WaitableEvent m_timedEventInvoker; + + // WaitableHandleWatchSupport + virtual Thread *GetInvokerThread(); + virtual void HandleDirectInvoker(); + bool m_directInvoke; + + // Internals + unsigned long GetCurrentTimeMiliseconds() const; + void ProcessEvents(); + void ProcessTimedEvents(); + + static void *StaticThreadEntry(void *param); + + public: + explicit Thread(); + virtual ~Thread(); + + /** + * Run thread. Does nothing if thread is already running + */ + void Run(); + + /** + * Send quit message to thread and wait for its end + * Does nothing is thread is not running + */ + void Quit(); + + /** + * Checks if current thread is main one + * Returns true if it is main program thread, false otherwise + */ + static bool IsMainThread(); + + /** + * Current thread retrieval + * Returns DPL thread handle or NULL if it is main program thread + */ + static Thread *GetCurrentThread(); + + /** + * Low-level event push, usually used only by EventSupport + */ + void PushEvent(void *event, + EventDispatchProc eventDispatchProc, + EventDeleteProc eventDeleteProc, + void *userParam); + + /** + * Low-level timed event push, usually used only by EventSupport + */ + void PushTimedEvent(void *event, + double dueTimeSeconds, + EventDispatchProc eventDispatchProc, + EventDeleteProc eventDeleteProc, + void *userParam); + + /** + * Sleep for a number of seconds + */ + static void Sleep(uint64_t seconds); + + /** + * Sleep for a number of miliseconds + */ + static void MiliSleep(uint64_t miliseconds); + + /** + * Sleep for a number of microseconds + */ + static void MicroSleep(uint64_t microseconds); + + /** + * Sleep for a number of nanoseconds + */ + static void NanoSleep(uint64_t nanoseconds); +}; + +extern bool g_TLSforMainCreated; + +// In case of using TLV in main thread, pthread_exit(NULL) has to be called in +// this thread explicitly. +// On the other hand, possibly, because of the kernel bug, there exist +// a problem, if any other thread than main exist during pthread_exit call +// (process can become non-responsive) +// TODO further investigation is required. +template<typename Type> +class ThreadLocalVariable : + public Noncopyable +{ + public: + typedef Type ValueType; + + class Exception + { + public: + DECLARE_EXCEPTION_TYPE(VcoreDPL::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, NullReference) + DECLARE_EXCEPTION_TYPE(Base, KeyCreateFailed) + }; + + private: + pthread_key_t m_key; + + struct ManagedValue + { + ValueType value; + boost::optional<pthread_key_t> guardKey; + }; + + static void MainThreadExitClean() + { + // There is a possible bug in kernel. If this function is called + // before ALL threads are closed, process will hang! + // Because of that, by default this function has to be called in well + // known "threads state". + + // pthread_exit(NULL); + } + + static void InternalDestroy(void *specific) + { + // Destroy underlying type + ManagedValue *instance = static_cast<ManagedValue *>(specific); + if (!instance->guardKey) { + delete instance; + } else { + int result = pthread_setspecific(*(instance->guardKey), instance); + + Assert(result == 0 && + "Failed to set thread local variable"); + } + } + + Type &Reference(bool allowInstantiate = false) + { + ManagedValue *instance = + static_cast<ManagedValue *>(pthread_getspecific(m_key)); + + if (!instance) { + // Check if it is allowed to instantiate + if (!allowInstantiate) { + Throw(typename Exception::NullReference); + } + + // checking, if specific data is created for Main thread + // If yes, pthread_exit(NULL) is required + if (!g_TLSforMainCreated) { + if (Thread::IsMainThread()) { + g_TLSforMainCreated = true; + atexit(&MainThreadExitClean); + } + } + + // Need to instantiate underlying type + instance = new ManagedValue(); + + int result = pthread_setspecific(m_key, instance); + + Assert(result == 0 && + "Failed to set thread local variable"); + } + + return instance->value; + } + + public: + ThreadLocalVariable() + { + int result = pthread_key_create(&m_key, &InternalDestroy); + if (result != 0) { + ThrowMsg(typename Exception::KeyCreateFailed, + "Failed to allocate thread local variable: " << result); + } + } + + ~ThreadLocalVariable() + { + pthread_key_delete(m_key); + } + + Type &operator=(const Type &other) + { + Type &reference = Reference(true); + reference = other; + return reference; + } + + bool IsNull() const + { + return pthread_getspecific(m_key) == NULL; + } + + Type& operator*() + { + return Reference(); + } + + const Type& operator*() const + { + return Reference(); + } + + const Type* operator->() const + { + return &Reference(); + } + + Type* operator->() + { + return &Reference(); + } + + bool operator!() const + { + return IsNull(); + } + + void Reset() + { + ManagedValue *specific = + static_cast<ManagedValue *>(pthread_getspecific(m_key)); + + if (!specific) { + return; + } + + // TODO Should be an assert? is it developers fault to Reset Guarded + // value? + specific->guardKey = boost::optional<pthread_key_t>(); + + InternalDestroy(specific); + + int result = pthread_setspecific(m_key, NULL); + + Assert(result == 0 && + "Failed to reset thread local variable"); + } + + // GuardValue(true) allows to defer destroy (by pthread internal + // functionality) thread specific value until GuardValue(false) will be + // called. + void GuardValue(bool guard) + { + ManagedValue *instance = + static_cast<ManagedValue *>(pthread_getspecific(m_key)); + + Assert(instance && "Failed to get the value"); + + instance->guardKey = guard ? m_key : boost::optional<pthread_key_t>(); + } +}; +} // namespace VcoreDPL + +#endif // DPL_THREAD_H diff --git a/vcore/src/dpl/core/include/dpl/type_list.h b/vcore/src/dpl/core/include/dpl/type_list.h new file mode 100644 index 0000000..e28172d --- /dev/null +++ b/vcore/src/dpl/core/include/dpl/type_list.h @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file type_list.h + * @author Bartosz Janiak (b.janiak@samsung.com) + * @version 1.0 + * @brief Generic type list template + */ +#ifndef DPL_TYPE_LIST_H +#define DPL_TYPE_LIST_H + +#include <cstddef> + +namespace VcoreDPL { +class TypeListGuard +{ + public: + template<size_t Index> + struct Element + { + struct ERROR_TypeListElementIndexIsOutOfBounds; + typedef ERROR_TypeListElementIndexIsOutOfBounds Type; + }; + + static const size_t Size = 0; +}; + +template<typename HeadType, typename TailType> +class TypeList +{ + private: + class DummyClass + {}; + + template<typename List, size_t Enum> + struct TypeCounter : public TypeCounter<typename List::Tail, Enum + 1> + {}; + + template<size_t Enum> + struct TypeCounter<TypeListGuard, Enum> + { + static const size_t Size = Enum; + }; + + public: + typedef TailType Tail; + typedef HeadType Head; + typedef TypeList<HeadType, TailType> ThisType; + + template<size_t Index, typename DummyType = DummyClass> + struct Element + { + typedef typename TailType::template Element<Index - 1>::Type Type; + }; + + template<typename DummyType> + struct Element<0, DummyType> + { + typedef HeadType Type; + }; + + template<typename Type, typename DummyType = DummyClass> + struct Contains + { + typedef typename TailType::template Contains<Type>::Yes Yes; + }; + + template<typename DummyType> + struct Contains<HeadType, DummyType> + { + typedef int Yes; + }; + + static const size_t Size = TypeCounter<ThisType, 0>::Size; +}; + +template<typename T1 = TypeListGuard, typename T2 = TypeListGuard, + typename T3 = TypeListGuard, typename T4 = TypeListGuard, + typename T5 = TypeListGuard, typename T6 = TypeListGuard, + typename T7 = TypeListGuard, typename T8 = TypeListGuard, + typename T9 = TypeListGuard, typename T10 = TypeListGuard, + typename T11 = TypeListGuard, typename T12 = TypeListGuard, + typename T13 = TypeListGuard, typename T14 = TypeListGuard, + typename T15 = TypeListGuard, typename T16 = TypeListGuard, + typename T17 = TypeListGuard, typename T18 = TypeListGuard, + typename T19 = TypeListGuard, typename T20 = TypeListGuard, + typename T21 = TypeListGuard, typename T22 = TypeListGuard, + typename T23 = TypeListGuard, typename T24 = TypeListGuard, + typename T25 = TypeListGuard, typename T26 = TypeListGuard, + typename T27 = TypeListGuard, typename T28 = TypeListGuard, + typename T29 = TypeListGuard, typename T30 = TypeListGuard, + typename T31 = TypeListGuard, typename T32 = TypeListGuard, + typename T33 = TypeListGuard, typename T34 = TypeListGuard, + typename T35 = TypeListGuard, typename T36 = TypeListGuard, + typename T37 = TypeListGuard, typename T38 = TypeListGuard, + typename T39 = TypeListGuard, typename T40 = TypeListGuard, + typename T41 = TypeListGuard, typename T42 = TypeListGuard, + typename T43 = TypeListGuard, typename T44 = TypeListGuard, + typename T45 = TypeListGuard, typename T46 = TypeListGuard, + typename T47 = TypeListGuard, typename T48 = TypeListGuard, + typename T49 = TypeListGuard, typename T50 = TypeListGuard, + typename T51 = TypeListGuard, typename T52 = TypeListGuard, + typename T53 = TypeListGuard, typename T54 = TypeListGuard, + typename T55 = TypeListGuard, typename T56 = TypeListGuard, + typename T57 = TypeListGuard, typename T58 = TypeListGuard, + typename T59 = TypeListGuard, typename T60 = TypeListGuard, + typename T61 = TypeListGuard, typename T62 = TypeListGuard, + typename T63 = TypeListGuard, typename T64 = TypeListGuard> +struct TypeListDecl +{ + typedef TypeList<T1, + typename TypeListDecl< + T2, T3, T4, T5, T6, T7, T8, + T9, T10, T11, T12, T13, T14, T15, + T16, T17, T18, T19, T20, T21, T22, + T23, T24, T25, T26, T27, T28, T29, + T30, T31, T32, T33, T34, T35, T36, + T37, T38, T39, T40, T41, T42, T43, + T44, T45, T46, T47, T48, T49, T50, + T51, T52, T53, T54, T55, T56, T57, + T58, T59, T60, T61, T62, T63, T64>::Type> Type; +}; + +template<> +struct TypeListDecl<TypeListGuard, TypeListGuard, TypeListGuard, TypeListGuard, + TypeListGuard, TypeListGuard, TypeListGuard, TypeListGuard, + TypeListGuard, TypeListGuard, TypeListGuard, TypeListGuard, + TypeListGuard, TypeListGuard, TypeListGuard, TypeListGuard, + TypeListGuard, TypeListGuard, TypeListGuard, TypeListGuard, + TypeListGuard, TypeListGuard, TypeListGuard, TypeListGuard, + TypeListGuard, TypeListGuard, TypeListGuard, TypeListGuard, + TypeListGuard, TypeListGuard, TypeListGuard, TypeListGuard, + TypeListGuard, TypeListGuard, TypeListGuard, TypeListGuard, + TypeListGuard, TypeListGuard, TypeListGuard, TypeListGuard, + TypeListGuard, TypeListGuard, TypeListGuard, TypeListGuard, + TypeListGuard, TypeListGuard, TypeListGuard, TypeListGuard, + TypeListGuard, TypeListGuard, TypeListGuard, TypeListGuard, + TypeListGuard, TypeListGuard, TypeListGuard, TypeListGuard, + TypeListGuard, TypeListGuard, TypeListGuard, TypeListGuard, + TypeListGuard, TypeListGuard, TypeListGuard, TypeListGuard> +{ + typedef TypeListGuard Type; +}; +} // namespace VcoreDPL + +#endif // DPL_TYPE_LIST_H diff --git a/vcore/src/dpl/core/include/dpl/waitable_event.h b/vcore/src/dpl/core/include/dpl/waitable_event.h new file mode 100644 index 0000000..b6305b0 --- /dev/null +++ b/vcore/src/dpl/core/include/dpl/waitable_event.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file waitable_event.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of waitable event + */ +#ifndef DPL_WAITABLE_EVENT_H +#define DPL_WAITABLE_EVENT_H + +#include <dpl/waitable_handle.h> +#include <dpl/noncopyable.h> +#include <dpl/exception.h> +#include <vector> + +namespace VcoreDPL { +class WaitableEvent : + private Noncopyable +{ + public: + class Exception + { + public: + DECLARE_EXCEPTION_TYPE(VcoreDPL::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, CreateFailed) + DECLARE_EXCEPTION_TYPE(Base, DestroyFailed) + DECLARE_EXCEPTION_TYPE(Base, SignalFailed) + DECLARE_EXCEPTION_TYPE(Base, ResetFailed) + }; + + private: + int m_pipe[2]; + + public: + WaitableEvent(); + virtual ~WaitableEvent(); + + WaitableHandle GetHandle() const; + + void Signal() const; + void Reset() const; +}; +} // namespace VcoreDPL + +#endif // DPL_WAITABLE_EVENT_H diff --git a/vcore/src/dpl/core/include/dpl/waitable_handle.h b/vcore/src/dpl/core/include/dpl/waitable_handle.h new file mode 100644 index 0000000..5ffd76c --- /dev/null +++ b/vcore/src/dpl/core/include/dpl/waitable_handle.h @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file waitable_handle.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the header file of waitable handle + */ +#ifndef DPL_WAITABLE_HANDLE_H +#define DPL_WAITABLE_HANDLE_H + +#include <dpl/noncopyable.h> +#include <dpl/exception.h> +#include <vector> + +namespace VcoreDPL { +/** + * Waitable unix wait handle definition + */ +typedef int WaitableHandle; + +/** + * Waitable handle list + */ +typedef std::vector<WaitableHandle> WaitableHandleList; + +/** + * Wait mode + */ +class WaitMode +{ + public: + enum Type + { + Read, ///< Wait for readability state changes + Write ///< Wait for writability state changes + }; +}; + +/** + * Waitable handle list ex + */ +typedef std::vector<std::pair<WaitableHandle, + WaitMode::Type> > WaitableHandleListEx; + +/** + * Waitable handle index list + */ +typedef std::vector<size_t> WaitableHandleIndexList; + +/** + * Wait exceptions + */ +DECLARE_EXCEPTION_TYPE(VcoreDPL::Exception, WaitFailed) + +/** + * Wait for single handle readability + * Convience function. + * + * @return Signaled waitable handle index list + * @throw WaitFailed Fatal error occurred while waiting for signal + */ +WaitableHandleIndexList WaitForSingleHandle( + WaitableHandle handle, + unsigned long miliseconds = + 0xFFFFFFFF); + +/** + * Wait for single handle + * Convience function. + * + * @return Signaled waitable handle index list + * @throw WaitFailed Fatal error occurred while waiting for signal + */ +WaitableHandleIndexList WaitForSingleHandle( + WaitableHandle handle, + WaitMode::Type mode, + unsigned long miliseconds = + 0xFFFFFFFF); + +/** + * Wait for multiple handles readability + * + * @return Signaled waitable handle index list + * @throw WaitFailed Fatal error occurred while waiting for signal + */ +WaitableHandleIndexList WaitForMultipleHandles( + const WaitableHandleList &handleList, + unsigned long miliseconds = 0xFFFFFFFF); + +/** + * Wait for multiple handles readability + * + * @return Signaled waitable handle index list + * @throw WaitFailed Fatal error occurred while waiting for signal + */ +WaitableHandleIndexList WaitForMultipleHandles( + const WaitableHandleListEx &handleListEx, + unsigned long miliseconds = 0xFFFFFFFF); +} // namespace VcoreDPL + +#endif // DPL_WAITABLE_HANDLE_H diff --git a/vcore/src/dpl/core/include/dpl/waitable_handle_watch_support.h b/vcore/src/dpl/core/include/dpl/waitable_handle_watch_support.h new file mode 100644 index 0000000..4f3f142 --- /dev/null +++ b/vcore/src/dpl/core/include/dpl/waitable_handle_watch_support.h @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file waitable_handle_watch_support.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of waitable handle watch + * support + */ +#ifndef DPL_WAITABLE_HANDLE_WATCH_SUPPORT_H +#define DPL_WAITABLE_HANDLE_WATCH_SUPPORT_H + +#include <dpl/waitable_event.h> +#include <dpl/waitable_handle.h> +#include <dpl/exception.h> +#include <list> +#include <map> +#include <mutex> + +namespace VcoreDPL { +class Thread; + +class WaitableHandleWatchSupport +{ + public: + class WaitableHandleListener + { + public: + virtual ~WaitableHandleListener() {} + + virtual void OnWaitableHandleEvent(WaitableHandle waitableHandle, + WaitMode::Type mode) = 0; + }; + + protected: + // Invoker waitable handle + // Signaled by Add/Remove methods + // After being signaled one must call Handle invoke to reset invoker + WaitableHandle WaitableInvokerHandle() const; + + // Waitable handle ex list + WaitableHandleListEx WaitableWatcherHandles() const; + + // Perform actions for signaled waitable handle + // Called in execution context, after + void HandleWatcher(WaitableHandle waitableHandle, WaitMode::Type mode); + + // Perform actions after invoker was signaled + void InvokerFinished(); + + // Get invoker context + virtual Thread *GetInvokerThread() = 0; + + // Invoke direct invoker + virtual void HandleDirectInvoker() = 0; + + private: + // Waitable event watchers + struct WaitableHandleWatcher + { + WaitableHandleListener *listener; + WaitMode::Type mode; + + WaitableHandleWatcher(WaitableHandleListener *l, WaitMode::Type m) : + listener(l), + mode(m) + {} + }; + + typedef std::list<WaitableHandleWatcher> WaitableHandleListenerList; + + struct WaitableHandleWatchers + { + WaitableHandleListenerList listeners; + size_t readListenersCount; + size_t writeListenersCount; + + WaitableHandleWatchers() : + readListenersCount(0), + writeListenersCount(0) + {} + }; + + typedef std::map<WaitableHandle, + WaitableHandleWatchers> WaitableHandleWatchersMap; + + // Waitable event watch support + mutable std::recursive_mutex m_watchersMutex; + WaitableHandleWatchersMap m_watchersMap; + WaitableEvent m_watchersInvoker; + WaitableEvent m_watchersInvokerCommit; + + // Invoke call + void CommitInvoker(); + + public: + /** + * Constructor + */ + explicit WaitableHandleWatchSupport(); + + /** + * Destructor + */ + virtual ~WaitableHandleWatchSupport(); + + /** + * Adds listener for specific waitable event + * + * @param[in] listener Listener to attach + * @param[in] waitableHandle Waitable handle to listen for changes + * @param[in] mode Type of changes to listen to + * @return none + * @see WaitMode::Type + */ + void AddWaitableHandleWatch(WaitableHandleListener *listener, + WaitableHandle waitableHandle, + WaitMode::Type mode); + + /** + * Remove listener for specific waitable event + * + * @param[in] listener Listener to detach + * @param[in] waitableHandle Waitable handle to unlisten for changes + * @param[in] mode Type of changes to unlisten to + * @return none + * @see WaitMode::Type + */ + void RemoveWaitableHandleWatch(WaitableHandleListener *listener, + WaitableHandle waitableHandle, + WaitMode::Type mode); + +}; +} // namespace VcoreDPL + +#endif // DPL_WAITABLE_HANDLE_WATCH_SUPPORT_H diff --git a/vcore/src/dpl/core/include/dpl/workaround.h b/vcore/src/dpl/core/include/dpl/workaround.h new file mode 100644 index 0000000..19c26ef --- /dev/null +++ b/vcore/src/dpl/core/include/dpl/workaround.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file workaround.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the header file of workaround + */ +#ifndef DPL_WORKAROUND_H +#define DPL_WORKAROUND_H + +/** + * Define following macro to track invalid waitable handles + * in WaitForSingle/WaitForMultiple functions + */ +#define DPL_ENABLE_WAITABLE_HANDLE_BADF_CHECK + +/** + * Define following macro to enable workaround for problem + * with GLIB loop integration and EBADF error handling + */ +#define DPL_ENABLE_GLIB_LOOP_INTEGRATION_WORKAROUND + +/** + * Define following macro to enable workaround for problem + * with invalid conversions in htons/ntohs macros + */ +#define DPL_ENABLE_HTONS_NTOHS_I386_WORKAROUND + +#endif // DPL_WORKAROUND_H diff --git a/vcore/src/dpl/core/src/assert.cpp b/vcore/src/dpl/core/src/assert.cpp new file mode 100644 index 0000000..2e55877 --- /dev/null +++ b/vcore/src/dpl/core/src/assert.cpp @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file assert.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of assert + */ +#include <cstdlib> +#include <sstream> +#include <stddef.h> +#include <dpl/assert.h> +#include <dpl/colors.h> +#include <dpl/exception.h> +#include <dpl/log/vcore_log.h> + +namespace VcoreDPL { +void AssertProc(const char *condition, + const char *file, + int line, + const char *function) +{ + +#define INTERNAL_LOG(message) \ +do { \ + std::ostringstream platformLog; \ + platformLog << message; \ + VcoreLogD("%s", platformLog.str().c_str()); \ +} while (0) + + // Try to log failed assertion to log system + Try { + INTERNAL_LOG("########################################################################"); + INTERNAL_LOG("### DPL assertion failed! ###"); + INTERNAL_LOG("########################################################################"); + INTERNAL_LOG("### Condition: " << condition); + INTERNAL_LOG("### File: " << file); + INTERNAL_LOG("### Line: " << line); + INTERNAL_LOG("### Function: " << function); + INTERNAL_LOG("########################################################################"); + } catch (Exception) { + // Just ignore possible double errors + } + + // Fail with c-library abort + abort(); +} +} // namespace VcoreDPL diff --git a/vcore/src/dpl/core/src/binary_queue.cpp b/vcore/src/dpl/core/src/binary_queue.cpp new file mode 100644 index 0000000..0b39a22 --- /dev/null +++ b/vcore/src/dpl/core/src/binary_queue.cpp @@ -0,0 +1,312 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file binary_queue.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of binary queue + */ +#include <stddef.h> +#include <dpl/binary_queue.h> +#include <dpl/assert.h> +#include <dpl/scoped_free.h> +#include <algorithm> +#include <malloc.h> +#include <cstring> +#include <new> + +namespace VcoreDPL { +BinaryQueue::BinaryQueue() : + m_size(0) +{} + +BinaryQueue::BinaryQueue(const BinaryQueue &other) : + m_size(0) +{ + AppendCopyFrom(other); +} + +BinaryQueue::~BinaryQueue() +{ + // Remove all remainig buckets + Clear(); +} + +BinaryQueue &BinaryQueue::operator=(const BinaryQueue &other) +{ + if (this != &other) { + Clear(); + AppendCopyFrom(other); + } + + return *this; +} + +void BinaryQueue::AppendCopyFrom(const BinaryQueue &other) +{ + // To speed things up, always copy as one bucket + void *bufferCopy = malloc(other.m_size); + + if (bufferCopy == NULL) { + throw std::bad_alloc(); + } + + try { + other.Flatten(bufferCopy, other.m_size); + AppendUnmanaged(bufferCopy, other.m_size, &BufferDeleterFree, NULL); + } catch (const std::bad_alloc &) { + // Free allocated memory + free(bufferCopy); + throw; + } +} + +void BinaryQueue::AppendMoveFrom(BinaryQueue &other) +{ + // Copy all buckets + std::copy(other.m_buckets.begin(), + other.m_buckets.end(), std::back_inserter(m_buckets)); + m_size += other.m_size; + + // Clear other, but do not free memory + other.m_buckets.clear(); + other.m_size = 0; +} + +void BinaryQueue::AppendCopyTo(BinaryQueue &other) const +{ + other.AppendCopyFrom(*this); +} + +void BinaryQueue::AppendMoveTo(BinaryQueue &other) +{ + other.AppendMoveFrom(*this); +} + +void BinaryQueue::Clear() +{ + std::for_each(m_buckets.begin(), m_buckets.end(), &DeleteBucket); + m_buckets.clear(); + m_size = 0; +} + +void BinaryQueue::AppendCopy(const void* buffer, size_t bufferSize) +{ + // Create data copy with malloc/free + void *bufferCopy = malloc(bufferSize); + + // Check if allocation succeded + if (bufferCopy == NULL) { + throw std::bad_alloc(); + } + + // Copy user data + memcpy(bufferCopy, buffer, bufferSize); + + try { + // Try to append new bucket + AppendUnmanaged(bufferCopy, bufferSize, &BufferDeleterFree, NULL); + } catch (const std::bad_alloc &) { + // Free allocated memory + free(bufferCopy); + throw; + } +} + +void BinaryQueue::AppendUnmanaged(const void* buffer, + size_t bufferSize, + BufferDeleter deleter, + void* userParam) +{ + // Do not attach empty buckets + if (bufferSize == 0) { + deleter(buffer, bufferSize, userParam); + return; + } + + // Just add new bucket with selected deleter + m_buckets.push_back(new Bucket(buffer, bufferSize, deleter, userParam)); + + // Increase total queue size + m_size += bufferSize; +} + +size_t BinaryQueue::Size() const +{ + return m_size; +} + +bool BinaryQueue::Empty() const +{ + return m_size == 0; +} + +void BinaryQueue::Consume(size_t size) +{ + // Check parameters + if (size > m_size) { + Throw(Exception::OutOfData); + } + + size_t bytesLeft = size; + + // Consume data and/or remove buckets + while (bytesLeft > 0) { + // Get consume size + size_t count = std::min(bytesLeft, m_buckets.front()->left); + + m_buckets.front()->ptr = + static_cast<const char *>(m_buckets.front()->ptr) + count; + m_buckets.front()->left -= count; + bytesLeft -= count; + m_size -= count; + + if (m_buckets.front()->left == 0) { + DeleteBucket(m_buckets.front()); + m_buckets.pop_front(); + } + } +} + +void BinaryQueue::Flatten(void *buffer, size_t bufferSize) const +{ + // Check parameters + if (bufferSize == 0) { + return; + } + + if (bufferSize > m_size) { + Throw(Exception::OutOfData); + } + + size_t bytesLeft = bufferSize; + void *ptr = buffer; + BucketList::const_iterator bucketIterator = m_buckets.begin(); + Assert(m_buckets.end() != bucketIterator); + + // Flatten data + while (bytesLeft > 0) { + // Get consume size + size_t count = std::min(bytesLeft, (*bucketIterator)->left); + + // Copy data to user pointer + memcpy(ptr, (*bucketIterator)->ptr, count); + + // Update flattened bytes count + bytesLeft -= count; + ptr = static_cast<char *>(ptr) + count; + + // Take next bucket + ++bucketIterator; + } +} + +void BinaryQueue::FlattenConsume(void *buffer, size_t bufferSize) +{ + // FIXME: Optimize + Flatten(buffer, bufferSize); + Consume(bufferSize); +} + +void BinaryQueue::DeleteBucket(BinaryQueue::Bucket *bucket) +{ + delete bucket; +} + +void BinaryQueue::BufferDeleterFree(const void* data, + size_t dataSize, + void* userParam) +{ + (void)dataSize; + (void)userParam; + + // Default free deleter + free(const_cast<void *>(data)); +} + +BinaryQueue::Bucket::Bucket(const void* data, + size_t dataSize, + BufferDeleter dataDeleter, + void* userParam) : + buffer(data), + ptr(data), + size(dataSize), + left(dataSize), + deleter(dataDeleter), + param(userParam) +{ + Assert(data != NULL); + Assert(deleter != NULL); +} + +BinaryQueue::Bucket::~Bucket() +{ + // Invoke deleter on bucket data + deleter(buffer, size, param); +} + +BinaryQueue::BucketVisitor::~BucketVisitor() +{} + +BinaryQueue::BucketVisitorCall::BucketVisitorCall(BucketVisitor *visitor) : + m_visitor(visitor) +{} + +BinaryQueue::BucketVisitorCall::~BucketVisitorCall() +{} + +void BinaryQueue::BucketVisitorCall::operator()(Bucket *bucket) const +{ + m_visitor->OnVisitBucket(bucket->ptr, bucket->left); +} + +void BinaryQueue::VisitBuckets(BucketVisitor *visitor) const +{ + Assert(visitor != NULL); + + // Visit all buckets + std::for_each(m_buckets.begin(), m_buckets.end(), BucketVisitorCall(visitor)); +} + +BinaryQueueAutoPtr BinaryQueue::Read(size_t size) +{ + // Simulate input stream + size_t available = std::min(size, m_size); + + ScopedFree<void> bufferCopy(malloc(available)); + + if (!bufferCopy) { + throw std::bad_alloc(); + } + + BinaryQueueAutoPtr result(new BinaryQueue()); + + Flatten(bufferCopy.Get(), available); + result->AppendUnmanaged( + bufferCopy.Get(), available, &BufferDeleterFree, NULL); + bufferCopy.Release(); + Consume(available); + + return result; +} + +size_t BinaryQueue::Write(const BinaryQueue &buffer, size_t bufferSize) +{ + // Simulate output stream + AppendCopyFrom(buffer); + return bufferSize; +} +} // namespace VcoreDPL diff --git a/vcore/src/dpl/core/src/char_traits.cpp b/vcore/src/dpl/core/src/char_traits.cpp new file mode 100644 index 0000000..32b9197 --- /dev/null +++ b/vcore/src/dpl/core/src/char_traits.cpp @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file char_traits.cpp + * @author Piotr Marcinkiewicz (p.marcinkiew@samsung.com) + * @version 1.0 + * @biref Char traits are used to create basic_string extended with + * additional features + * Current char traits could be extended in feature to boost + * performance + */ +#include <stddef.h> +#include <dpl/char_traits.h> + +// +// Note: +// +// The file here is left blank to enable precompilation +// of templates in corresponding header file. +// Do not remove this file. +// diff --git a/vcore/src/dpl/core/src/colors.cpp b/vcore/src/dpl/core/src/colors.cpp new file mode 100644 index 0000000..e918453 --- /dev/null +++ b/vcore/src/dpl/core/src/colors.cpp @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file colors.cpp + * @author Lukasz Wrzosek (l.wrzosek@samsung.com) + * @version 1.0 + * @brief Some constants with definition of colors for Console + * and html output + */ +#include <stddef.h> +#include <dpl/colors.h> + +namespace VcoreDPL { +namespace Colors { +namespace Text { +const char* BOLD_GREEN_BEGIN = "\033[1;32m"; +const char* BOLD_GREEN_END = "\033[m"; +const char* RED_BEGIN = "\033[0;31m"; +const char* RED_END = "\033[m"; +const char* PURPLE_BEGIN = "\033[0;35m"; +const char* PURPLE_END = "\033[m"; +const char* GREEN_BEGIN = "\033[0;32m"; +const char* GREEN_END = "\033[m"; +const char* CYAN_BEGIN = "\033[0;36m"; +const char* CYAN_END = "\033[m"; +const char* BOLD_RED_BEGIN = "\033[1;31m"; +const char* BOLD_RED_END = "\033[m"; +const char* BOLD_YELLOW_BEGIN = "\033[1;33m"; +const char* BOLD_YELLOW_END = "\033[m"; +const char* BOLD_GOLD_BEGIN = "\033[0;33m"; +const char* BOLD_GOLD_END = "\033[m"; +const char* BOLD_WHITE_BEGIN = "\033[1;37m"; +const char* BOLD_WHITE_END = "\033[m"; +} //namespace Text + +namespace Html { +const char* BOLD_GREEN_BEGIN = "<font color=\"green\"><b>"; +const char* BOLD_GREEN_END = "</b></font>"; +const char* PURPLE_BEGIN = "<font color=\"purple\"><b>"; +const char* PURPLE_END = "</b></font>"; +const char* RED_BEGIN = "<font color=\"red\"><b>"; +const char* RED_END = "</b></font>"; +const char* GREEN_BEGIN = "<font color=\"green\">"; +const char* GREEN_END = "</font>"; +const char* CYAN_BEGIN = "<font color=\"cyan\">"; +const char* CYAN_END = "</font>"; +const char* BOLD_RED_BEGIN = "<font color=\"red\"><b>"; +const char* BOLD_RED_END = "</b></font>"; +const char* BOLD_YELLOW_BEGIN = "<font color=\"yellow\"><b>"; +const char* BOLD_YELLOW_END = "</b></font>"; +const char* BOLD_GOLD_BEGIN = "<font color=\"gold\"><b>"; +const char* BOLD_GOLD_END = "</b></font>"; +const char* BOLD_WHITE_BEGIN = "<font color=\"white\"><b>"; +const char* BOLD_WHITE_END = "</b></font>"; +} //namespace Html +} //namespace Colors +} //namespace VcoreDPL diff --git a/vcore/src/dpl/core/src/errno_string.cpp b/vcore/src/dpl/core/src/errno_string.cpp new file mode 100644 index 0000000..c4efc4d --- /dev/null +++ b/vcore/src/dpl/core/src/errno_string.cpp @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file errno_string.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of errno string + */ +#include <stddef.h> +#include <dpl/errno_string.h> +#include <dpl/assert.h> +#include <dpl/exception.h> +#include <dpl/assert.h> +#include <dpl/scoped_free.h> +#include <string> +#include <cstddef> +#include <cstring> +#include <malloc.h> +#include <cerrno> +#include <stdexcept> + +namespace VcoreDPL { +namespace // anonymous +{ +const size_t DEFAULT_ERRNO_STRING_SIZE = 32; +} // namespace anonymous + +std::string GetErrnoString(int error) +{ + size_t size = DEFAULT_ERRNO_STRING_SIZE; + char *buffer = NULL; + + for (;;) { + // Add one extra characted for end of string null value + char *newBuffer = static_cast<char *>(::realloc(buffer, size + 1)); + + if (!newBuffer) { + // Failed to realloc + ::free(buffer); + throw std::bad_alloc(); + } + + // Setup reallocated buffer + buffer = newBuffer; + ::memset(buffer, 0, size + 1); + + // Try to retrieve error string +#if (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && !_GNU_SOURCE + // The XSI-compliant version of strerror_r() is provided if: + int result = ::strerror_r(error, buffer, size); + + if (result == 0) { + ScopedFree<char> scopedBufferFree(buffer); + return std::string(buffer); + } +#else + errno = 0; + + // Otherwise, the GNU-specific version is provided. + char *result = ::strerror_r(error, buffer, size); + + if (result != NULL) { + ScopedFree<char> scopedBufferFree(buffer); + return std::string(result); + } +#endif + + // Interpret errors + switch (errno) { + case EINVAL: + // We got an invalid errno value + ::free(buffer); + ThrowMsg(InvalidErrnoValue, "Invalid errno value: " << error); + + case ERANGE: + // Incease buffer size and retry + size <<= 1; + continue; + + default: + AssertMsg(0, "Invalid errno value after call to strerror_r!"); + } + } +} +} // namespace VcoreDPL diff --git a/vcore/src/dpl/core/src/exception.cpp b/vcore/src/dpl/core/src/exception.cpp new file mode 100644 index 0000000..16a3c25 --- /dev/null +++ b/vcore/src/dpl/core/src/exception.cpp @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file exception.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation of exception system + */ +#include <stddef.h> +#include <dpl/exception.h> +#include <dpl/log/vcore_log.h> +#include <cstdio> + +namespace VcoreDPL { +Exception* Exception::m_lastException = NULL; +unsigned int Exception::m_exceptionCount = 0; +void (*Exception::m_terminateHandler)() = NULL; + +void LogUnhandledException(const std::string &str) +{ + // Logging to dlog + VcoreLogD("%s", str.c_str()); +} + +void LogUnhandledException(const std::string &str, + const char *filename, + int line, + const char *function) +{ + // Logging to dlog + VcoreLogE("Exception occured on file[%s] line[%d] function[%s] msg[%s]", + filename, line, function, str.c_str()); +} +} // namespace VcoreDPL diff --git a/vcore/src/dpl/core/src/file_input.cpp b/vcore/src/dpl/core/src/file_input.cpp new file mode 100644 index 0000000..18bef68 --- /dev/null +++ b/vcore/src/dpl/core/src/file_input.cpp @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file file_input.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of named input pipe + */ +#include <stddef.h> +#include <dpl/file_input.h> +#include <dpl/binary_queue.h> +#include <dpl/log/log.h> +#include <unistd.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <errno.h> + +namespace VcoreDPL { +namespace // anonymous +{ +const size_t DEFAULT_READ_BUFFER_SIZE = 4096; +} // namespace anonymous + +FileInput::FileInput() : + m_fd(-1) +{} + +FileInput::FileInput(const std::string& fileName) : + m_fd(-1) +{ + Open(fileName); +} + +FileInput::~FileInput() +{ + Close(); +} + +void FileInput::Open(const std::string& fileName) +{ + // Open non-blocking + int fd = TEMP_FAILURE_RETRY(open(fileName.c_str(), O_RDONLY | O_NONBLOCK)); + + // Throw an exception if an error occurred + if (fd == -1) { + ThrowMsg(Exception::OpenFailed, fileName); + } + + // Close if any existing + Close(); + + // Save new descriptor + m_fd = fd; + + LogPedantic("Opened file: " << fileName); +} + +void FileInput::Close() +{ + if (m_fd == -1) { + return; + } + + if (TEMP_FAILURE_RETRY(close(m_fd)) == -1) { + Throw(Exception::CloseFailed); + } + + m_fd = -1; + + LogPedantic("Closed file"); +} + +BinaryQueueAutoPtr FileInput::Read(size_t size) +{ + size_t bytesToRead = size > + DEFAULT_READ_BUFFER_SIZE ? DEFAULT_READ_BUFFER_SIZE : size; + + // Malloc default read buffer size + // It is unmanaged, so it can be then attached directly to binary queue + void *buffer = malloc(bytesToRead); + + if (buffer == NULL) { + throw std::bad_alloc(); + } + + LogPedantic("Trying to read " << bytesToRead << " bytes"); + + ssize_t result = TEMP_FAILURE_RETRY(read(m_fd, buffer, bytesToRead)); + + LogPedantic("Read " << result << " bytes from file"); + + if (result > 0) { + // Succedded to read socket data + BinaryQueueAutoPtr binaryQueue(new BinaryQueue()); + + // Append unmanaged memory + binaryQueue->AppendUnmanaged(buffer, + result, + &BinaryQueue::BufferDeleterFree, + NULL); + + // Return buffer + return binaryQueue; + } else if (result == 0) { + // Socket was gracefuly closed + free(buffer); + + // Return empty buffer + return BinaryQueueAutoPtr(new BinaryQueue()); + } else { + // Must first save errno value, because it may be altered + int lastErrno = errno; + + // Free buffer + free(buffer); + + // Interpret error result + (void)lastErrno; + + // FIXME: Handle specific errno + Throw(AbstractInput::Exception::ReadFailed); + } +} + +WaitableHandle FileInput::WaitableReadHandle() const +{ + return static_cast<WaitableHandle>(m_fd); +} +} // namespace VcoreDPL diff --git a/vcore/src/dpl/core/src/noncopyable.cpp b/vcore/src/dpl/core/src/noncopyable.cpp new file mode 100644 index 0000000..74fc9af --- /dev/null +++ b/vcore/src/dpl/core/src/noncopyable.cpp @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file noncopyable.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of noncopyable + */ +#include <stddef.h> +#include <dpl/noncopyable.h> + +namespace VcoreDPL { +Noncopyable::Noncopyable() +{} + +Noncopyable::~Noncopyable() +{} +} // namespace VcoreDPL diff --git a/vcore/src/dpl/core/src/singleton.cpp b/vcore/src/dpl/core/src/singleton.cpp new file mode 100644 index 0000000..a76e8ac --- /dev/null +++ b/vcore/src/dpl/core/src/singleton.cpp @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file generic_event.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of singleton + */ +#include <stddef.h> +#include <dpl/singleton.h> + +// +// Note: +// +// The file here is left blank to enable precompilation +// of templates in corresponding header file. +// Do not remove this file. +// diff --git a/vcore/src/dpl/core/src/string.cpp b/vcore/src/dpl/core/src/string.cpp new file mode 100644 index 0000000..fb2f79c --- /dev/null +++ b/vcore/src/dpl/core/src/string.cpp @@ -0,0 +1,250 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file string.cpp + * @author Piotr Marcinkiewicz (p.marcinkiew@samsung.com) + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + */ +#include <stddef.h> +#include <memory> +#include <dpl/string.h> +#include <dpl/char_traits.h> +#include <dpl/errno_string.h> +#include <dpl/exception.h> +#include <dpl/log/vcore_log.h> +#include <string> +#include <vector> +#include <algorithm> +#include <cstring> +#include <errno.h> +#include <iconv.h> +#include <unicode/ustring.h> + +// TODO: Completely move to ICU +namespace VcoreDPL { +namespace //anonymous +{ +class ASCIIValidator +{ + const std::string& m_TestedString; + + public: + ASCIIValidator(const std::string& aTestedString); + + void operator()(char aCharacter) const; +}; + +ASCIIValidator::ASCIIValidator(const std::string& aTestedString) : + m_TestedString(aTestedString) +{} + +void ASCIIValidator::operator()(char aCharacter) const +{ + // Check for ASCII data range + if (aCharacter <= 0) { + ThrowMsg( + StringException::InvalidASCIICharacter, + "invalid character code " << static_cast<int>(aCharacter) + << " from string [" << + m_TestedString + << "] passed as ASCII"); + } +} + +const iconv_t gc_IconvOperError = reinterpret_cast<iconv_t>(-1); +const size_t gc_IconvConvertError = static_cast<size_t>(-1); +} // namespace anonymous + +String FromUTF8String(const std::string& aIn) +{ + if (aIn.empty()) { + return String(); + } + + size_t inbytes = aIn.size(); + + // Default iconv UTF-32 module adds BOM (4 bytes) in from of string + // The worst case is when 8bit UTF-8 char converts to 32bit UTF-32 + // newsize = oldsize * 4 + end + bom + // newsize - bytes for UTF-32 string + // oldsize - letters in UTF-8 string + // end - end character for UTF-32 (\0) + // bom - Unicode header in front of string (0xfeff) + size_t outbytes = sizeof(wchar_t) * (inbytes + 2); + std::vector<wchar_t> output(inbytes + 2, 0); + + size_t outbytesleft = outbytes; + char* inbuf = const_cast<char*>(aIn.c_str()); + + // vector is used to provide buffer for iconv which expects char* buffer + // but during conversion from UTF32 uses internaly wchar_t + char* outbuf = reinterpret_cast<char*>(&output[0]); + + iconv_t iconvHandle = iconv_open("UTF-32", "UTF-8"); + + if (gc_IconvOperError == iconvHandle) { + int error = errno; + + ThrowMsg(StringException::IconvInitErrorUTF8ToUTF32, + "iconv_open failed for " << "UTF-32 <- UTF-8" << + "error: " << GetErrnoString(error)); + } + + size_t iconvRet = iconv(iconvHandle, + &inbuf, + &inbytes, + &outbuf, + &outbytesleft); + + iconv_close(iconvHandle); + + if (gc_IconvConvertError == iconvRet) { + ThrowMsg(StringException::IconvConvertErrorUTF8ToUTF32, + "iconv failed for " << "UTF-32 <- UTF-8" << "error: " + << GetErrnoString()); + } + + // Ignore BOM in front of UTF-32 + return &output[1]; +} + +std::string ToUTF8String(const VcoreDPL::String& aIn) +{ + if (aIn.empty()) { + return std::string(); + } + + size_t inbytes = aIn.size() * sizeof(wchar_t); + size_t outbytes = inbytes + sizeof(char); + + // wstring returns wchar_t but iconv expects char* + // iconv internally is processing input as wchar_t + char* inbuf = reinterpret_cast<char*>(const_cast<wchar_t*>(aIn.c_str())); + std::vector<char> output(inbytes, 0); + char* outbuf = &output[0]; + + size_t outbytesleft = outbytes; + + iconv_t iconvHandle = iconv_open("UTF-8", "UTF-32"); + + if (gc_IconvOperError == iconvHandle) { + ThrowMsg(StringException::IconvInitErrorUTF32ToUTF8, + "iconv_open failed for " << "UTF-8 <- UTF-32" + << "error: " << GetErrnoString()); + } + + size_t iconvRet = iconv(iconvHandle, + &inbuf, + &inbytes, + &outbuf, + &outbytesleft); + + iconv_close(iconvHandle); + + if (gc_IconvConvertError == iconvRet) { + ThrowMsg(StringException::IconvConvertErrorUTF32ToUTF8, + "iconv failed for " << "UTF-8 <- UTF-32" + << "error: " << GetErrnoString()); + } + + return &output[0]; +} + +String FromASCIIString(const std::string& aString) +{ + String output; + + std::for_each(aString.begin(), aString.end(), ASCIIValidator(aString)); + std::copy(aString.begin(), aString.end(), std::back_inserter<String>(output)); + + return output; +} + +String FromUTF32String(const std::wstring& aString) +{ + return String(&aString[0]); +} + +static UChar *ConvertToICU(const String &inputString) +{ + std::unique_ptr<UChar[]> outputString; + int32_t size = 0; + int32_t convertedSize = 0; + UErrorCode error = U_ZERO_ERROR; + + // Calculate size of output string + ::u_strFromWCS(NULL, + 0, + &size, + inputString.c_str(), + -1, + &error); + + if (error == U_ZERO_ERROR || + error == U_BUFFER_OVERFLOW_ERROR) + { + // What buffer size is ok ? + VcoreLogD("ICU: Output buffer size: %i", size); + } else { + ThrowMsg(StringException::ICUInvalidCharacterFound, + "ICU: Failed to retrieve output string size. Error: " + << error); + } + + // Allocate proper buffer + outputString.reset(new UChar[size + 1]); + ::memset(outputString.get(), 0, sizeof(UChar) * (size + 1)); + + error = U_ZERO_ERROR; + + // Do conversion + ::u_strFromWCS(outputString.get(), + size + 1, + &convertedSize, + inputString.c_str(), + -1, + &error); + + if (!U_SUCCESS(error)) { + ThrowMsg(StringException::ICUInvalidCharacterFound, + "ICU: Failed to convert string. Error: " << error); + } + + // Done + return outputString.release(); +} + +int StringCompare(const String &left, + const String &right, + bool caseInsensitive) +{ + // Convert input strings + std::unique_ptr<UChar[]> leftICU(ConvertToICU(left)); + std::unique_ptr<UChar[]> rightICU(ConvertToICU(right)); + + if (caseInsensitive) { + return static_cast<int>(u_strcasecmp(leftICU.get(), rightICU.get(), 0)); + } else { + return static_cast<int>(u_strcmp(leftICU.get(), rightICU.get())); + } +} +} //namespace VcoreDPL + +std::ostream& operator<<(std::ostream& aStream, const VcoreDPL::String& aString) +{ + return aStream << VcoreDPL::ToUTF8String(aString); +} diff --git a/vcore/src/dpl/core/src/thread.cpp b/vcore/src/dpl/core/src/thread.cpp new file mode 100644 index 0000000..98fdd48 --- /dev/null +++ b/vcore/src/dpl/core/src/thread.cpp @@ -0,0 +1,609 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file thread.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of thread + */ +#include <stddef.h> +#include <dpl/thread.h> +#include <dpl/log/vcore_log.h> +#include <sys/time.h> +#include <algorithm> +#include <dpl/assert.h> +#include <errno.h> +#include <time.h> +#include <string.h> + +namespace // anonymous +{ +static const size_t NANOSECONDS_PER_SECOND = + static_cast<uint64_t>(1000 * 1000 * 1000); + +static const size_t NANOSECONDS_PER_MILISECOND = + static_cast<uint64_t>(1000 * 1000); + +static const size_t NANOSECONDS_PER_MICROSECOND = + static_cast<uint64_t>(1000); + +static const std::thread::id g_mainThread = std::this_thread::get_id(); + +class ThreadSpecific +{ + public: + pthread_key_t threadSpecific; + + ThreadSpecific() : + threadSpecific(0) + { + threadSpecific = 0; + pthread_key_create(&threadSpecific, NULL); + } + + virtual ~ThreadSpecific() + { + pthread_key_delete(threadSpecific); + } +}; + +static ThreadSpecific g_threadSpecific; +} // namespace anonymous + +namespace VcoreDPL { +bool g_TLSforMainCreated = false; + +Thread::Thread() : + m_thread(), + m_abandon(false), + m_running(false), + m_directInvoke(false) +{} + +Thread::~Thread() +{ + // Ensure that we quit thread + // Always wait thread by yourself; if thread is still running + // this may be sometimes very bad. When derived, some resources + // may leak or be doubly freed + Quit(); + + // Remove any remainig events + // Thread proc is surely not running now + for (InternalEventList::iterator iterator = m_eventList.begin(); + iterator != m_eventList.end(); + ++iterator) + { + iterator->eventDeleteProc(iterator->event, iterator->userParam); + } + + m_eventList.clear(); +} + +bool Thread::IsMainThread() +{ + return (std::this_thread::get_id() == g_mainThread); +} + +Thread *Thread::GetCurrentThread() +{ + if (std::this_thread::get_id() == g_mainThread) { + return NULL; + } + + void *threadSpecific = pthread_getspecific(g_threadSpecific.threadSpecific); + + // Is this a managed thread ? + if (threadSpecific == NULL) { + Throw(Exception::UnmanagedThread); + } + + return static_cast<Thread *>(threadSpecific); +} + +void *Thread::StaticThreadEntry(void *param) +{ + VcoreLogD("Entered static thread entry"); + + // Retrieve context + Thread *This = static_cast<Thread *>(param); + Assert(This != NULL); + + // Set thread specific + int result = pthread_setspecific(g_threadSpecific.threadSpecific, This); + + if (result) + VcoreLogE("Failed to set threadSpecific."); + + // Enter thread proc + // Do not allow exceptions to hit pthread core + UNHANDLED_EXCEPTION_HANDLER_BEGIN + { + This->ThreadEntry(); + } + UNHANDLED_EXCEPTION_HANDLER_END + + // Critical section + { + // Leave running state + std::lock_guard<std::mutex> lock(This->m_stateMutex); + + This->m_running = false; + + // Abandon thread + if (This->m_abandon) { + VcoreLogD("Thread was abandoned"); + This->m_thread.detach(); + } else { + VcoreLogD("Thread is joinable"); + } + } + + return NULL; +} + +int Thread::ThreadEntry() +{ + VcoreLogD("Entered default thread entry"); + return Exec(); +} + +void Thread::ProcessEvents() +{ + VcoreLogD("Processing events"); + + // Steal current event list + InternalEventList stolenEvents; + + // Enter event list critical section + { + std::lock_guard<std::mutex> lock(m_eventMutex); + m_eventList.swap(stolenEvents); + m_eventInvoker.Reset(); + } + + // Process event list + VcoreLogD("Stolen %u internal events", stolenEvents.size()); + + for (InternalEventList::iterator iterator = stolenEvents.begin(); + iterator != stolenEvents.end(); + ++iterator) + { + // Dispatch immediate event + iterator->eventDispatchProc(iterator->event, iterator->userParam); + + // Delete event + iterator->eventDeleteProc(iterator->event, iterator->userParam); + } +} + +void Thread::ProcessTimedEvents() +{ + // Critical section on timed events mutex + { + std::lock_guard<std::mutex> lock(m_timedEventMutex); + + // Get current time + unsigned long currentTimeMiliseconds = GetCurrentTimeMiliseconds(); + + // Info + VcoreLogD("Processing timed events. Time now: %lu ms", currentTimeMiliseconds); + + // All timed events are sorted chronologically + // Emit timed out events + while (!m_timedEventVector.empty() && + currentTimeMiliseconds >= + m_timedEventVector.begin()->registerTimeMiliseconds + + m_timedEventVector.begin()->dueTimeMiliseconds) + { + // Info + VcoreLogD("Transforming timed event into immediate event. Absolute due time: %lu ms", + (m_timedEventVector.begin()->registerTimeMiliseconds + + m_timedEventVector.begin()->dueTimeMiliseconds)); + + // Emit immediate event + PushEvent(m_timedEventVector.begin()->event, + m_timedEventVector.begin()->eventDispatchProc, + m_timedEventVector.begin()->eventDeleteProc, + m_timedEventVector.begin()->userParam); + + // Remove timed eventand fix heap + std::pop_heap(m_timedEventVector.begin(), m_timedEventVector.end()); + m_timedEventVector.pop_back(); + } + } +} + +unsigned long Thread::GetCurrentTimeMiliseconds() const +{ + timeval tv; + gettimeofday(&tv, NULL); + return static_cast<unsigned long>(tv.tv_sec) * 1000 + + static_cast<unsigned long>(tv.tv_usec) / 1000; +} + +int Thread::Exec() +{ + VcoreLogD("Executing thread event processing"); + + const std::size_t MIN_HANDLE_LIST_SIZE = 4; + + // Start processing of events + WaitableHandleListEx handleList; + + // index 0: Quit waitable event handle + handleList.push_back(std::make_pair(m_quitEvent.GetHandle(), WaitMode::Read)); + + // index 1: Event occurred event handle + handleList.push_back(std::make_pair(m_eventInvoker.GetHandle(), + WaitMode::Read)); + + // index 2: Timed event occurred event handle + handleList.push_back(std::make_pair(m_timedEventInvoker.GetHandle(), + WaitMode::Read)); + + // index 3: Waitable handle watch support invoker + handleList.push_back(std::make_pair(WaitableHandleWatchSupport:: + WaitableInvokerHandle(), + WaitMode::Read)); + + // + // Watch list might have been initialized before threaded started + // Need to fill waitable event watch list in this case + // + { + WaitableHandleListEx waitableHandleWatchHandles = + WaitableHandleWatchSupport::WaitableWatcherHandles(); + std::copy( + waitableHandleWatchHandles.begin(), + waitableHandleWatchHandles.end(), std::back_inserter(handleList)); + } + + // Quit flag + bool quit = false; + + while (!quit) { + // Retrieve minimum wait time, according to timed events list + unsigned long minimumWaitTime; + + // Critical section on timed events mutex + { + std::lock_guard<std::mutex> lock(m_timedEventMutex); + + if (!m_timedEventVector.empty()) { + unsigned long currentTimeMiliseconds = + GetCurrentTimeMiliseconds(); + unsigned long destinationTimeMiliseconds = + m_timedEventVector.begin()->registerTimeMiliseconds + + m_timedEventVector.begin()->dueTimeMiliseconds; + + // Are we already late with timed event ? + if (currentTimeMiliseconds > destinationTimeMiliseconds) { + minimumWaitTime = 0; + } else { + minimumWaitTime = destinationTimeMiliseconds - + currentTimeMiliseconds; + } + } else { + minimumWaitTime = 0xFFFFFFFF; // Infinity + } + } + + // Info + VcoreLogD("Thread loop minimum wait time: %lu ms", minimumWaitTime); + + // Do thread waiting + WaitableHandleIndexList waitableHandleIndexList = + WaitForMultipleHandles(handleList, minimumWaitTime); + + if (waitableHandleIndexList.empty()) { + // Timeout occurred. Process timed events. + VcoreLogD("Timed event list elapsed invoker"); + ProcessTimedEvents(); + continue; + } + + // Go through each index + for (WaitableHandleIndexList::const_iterator + waitableHandleIndexIterator = waitableHandleIndexList.begin(); + waitableHandleIndexIterator != waitableHandleIndexList.end(); + ++waitableHandleIndexIterator) + { + size_t index = *waitableHandleIndexIterator; + + VcoreLogD("Event loop triggered with index: %u", index); + + switch (index) { + case 0: + // Quit waitable event handle + quit = true; + break; + + case 1: + // Event occurred event handle + ProcessEvents(); + + // Handle direct invoker + if (m_directInvoke) { + m_directInvoke = false; + + VcoreLogD("Handling direct invoker"); + + // Update list + while (handleList.size() > MIN_HANDLE_LIST_SIZE) { + handleList.pop_back(); + } + + // Insert current waitable event handles instead + { + WaitableHandleListEx waitableHandleWatchHandles = + WaitableHandleWatchSupport::WaitableWatcherHandles(); + std::copy( + waitableHandleWatchHandles.begin(), + waitableHandleWatchHandles.end(), + std::back_inserter(handleList)); + } + } + + // Done + break; + + case 2: + // Timed event list changed + VcoreLogD("Timed event list changed invoker"); + ProcessTimedEvents(); + + // Reset timed event invoker + m_timedEventInvoker.Reset(); + + // Done + break; + + case 3: + // Waitable handle watch support invoker + VcoreLogD("Waitable handle watch invoker event occurred"); + + // First, remove all previous handles + while (handleList.size() > MIN_HANDLE_LIST_SIZE) { + handleList.pop_back(); + } + + // Insert current waitable event handles instead + { + WaitableHandleListEx waitableHandleWatchHandles = + WaitableHandleWatchSupport::WaitableWatcherHandles(); + std::copy( + waitableHandleWatchHandles.begin(), + waitableHandleWatchHandles.end(), + std::back_inserter(handleList)); + } + + // Handle invoker in waitable watch support + WaitableHandleWatchSupport::InvokerFinished(); + + VcoreLogD("Waitable handle watch invoker event handled"); + + // Done + break; + + default: + // Waitable event watch list + VcoreLogD("Waitable handle watch event occurred"); + + // Handle event in waitable handle watch + { + std::pair<WaitableHandle, + WaitMode::Type> handle = handleList[index]; + WaitableHandleWatchSupport::HandleWatcher(handle.first, + handle.second); + } + + if (m_directInvoke) { + m_directInvoke = false; + + VcoreLogD("Handling direct invoker"); + + // Update list + while (handleList.size() > MIN_HANDLE_LIST_SIZE) { + handleList.pop_back(); + } + + // Insert current waitable event handles instead + { + WaitableHandleListEx waitableHandleWatchHandles = + WaitableHandleWatchSupport:: + WaitableWatcherHandles(); + std::copy(waitableHandleWatchHandles.begin(), + waitableHandleWatchHandles.end(), + std::back_inserter(handleList)); + } + } + + VcoreLogD("Waitable handle watch event handled"); + + // Done + break; + } + } + } + + VcoreLogD("Leaving thread event processing"); + return 0; +} + +void Thread::Run() +{ + VcoreLogD("Running thread"); + + // Critical section + { + std::lock_guard<std::mutex> lock(m_stateMutex); + + if (m_running) { + return; + } + + try{ + m_thread = std::thread(StaticThreadEntry,this); + }catch(std::system_error e){ + Throw(Exception::RunFailed); + } + + // At default, we abandon thread + m_abandon = true; + + // Enter running state + m_running = true; + } + + VcoreLogD("Thread run"); +} + +void Thread::Quit() +{ + // Critical section + { + std::lock_guard<std::mutex> lock(m_stateMutex); + + // Is thread running ? + if (!m_running) { + return; + } + + VcoreLogD("Quitting thread..."); + + // Do not abandon thread, we will join + m_abandon = false; + + // Singal quit waitable event + m_quitEvent.Signal(); + } + + try{ + m_thread.join(); + }catch(std::system_error e){ + Throw(Exception::QuitFailed); + } + + VcoreLogD("Thread quit"); +} + +void Thread::PushEvent(void *event, + EventDispatchProc eventDispatchProc, + EventDeleteProc eventDeleteProc, + void *userParam) +{ + // Enter event list critical section + std::lock_guard<std::mutex> lock(m_eventMutex); + + // Push new event + m_eventList.push_back(InternalEvent(event, userParam, eventDispatchProc, + eventDeleteProc)); + + // Trigger invoker + m_eventInvoker.Signal(); + + VcoreLogD("Event pushed and invoker signaled"); +} + +void Thread::PushTimedEvent(void *event, + double dueTimeSeconds, + EventDispatchProc eventDispatchProc, + EventDeleteProc eventDeleteProc, + void *userParam) +{ + // Check for developer errors + Assert(dueTimeSeconds >= 0.0); + + // Enter timed event list critical section + std::lock_guard<std::mutex> lock(m_timedEventMutex); + + // Get current time + unsigned long currentTimeMiliseconds = GetCurrentTimeMiliseconds(); + + // Convert to miliseconds + unsigned long dueTimeMiliseconds = + static_cast<unsigned long>(1000.0 * dueTimeSeconds); + + // Push new timed event + m_timedEventVector.push_back(InternalTimedEvent(event, userParam, + dueTimeMiliseconds, + currentTimeMiliseconds, + eventDispatchProc, + eventDeleteProc)); + + // Heapify timed events + std::make_heap(m_timedEventVector.begin(), m_timedEventVector.end()); + + // Trigger invoker + m_timedEventInvoker.Signal(); + + VcoreLogD("Timed event pushed and invoker signaled: " + "due time: %lu ms, absolute due time: %lu ms", + dueTimeMiliseconds, currentTimeMiliseconds + dueTimeMiliseconds); +} + +Thread *Thread::GetInvokerThread() +{ + return this; +} + +void Thread::HandleDirectInvoker() +{ + // We must be in ProcessEvents call stack + // Mark that situation to handle direct invoker + m_directInvoke = true; +} + +void Thread::Sleep(uint64_t seconds) +{ + NanoSleep(seconds * NANOSECONDS_PER_SECOND); +} + +void Thread::MiliSleep(uint64_t miliseconds) +{ + NanoSleep(miliseconds * NANOSECONDS_PER_MILISECOND); +} + +void Thread::MicroSleep(uint64_t microseconds) +{ + NanoSleep(microseconds * NANOSECONDS_PER_MICROSECOND); +} + +void Thread::NanoSleep(uint64_t nanoseconds) +{ + timespec requestedTime = { + static_cast<time_t>( + nanoseconds / NANOSECONDS_PER_SECOND), + + static_cast<long>( + nanoseconds % NANOSECONDS_PER_SECOND) + }; + + timespec remainingTime; + + for (;;) { + if (nanosleep(&requestedTime, &remainingTime) == 0) { + break; + } + + int error = errno; + Assert(error == EINTR); + + requestedTime = remainingTime; + } +} +} // namespace VcoreDPL diff --git a/vcore/src/dpl/core/src/type_list.cpp b/vcore/src/dpl/core/src/type_list.cpp new file mode 100644 index 0000000..fa94806 --- /dev/null +++ b/vcore/src/dpl/core/src/type_list.cpp @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file type_list.cpp + * @author Bartosz Janiak (b.janiak@samsung.com) + * @version 1.0 + * @brief Generic type list template + */ +#include <stddef.h> +#include <dpl/type_list.h> + +// +// Note: +// +// The file here is left blank to enable precompilation +// of templates in corresponding header file. +// Do not remove this file. +// diff --git a/vcore/src/dpl/core/src/waitable_event.cpp b/vcore/src/dpl/core/src/waitable_event.cpp new file mode 100644 index 0000000..8ff1417 --- /dev/null +++ b/vcore/src/dpl/core/src/waitable_event.cpp @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file waitable_event.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of waitable event + */ +#include <stddef.h> +#include <dpl/waitable_event.h> +#include <sys/select.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <errno.h> + +namespace VcoreDPL { +WaitableEvent::WaitableEvent() +{ + if (pipe(m_pipe) == -1) { + Throw(Exception::CreateFailed); + } + + if (fcntl(m_pipe[0], F_SETFL, O_NONBLOCK | + fcntl(m_pipe[0], F_GETFL)) == -1) + { + Throw(Exception::CreateFailed); + } +} + +WaitableEvent::~WaitableEvent() +{ + if (TEMP_FAILURE_RETRY(close(m_pipe[0])) == -1) { + Throw(Exception::DestroyFailed); + } + + if (TEMP_FAILURE_RETRY(close(m_pipe[1])) == -1) { + Throw(Exception::DestroyFailed); + } +} + +WaitableHandle WaitableEvent::GetHandle() const +{ + return m_pipe[0]; +} + +void WaitableEvent::Signal() const +{ + char data = 0; + + if (TEMP_FAILURE_RETRY(write(m_pipe[1], &data, 1)) != 1) { + Throw(Exception::SignalFailed); + } +} + +void WaitableEvent::Reset() const +{ + char data; + + if (TEMP_FAILURE_RETRY(read(m_pipe[0], &data, 1)) != 1) { + Throw(Exception::ResetFailed); + } +} +} // namespace VcoreDPL diff --git a/vcore/src/dpl/core/src/waitable_handle.cpp b/vcore/src/dpl/core/src/waitable_handle.cpp new file mode 100644 index 0000000..58d0a35 --- /dev/null +++ b/vcore/src/dpl/core/src/waitable_handle.cpp @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file waitable_handle.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of waitable handle + */ +#include <stddef.h> +#include <dpl/waitable_event.h> +#include <dpl/workaround.h> +#include <sys/select.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <dpl/assert.h> + +namespace VcoreDPL { +namespace // anonymous +{ +void CheckWaitableHandle(WaitableHandle handle) +{ +#ifdef DPL_ENABLE_WAITABLE_HANDLE_BADF_CHECK + // Try to get descriptor flags + int result = fcntl(handle, F_GETFL); + + if (result == -1 && errno == EBADF) { + AssertMsg(0, "CheckWaitableHandle: Invalid WaitableHandle! (EBADF)"); + } + + AssertMsg(result != -1, "CheckWaitableHandle: Invalid WaitableHandle!"); +#endif // DPL_ENABLE_WAITABLE_HANDLE_BADF_CHECK +} +} // namespace anonymous + +WaitableHandleIndexList WaitForSingleHandle(WaitableHandle handle, + unsigned long miliseconds) +{ + WaitableHandleList waitHandles; + waitHandles.push_back(handle); + return WaitForMultipleHandles(waitHandles, miliseconds); +} + +WaitableHandleIndexList WaitForSingleHandle(WaitableHandle handle, + WaitMode::Type mode, + unsigned long miliseconds) +{ + WaitableHandleListEx waitHandles; + waitHandles.push_back(std::make_pair(handle, mode)); + return WaitForMultipleHandles(waitHandles, miliseconds); +} + +WaitableHandleIndexList WaitForMultipleHandles( + const WaitableHandleList &waitableHandleList, + unsigned long miliseconds) +{ + WaitableHandleListEx handleList; + + for (WaitableHandleList::const_iterator iterator = waitableHandleList.begin(); + iterator != waitableHandleList.end(); + ++iterator) + { + // Wait for multiple objects + handleList.push_back(std::make_pair(*iterator, WaitMode::Read)); + } + + // Do waiting + return WaitForMultipleHandles(handleList, miliseconds); +} + +WaitableHandleIndexList WaitForMultipleHandles( + const WaitableHandleListEx &waitableHandleListEx, + unsigned long miliseconds) +{ + fd_set readFds, writeFds, errorFds; + + // Fill sets + int maxFd = -1; + + FD_ZERO(&readFds); + FD_ZERO(&writeFds); + FD_ZERO(&errorFds); + + // Add read wait handles + for (WaitableHandleListEx::const_iterator iterator = + waitableHandleListEx.begin(); + iterator != waitableHandleListEx.end(); + ++iterator) + { + if (iterator->first > maxFd) { + maxFd = iterator->first; + } + + CheckWaitableHandle(iterator->first); + + // Handle errors along with read and write events + FD_SET(iterator->first, &errorFds); + + if (iterator->second == WaitMode::Read) { + FD_SET(iterator->first, &readFds); + } else if (iterator->second == WaitMode::Write) { + FD_SET(iterator->first, &writeFds); + } + } + + // Do select + timeval timeout; + timeval *effectiveTimeout = NULL; + if (miliseconds != 0xFFFFFFFF) { + timeout.tv_sec = miliseconds / 1000; + timeout.tv_usec = (miliseconds % 1000) * 1000; + effectiveTimeout = &timeout; + } + + if (TEMP_FAILURE_RETRY(select(maxFd + 1, &readFds, &writeFds, &errorFds, + effectiveTimeout)) == -1) + { + Throw(WaitFailed); + } + + // Check results + WaitableHandleIndexList indexes; + size_t index = 0; + + for (WaitableHandleListEx::const_iterator iterator = + waitableHandleListEx.begin(); + iterator != waitableHandleListEx.end(); + ++iterator) + { + // Always return errors, no matter what type of listening is set + if (FD_ISSET(iterator->first, &errorFds)) { + indexes.push_back(index); + } else if (iterator->second == WaitMode::Read) { + if (FD_ISSET(iterator->first, &readFds)) { + indexes.push_back(index); + } + } else if (iterator->second == WaitMode::Write) { + if (FD_ISSET(iterator->first, &writeFds)) { + indexes.push_back(index); + } + } + ++index; + } + + // Successfuly awaited some events or timeout occurred + return indexes; +} +} // namespace VcoreDPL diff --git a/vcore/src/dpl/core/src/waitable_handle_watch_support.cpp b/vcore/src/dpl/core/src/waitable_handle_watch_support.cpp new file mode 100644 index 0000000..fb46539 --- /dev/null +++ b/vcore/src/dpl/core/src/waitable_handle_watch_support.cpp @@ -0,0 +1,376 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file waitable_handle_watch_support.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of waitable handle watch + * support + */ +#include <stddef.h> +#include <dpl/waitable_handle_watch_support.h> +#include <dpl/thread.h> +#include <dpl/log/vcore_log.h> +#include <algorithm> +#include <dpl/assert.h> + +namespace VcoreDPL { +WaitableHandleWatchSupport::WaitableHandleWatchSupport() +{} + +WaitableHandleWatchSupport::~WaitableHandleWatchSupport() +{ + // Developer assertions + if (!m_watchersMap.empty()) { + VcoreLogW("### Leaked watchers map dump ###"); + + for (WaitableHandleWatchersMap::const_iterator iterator = + m_watchersMap.begin(); + iterator != m_watchersMap.end(); + ++iterator) + { + VcoreLogW("### Waitable handle: %i", iterator->first); + + VcoreLogW("### Read listeners: %u", iterator->second.readListenersCount); + VcoreLogW("### Write listeners: %u", iterator->second.writeListenersCount); + + for (WaitableHandleListenerList::const_iterator listenersIterator = + iterator->second.listeners.begin(); + listenersIterator != iterator->second.listeners.end(); + ++listenersIterator) + { + VcoreLogW("### Mode: %i. Listener: %p", + listenersIterator->mode, listenersIterator->listener); + } + } + } +} + +WaitableHandle WaitableHandleWatchSupport::WaitableInvokerHandle() const +{ + return m_watchersInvoker.GetHandle(); +} + +WaitableHandleListEx WaitableHandleWatchSupport::WaitableWatcherHandles() const +{ + // Critical section + { + std::lock_guard<std::recursive_mutex> lock(m_watchersMutex); + + WaitableHandleListEx handleList; + + for (WaitableHandleWatchersMap::const_iterator iterator = + m_watchersMap.begin(); + iterator != m_watchersMap.end(); + ++iterator) + { + // Register waitable event id for wait + // Check if there are any read listeners and write listeners + // and register for both if applicable + if (iterator->second.readListenersCount > 0) { + handleList.push_back(std::make_pair(iterator->first, + WaitMode::Read)); + } + + if (iterator->second.writeListenersCount > 0) { + handleList.push_back(std::make_pair(iterator->first, + WaitMode::Write)); + } + } + + return handleList; + } +} + +void WaitableHandleWatchSupport::InvokerFinished() +{ + VcoreLogD("Invoker finished called"); + + // Reset invoker + m_watchersInvoker.Reset(); + + // Commit invoke + m_watchersInvokerCommit.Signal(); +} + +void WaitableHandleWatchSupport::HandleWatcher(WaitableHandle waitableHandle, + WaitMode::Type mode) +{ + // + // Waitable event occurred + // Now call all listeners for that waitable event. It is possible + // that some of listeners early disappeared. This is not a problem. + // Warning: Listeners and/or watcher may also disappear during dispatching + // handlers! + // + VcoreLogD("Waitable event occurred"); + + // Critical section for other threads + { + std::lock_guard<std::recursive_mutex> lock(m_watchersMutex); + + // Notice: We must carefully call watchers here as they may disappear + // (zero listeners) or be created during each of handler call + // All removed listeners are handled correctly. Adding + // additional listener to the same waitable handle + // during handler dispatch sequence is _not_ supported. + WaitableHandleWatchersMap trackedWatchers = m_watchersMap; + + for (WaitableHandleWatchersMap::const_iterator trackedWatchersIterator + = trackedWatchers.begin(); + trackedWatchersIterator != trackedWatchers.end(); + ++trackedWatchersIterator) + { + // Check if this watcher still exists + // If not, go to next tracked watcher + if (m_watchersMap.find(trackedWatchersIterator->first) == + m_watchersMap.end()) + { + VcoreLogD("Watcher disappeared during watcher handler"); + continue; + } + + // Is this is a waitable handle that we are searching for ? + if (waitableHandle != trackedWatchersIterator->first) { + continue; + } + + // Track watcher listeners list + WaitableHandleListenerList trackedListeners = + trackedWatchersIterator->second.listeners; + + VcoreLogD("Calling waitable event listeners (%u)...", + trackedListeners.size()); + + // Notice: We must carefully call listeners here as they may + // disappear or be created during each of handler call + // All removed listeners are handled correctly. Adding + // additional listener to the same waitable handle + // during handler dispatch sequence is should be also + // handled, as an extremly case. + + // Call all waitable event listeners who listen for that event + for (WaitableHandleListenerList::const_iterator + trackedListenersIterator = trackedListeners.begin(); + trackedListenersIterator != trackedListeners.end(); + ++trackedListenersIterator) + { + // Check if this watcher still exists + // If not, there cannot be another one. Must exit now (after + // break, we actually exit) + if (m_watchersMap.find(trackedWatchersIterator->first) == + m_watchersMap.end()) + { + VcoreLogD("Watcher disappeared during watcher handler"); + break; + } + + // Check if this watcher listener still exists + // If not, go to next tracked watcher listener + bool listenerStillExists = false; + + for (WaitableHandleListenerList::const_iterator + searchListenerIterator = + trackedWatchersIterator->second.listeners.begin(); + searchListenerIterator != + trackedWatchersIterator->second.listeners.end(); + ++searchListenerIterator) + { + if (searchListenerIterator->listener == + trackedListenersIterator->listener && + searchListenerIterator->mode == + trackedListenersIterator->mode) + { + listenerStillExists = true; + break; + } + } + + if (!listenerStillExists) { + VcoreLogD("Watcher listener disappeared during watcher handler"); + break; + } + + // Is this is a listener mode that we are searching for ? + if (mode != trackedListenersIterator->mode) { + continue; + } + + // Call waitable event watch listener + VcoreLogD("Before tracker listener call..."); + trackedListenersIterator->listener->OnWaitableHandleEvent( + trackedWatchersIterator->first, + trackedListenersIterator->mode); + VcoreLogD("After tracker listener call..."); + } + + // Now call all those listeners who registered during listener calls + // FIXME: Implement! Notice, that scenario may be recursive! + + VcoreLogD("Waitable event listeners called"); + + // No more waitable events possible - consistency check + break; + } + } +} + +void WaitableHandleWatchSupport::AddWaitableHandleWatch( + WaitableHandleListener* listener, + WaitableHandle waitableHandle, + WaitMode::Type mode) +{ + // Enter waitable event list critical section + std::lock_guard<std::recursive_mutex> lock(m_watchersMutex); + + // Find proper list to register into + WaitableHandleWatchersMap::iterator mapIterator = m_watchersMap.find( + waitableHandle); + + if (mapIterator != m_watchersMap.end()) { + // Assert if there is no such listener already that is listening in this + // mode + for (WaitableHandleListenerList::iterator listenersIterator = + mapIterator->second.listeners.begin(); + listenersIterator != mapIterator->second.listeners.end(); + ++listenersIterator) + { + // Must not insert same listener-mode pair + Assert( + listenersIterator->listener != listener || + listenersIterator->mode != mode); + } + } + + VcoreLogD("Adding waitable handle watch: %i", waitableHandle); + + // Push new waitable event watch + if (mapIterator != m_watchersMap.end()) { + mapIterator->second.listeners.push_back(WaitableHandleWatcher(listener, + mode)); + } else { + m_watchersMap[waitableHandle].listeners.push_back(WaitableHandleWatcher( + listener, mode)); + } + + // Update counters + switch (mode) { + case WaitMode::Read: + m_watchersMap[waitableHandle].readListenersCount++; + break; + + case WaitMode::Write: + m_watchersMap[waitableHandle].writeListenersCount++; + break; + + default: + Assert(0); + } + + // Trigger waitable event invoker to commit changes + CommitInvoker(); + + VcoreLogD("Waitable event watch added and invoker signaled"); +} + +void WaitableHandleWatchSupport::RemoveWaitableHandleWatch( + WaitableHandleListener *listener, + WaitableHandle waitableHandle, + WaitMode::Type mode) +{ + // Enter waitable event list critical section + std::lock_guard<std::recursive_mutex> lock(m_watchersMutex); + + // Find proper list with listener + WaitableHandleWatchersMap::iterator mapIterator = m_watchersMap.find( + waitableHandle); + + Assert(mapIterator != m_watchersMap.end()); + + // Assert if there is such listener and mode + WaitableHandleListenerList::iterator listIterator = + mapIterator->second.listeners.end(); + + for (WaitableHandleListenerList::iterator listenersIterator = + mapIterator->second.listeners.begin(); + listenersIterator != mapIterator->second.listeners.end(); + ++listenersIterator) + { + // Check same pair listener-mode + if (listenersIterator->listener == listener && + listenersIterator->mode == mode) + { + listIterator = listenersIterator; + break; + } + } + + // Same pair listener-mode must exist + Assert(listIterator != mapIterator->second.listeners.end()); + + VcoreLogD("Removing waitable handle watch: %i", waitableHandle); + + // Remove waitable event watch + mapIterator->second.listeners.erase(listIterator); + + // Update counters + switch (mode) { + case WaitMode::Read: + mapIterator->second.readListenersCount--; + break; + + case WaitMode::Write: + mapIterator->second.writeListenersCount--; + break; + + default: + Assert(0); + } + + // If list is empty, remove it too + if (mapIterator->second.listeners.empty()) { + m_watchersMap.erase(mapIterator); + } + + // Trigger waitable event invoker to commit changes + CommitInvoker(); + + VcoreLogD("Waitable event watch removed and invoker signaled"); +} + +void WaitableHandleWatchSupport::CommitInvoker() +{ + // Check calling context and execute invoker + if (Thread::GetCurrentThread() == GetInvokerThread()) { + VcoreLogD("Calling direct invoker"); + + // Direct invoker call + HandleDirectInvoker(); + } else { + VcoreLogD("Calling indirect invoker"); + + // Indirect invoker call + m_watchersInvoker.Signal(); + + WaitableHandleList waitHandles; + waitHandles.push_back(m_watchersInvokerCommit.GetHandle()); + WaitForMultipleHandles(waitHandles); + + m_watchersInvokerCommit.Reset(); + } +} + +} // namespace VcoreDPL diff --git a/vcore/src/dpl/db/include/dpl/db/naive_synchronization_object.h b/vcore/src/dpl/db/include/dpl/db/naive_synchronization_object.h new file mode 100644 index 0000000..d774ce0 --- /dev/null +++ b/vcore/src/dpl/db/include/dpl/db/naive_synchronization_object.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file naive_synchronization_object.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of SQL naive + * synchronization object + */ +#ifndef DPL_NAIVE_SYNCHRONIZATION_OBJECT_H +#define DPL_NAIVE_SYNCHRONIZATION_OBJECT_H + +#include <dpl/db/sql_connection.h> + +namespace VcoreDPL { +namespace DB { +/** + * Naive synchronization object used to synchronize SQL connection + * to the same database across different threads and processes + */ +class NaiveSynchronizationObject : + public SqlConnection::SynchronizationObject +{ + public: + // [SqlConnection::SynchronizationObject] + virtual void Synchronize(); + virtual void NotifyAll(); +}; +} // namespace DB +} // namespace VcoreDPL + +#endif // DPL_NAIVE_SYNCHRONIZATION_OBJECT_H diff --git a/vcore/src/dpl/db/include/dpl/db/orm.h b/vcore/src/dpl/db/include/dpl/db/orm.h new file mode 100644 index 0000000..39d0503 --- /dev/null +++ b/vcore/src/dpl/db/include/dpl/db/orm.h @@ -0,0 +1,1117 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file orm.h + * @author Bartosz Janiak (b.janiak@samsung.com) + * @version 1.0 + * @brief DPL-ORM: Object-relational mapping for sqlite database, written on top of DPL. + */ + +#include <cstdlib> +#include <cstdio> +#include <string> +#include <typeinfo> +#include <utility> +#include <set> +#include <list> +#include <memory> +#include <boost/optional.hpp> + +#include <dpl/db/sql_connection.h> +#include <dpl/db/orm_interface.h> +#include <dpl/string.h> +#include <dpl/type_list.h> +#include <dpl/assert.h> +#include <dpl/foreach.h> + +#ifndef DPL_ORM_H +#define DPL_ORM_H + +namespace VcoreDPL { +namespace DB { +namespace ORM { + +//TODO move to type utils +#define DPL_CHECK_TYPE_INSTANTIABILITY(type) \ + { \ + type _ignored_; \ + (void)_ignored_; \ + } + +#define DECLARE_COLUMN_TYPE_LIST() typedef VcoreDPL::TypeListDecl< +#define SELECTED_COLUMN(table_name, column_name) table_name::column_name, +#define DECLARE_COLUMN_TYPE_LIST_END(name) VcoreDPL::TypeListGuard>::Type name; + +typedef size_t ColumnIndex; +typedef size_t ArgumentIndex; +typedef boost::optional<VcoreDPL::String> OptionalString; +typedef boost::optional<int> OptionalInteger; +typedef VcoreDPL::DB::SqlConnection::DataCommand DataCommand; + +namespace RelationTypes { + extern const char Equal[]; + extern const char LessThan[]; + extern const char And[]; + extern const char Or[]; + extern const char Is[]; + extern const char In[]; + //TODO define more relation types +} + +namespace DataCommandUtils { + //TODO move to VcoreDPL::DataCommand? + void BindArgument(DataCommand *command, ArgumentIndex index, int argument); + void BindArgument(DataCommand *command, ArgumentIndex index, const OptionalInteger& argument); + void BindArgument(DataCommand *command, ArgumentIndex index, const VcoreDPL::String& argument); + void BindArgument(DataCommand *command, ArgumentIndex index, const OptionalString& argument); +} +class __attribute__ ((visibility("hidden"))) Expression { +public: + virtual ~Expression() {} + virtual std::string GetString() const = 0; + virtual ArgumentIndex BindTo(DataCommand *command, ArgumentIndex index) = 0; +}; + +typedef std::shared_ptr<Expression> ExpressionPtr; + +namespace OrderingUtils { + +template<typename CompoundType> inline std::string OrderByInternal() +{ + std::string order = OrderByInternal<typename CompoundType::Tail>(); + if(!order.empty()) return CompoundType::Head::GetString() + ", " + order; + else return CompoundType::Head::GetString(); +} + +template<> inline std::string OrderByInternal<TypeListGuard>() +{ + return std::string(); +} + +} + +template<typename ColumnType> +class __attribute__ ((visibility("hidden"))) OrderingExpression { +protected: + static std::string GetSchemaAndName() + { + std::string statement; + statement += ColumnType::GetTableName(); + statement += "."; + statement += ColumnType::GetColumnName(); + statement += " "; + return statement; + } +public: + virtual ~OrderingExpression() {} +}; + +template<const char* Operator, typename LeftExpression, typename RightExpression> +class __attribute__ ((visibility("hidden"))) BinaryExpression : public Expression { +protected: + LeftExpression m_leftExpression; + RightExpression m_rightExpression; + bool m_outerParenthesis; +public: + BinaryExpression(const LeftExpression& leftExpression, const RightExpression& rightExpression, bool outerParenthesis = true) : + m_leftExpression(leftExpression), + m_rightExpression(rightExpression), + m_outerParenthesis(outerParenthesis) + {} + + virtual std::string GetString() const + { + return (m_outerParenthesis ? "( " : " " ) + + m_leftExpression.GetString() + " " + Operator + " " + m_rightExpression.GetString() + + (m_outerParenthesis ? " )" : " " ) ; + } + + virtual ArgumentIndex BindTo(DataCommand *command, ArgumentIndex index) + { + index = m_leftExpression.BindTo(command, index); + return m_rightExpression.BindTo(command, index); + } + + template<typename TableDefinition> + struct ValidForTable { + typedef std::pair<typename LeftExpression ::template ValidForTable<TableDefinition>::Yes , + typename RightExpression::template ValidForTable<TableDefinition>::Yes > + Yes; + }; +}; + +template<typename LeftExpression, typename RightExpression> +BinaryExpression<RelationTypes::And, LeftExpression, RightExpression> + And(const LeftExpression& leftExpression, const RightExpression& rightExpression) +{ + return BinaryExpression<RelationTypes::And, LeftExpression, RightExpression> + (leftExpression, rightExpression); +} + +template<typename LeftExpression, typename RightExpression> +BinaryExpression<RelationTypes::Or, LeftExpression, RightExpression> + Or(const LeftExpression& leftExpression, const RightExpression& rightExpression) +{ + return BinaryExpression<RelationTypes::Or, LeftExpression, RightExpression> + (leftExpression, rightExpression); +} + +template<typename ArgumentType> +class __attribute__ ((visibility("hidden"))) ExpressionWithArgument : public Expression { +protected: + ArgumentType argument; + +public: + explicit ExpressionWithArgument(const ArgumentType& _argument) : argument(_argument) {} + + virtual ArgumentIndex BindTo(DataCommand *command, ArgumentIndex index) + { + DataCommandUtils::BindArgument(command, index, argument); + return index + 1; + } +}; + +template<typename ColumnData, const char* Relation> +class __attribute__ ((visibility("hidden"))) Compare : public ExpressionWithArgument<typename ColumnData::ColumnType> { +public: + explicit Compare(typename ColumnData::ColumnType column) : + ExpressionWithArgument<typename ColumnData::ColumnType>(column) + {} + + virtual std::string GetString() const + { + std::string statement; + statement += ColumnData::GetTableName(); + statement += "."; + statement += ColumnData::GetColumnName(); + statement += " "; + statement += Relation; + statement += " ?"; + return statement; + } + + template<typename TableDefinition> + struct ValidForTable { + typedef typename TableDefinition::ColumnList::template Contains<ColumnData> Yes; + }; +}; +#define ORM_DEFINE_COMPARE_EXPRESSION(name, relationType) \ + template<typename ColumnData> \ + class __attribute__ ((visibility("hidden"))) name : public Compare<ColumnData, RelationTypes::relationType> { \ + public: \ + name(typename ColumnData::ColumnType column) : \ + Compare<ColumnData, RelationTypes::relationType>(column) \ + {} \ + }; + +ORM_DEFINE_COMPARE_EXPRESSION(Equals, Equal) +ORM_DEFINE_COMPARE_EXPRESSION(Is, Is) + +#define ORM_DEFINE_ORDERING_EXPRESSION(name, value) \ + template<typename ColumnType> \ + class __attribute__ ((visibility("hidden"))) name \ + : OrderingExpression<ColumnType> { \ + public: \ + static std::string GetString() \ + { \ + std::string statement = OrderingExpression<ColumnType>::GetSchemaAndName(); \ + statement += value; \ + return statement; \ + } \ + }; + +ORM_DEFINE_ORDERING_EXPRESSION(OrderingAscending, "ASC") +ORM_DEFINE_ORDERING_EXPRESSION(OrderingDescending, "DESC") + +template<typename ColumnData1, typename ColumnData2> +class __attribute__ ((visibility("hidden"))) CompareBinaryColumn { +private: + std::string m_relation; +public: + CompareBinaryColumn(const char* Relation) : + m_relation(Relation) + {} + + virtual ~CompareBinaryColumn() {} + + virtual std::string GetString() const + { + std::string statement; + statement += ColumnData1::GetTableName(); + statement += "."; + statement += ColumnData1::GetColumnName(); + statement += " "; + statement += m_relation; + statement += " "; + statement += ColumnData2::GetTableName(); + statement += "."; + statement += ColumnData2::GetColumnName(); + + return statement; + } +}; + +template<typename ColumnData1, typename ColumnData2> +CompareBinaryColumn<ColumnData1, ColumnData2> + Equal() +{ + return CompareBinaryColumn<ColumnData1, ColumnData2>(RelationTypes::Equal); +} + +template<typename ColumnData, const char* Relation> +class __attribute__ ((visibility("hidden"))) NumerousArguments : public Expression { +protected: + std::set<typename ColumnData::ColumnType> m_argumentList; +public: + NumerousArguments(const std::set<typename ColumnData::ColumnType>& argumentList) : m_argumentList(argumentList) {} + + virtual std::string GetString() const + { + std::string statement; + statement += ColumnData::GetColumnName(); + statement += " "; + statement += Relation; + statement += " ( "; + + int argumentCount = m_argumentList.size(); + while(argumentCount) + { + statement += "?"; + argumentCount--; + if (argumentCount) + { + statement += ", "; + } + } + + statement += " )"; + + return statement; + } + + virtual ArgumentIndex BindTo(DataCommand *command, ArgumentIndex index) + { + ArgumentIndex argumentIndex = index; + FOREACH(argumentIt, m_argumentList) + { + DataCommandUtils::BindArgument(command, argumentIndex, *argumentIt); + argumentIndex++; + } + return argumentIndex + 1; + } + + template<typename TableDefinition> + struct ValidForTable { + typedef typename TableDefinition::ColumnList::template Contains<ColumnData> Yes; + }; +}; + +#define ORM_DEFINE_COMPARE_EXPRESSION_NUMEROUS_ARGUMENTS(name, relationType) \ + template<typename ColumnData> \ + class __attribute__ ((visibility("hidden"))) name : public NumerousArguments<ColumnData, RelationTypes::relationType> { \ + public: \ + name(std::set<typename ColumnData::ColumnType> column) : \ + NumerousArguments<ColumnData, RelationTypes::relationType>(column) \ + {} \ + }; + +ORM_DEFINE_COMPARE_EXPRESSION_NUMEROUS_ARGUMENTS(In, In) + +template<typename ColumnType> +ColumnType GetColumnFromCommand(ColumnIndex columnIndex, DataCommand *command); + +class __attribute__ ((visibility("hidden"))) CustomColumnBase { +public: + CustomColumnBase() {} + virtual ~CustomColumnBase() {} +}; + +template<typename ColumnType> +class __attribute__ ((visibility("hidden"))) CustomColumn : public CustomColumnBase { +private: + ColumnType m_columnData; + +public: + CustomColumn() {} + CustomColumn(ColumnType data) + { + m_columnData = data; + } + + void SetColumnData(ColumnType data) + { + m_columnData = data; + } + + ColumnType GetColumnData() const + { + return m_columnData; + } +}; + +template<typename ColumnList> +class __attribute__ ((visibility("hidden"))) CustomRowUtil { +public: + static void MakeColumnList(std::vector<CustomColumnBase*>& columnList) + { + typedef CustomColumn<typename ColumnList::Head::ColumnType> Type; + Type* pColumn = new Type(); + columnList.push_back(pColumn); + CustomRowUtil<typename ColumnList::Tail>::MakeColumnList(columnList); + } + + static void CopyColumnList(const std::vector<CustomColumnBase*>& srcList, std::vector<CustomColumnBase*>& dstList) + { + CopyColumnList(srcList, dstList, 0); + } + + static ColumnIndex GetColumnIndex(const std::string& columnName) + { + return GetColumnIndex(columnName, 0); + } + +private: + static void CopyColumnList(const std::vector<CustomColumnBase*>& srcList, std::vector<CustomColumnBase*>& dstList, ColumnIndex index) + { + typedef CustomColumn<typename ColumnList::Head::ColumnType> Type; + Type* pColumn = new Type(((Type*)(srcList.at(index)))->GetColumnData()); + dstList.push_back(pColumn); + CustomRowUtil<typename ColumnList::Tail>::CopyColumnList(srcList, dstList, index + 1); + } + + static ColumnIndex GetColumnIndex(const std::string& columnName, ColumnIndex index) + { + if (ColumnList::Head::GetColumnName() == columnName) + return index; + + return CustomRowUtil<typename ColumnList::Tail>::GetColumnIndex(columnName, index + 1); + } + +template<typename Other> +friend class CustomRowUtil; +}; + +template<> +class __attribute__ ((visibility("hidden"))) CustomRowUtil<VcoreDPL::TypeListGuard> { +public: + static void MakeColumnList(std::vector<CustomColumnBase*>&) {} +private: + static void CopyColumnList(const std::vector<CustomColumnBase*>&, std::vector<CustomColumnBase*>&, ColumnIndex) {} + static ColumnIndex GetColumnIndex(const std::string&, ColumnIndex) { return -1; } + +template<typename Other> +friend class CustomRowUtil; +}; + +template<typename ColumnList> +class __attribute__ ((visibility("hidden"))) CustomRow { +private: + std::vector<CustomColumnBase*> m_columns; + +public: + CustomRow() + { + CustomRowUtil<ColumnList>::MakeColumnList(m_columns); + } + + CustomRow(const CustomRow& r) + { + CustomRowUtil<ColumnList>::CopyColumnList(r.m_columns, m_columns); + } + + virtual ~CustomRow() + { + while (!m_columns.empty()) + { + CustomColumnBase* pCustomColumn = m_columns.back(); + m_columns.pop_back(); + if (pCustomColumn) + delete pCustomColumn; + } + } + + template<typename ColumnType> + void SetColumnData(ColumnIndex columnIndex, ColumnType data) + { + typedef CustomColumn<ColumnType> Type; + Assert(columnIndex < m_columns.size()); + Type* pColumn = dynamic_cast<Type*>(m_columns.at(columnIndex)); + Assert(pColumn); + pColumn->SetColumnData(data); + } + + template<typename ColumnData> + typename ColumnData::ColumnType GetColumnData() + { + typedef CustomColumn<typename ColumnData::ColumnType> Type; + ColumnIndex index = CustomRowUtil<ColumnList>::GetColumnIndex(ColumnData::GetColumnName()); + Assert(index < m_columns.size()); + Type* pColumn = dynamic_cast<Type*>(m_columns.at(index)); + Assert(pColumn); + return pColumn->GetColumnData(); + } +}; + +template<typename CustomRow, typename ColumnType> +void SetColumnData(CustomRow& row, ColumnType columnData, ColumnIndex columnIndex) +{ + row.SetColumnData<ColumnType>(columnIndex, columnData); +} + +template<typename ColumnList, typename CustomRow> +class __attribute__ ((visibility("hidden"))) FillCustomRowUtil { +public: + static void FillCustomRow(CustomRow& row, DataCommand* command) + { + FillCustomRow(row, 0, command); + } + +private: + static void FillCustomRow(CustomRow& row, ColumnIndex columnIndex, DataCommand* command) + { + typename ColumnList::Head::ColumnType columnData; + columnData = GetColumnFromCommand<typename ColumnList::Head::ColumnType>(columnIndex, command); + SetColumnData<CustomRow, typename ColumnList::Head::ColumnType>(row, columnData, columnIndex); + FillCustomRowUtil<typename ColumnList::Tail, CustomRow>::FillCustomRow(row, columnIndex + 1, command); + } + +template<typename Other, typename OtherRow> +friend class FillCustomRowUtil; +}; + +template<typename CustomRow> +class __attribute__ ((visibility("hidden"))) FillCustomRowUtil<VcoreDPL::TypeListGuard, CustomRow> { +private: + static void FillCustomRow(CustomRow&, ColumnIndex, DataCommand *) + { /* do nothing, we're past the last element of column list */ } + +template<typename Other, typename OtherRow> +friend class FillCustomRowUtil; +}; + +template<typename ColumnList, typename Row> +class __attribute__ ((visibility("hidden"))) FillRowUtil { +public: + static void FillRow(Row& row, DataCommand *command) + { + FillRow(row, 0, command); + } + +private: + static void FillRow(Row& row, ColumnIndex columnIndex, DataCommand *command) + { + typename ColumnList::Head::ColumnType rowField; + rowField = GetColumnFromCommand<typename ColumnList::Head::ColumnType>(columnIndex, command); + ColumnList::Head::SetRowField(row, rowField); + FillRowUtil<typename ColumnList::Tail, Row>::FillRow(row, columnIndex + 1, command); + } + +template<typename Other, typename OtherRow> +friend class FillRowUtil; +}; + +template<typename Row> +class __attribute__ ((visibility("hidden"))) FillRowUtil<VcoreDPL::TypeListGuard, Row> { +private: + static void FillRow(Row&, ColumnIndex, DataCommand *) + { /* do nothing, we're past the last element of column list */ } + +template<typename Other, typename OtherRow> +friend class FillRowUtil; +}; + +template<typename ColumnList> +class __attribute__ ((visibility("hidden"))) JoinUtil { +public: + static std::string GetColumnNames() + { + std::string result; + result = ColumnList::Head::GetTableName(); + result += "."; + result += ColumnList::Head::GetColumnName(); + if (ColumnList::Tail::Size > 0) + result += ", "; + + return result += JoinUtil<typename ColumnList::Tail>::GetColumnNames(); + } + + static std::string GetJoinTableName(const std::string& tableName) + { + std::string joinTableName = ColumnList::Head::GetTableName(); + if (tableName.find(joinTableName) == std::string::npos) + return joinTableName; + + return JoinUtil<typename ColumnList::Tail>::GetJoinTableName(tableName); + } +}; + +template<> +class __attribute__ ((visibility("hidden"))) JoinUtil<VcoreDPL::TypeListGuard> { +public: + static std::string GetColumnNames() { return ""; } + static std::string GetJoinTableName(std::string) { return ""; } +}; + +class Exception { +public: + DECLARE_EXCEPTION_TYPE(VcoreDPL::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, SelectReuseWithDifferentQuerySignature) + DECLARE_EXCEPTION_TYPE(Base, RowFieldNotInitialized) + DECLARE_EXCEPTION_TYPE(Base, EmptyUpdateStatement) +}; + +template<typename TableDefinition> +class __attribute__ ((visibility("hidden"))) Query +{ +protected: + explicit Query(IOrmInterface* interface) : + m_interface(interface), + m_command(NULL) + { + } + + virtual ~Query() + { + if (m_command == NULL) + return; + + TableDefinition::FreeTableDataCommand(m_command, m_interface); + } + + IOrmInterface* m_interface; + DataCommand *m_command; + std::string m_commandString; + ArgumentIndex m_bindArgumentIndex; +}; + +template<typename TableDefinition> +class __attribute__ ((visibility("hidden"))) QueryWithWhereClause : public Query<TableDefinition> +{ +protected: + ExpressionPtr m_whereExpression; + + void Prepare() + { + if ( !!m_whereExpression ) + { + this->m_commandString += " WHERE "; + this->m_commandString += m_whereExpression->GetString(); + } + } + + void Bind() + { + if ( !!m_whereExpression ) + { + this->m_bindArgumentIndex = m_whereExpression->BindTo( + this->m_command, this->m_bindArgumentIndex); + } + } + +public: + explicit QueryWithWhereClause(IOrmInterface* interface) : + Query<TableDefinition>(interface) + { + } + + template<typename Expression> + void Where(const Expression& expression) + { + DPL_CHECK_TYPE_INSTANTIABILITY(typename Expression::template ValidForTable<TableDefinition>::Yes); + if ( !!m_whereExpression && ( typeid(Expression) != typeid(*m_whereExpression) ) ) + { + std::ostringstream str; + str << "Current ORM implementation doesn't allow to reuse Select" + " instance with different query signature (particularly " + "WHERE on different column).\n"; + str << "Query: "; + str << this->m_commandString; + ThrowMsg(Exception::SelectReuseWithDifferentQuerySignature, + str.str()); + } + //TODO maybe don't make a copy here but just generate the string part of the query. + m_whereExpression.reset(new Expression(expression)); + } + +}; + +template<typename TableDefinition> +class __attribute__ ((visibility("hidden"))) Delete : public QueryWithWhereClause<TableDefinition> +{ +protected: + void Prepare() + { + if ( !this->m_command) + { + this->m_commandString = "DELETE FROM "; + this->m_commandString += TableDefinition::GetName(); + + QueryWithWhereClause<TableDefinition>::Prepare(); + + this->m_command = TableDefinition::AllocTableDataCommand( + this->m_commandString.c_str(), + Query<TableDefinition>::m_interface); + VcoreLogD("Prepared SQL command %s", this->m_commandString.c_str()); + } + } + + void Bind() + { + this->m_bindArgumentIndex = 1; + QueryWithWhereClause<TableDefinition>::Bind(); + } + +public: + explicit Delete(IOrmInterface *interface = NULL) : + QueryWithWhereClause<TableDefinition>(interface) + { + } + + void Execute() + { + Prepare(); + Bind(); + this->m_command->Step(); + this->m_command->Reset(); + } +}; + +namespace { +class BindVisitor { +private: + DataCommand *m_command; +public: + ArgumentIndex m_bindArgumentIndex; + + BindVisitor(DataCommand *command) : + m_command(command), + m_bindArgumentIndex(1) + {} + + template<typename ColumnType> + void Visit(const char*, const ColumnType& value, bool isSet) + { + if ( isSet ) + { + DataCommandUtils::BindArgument(m_command, m_bindArgumentIndex, value); + m_bindArgumentIndex++; + } + } +}; +} //anonymous namespace +template<typename TableDefinition> +class __attribute__ ((visibility("hidden"))) Insert : public Query<TableDefinition> +{ +public: + typedef typename TableDefinition::Row Row; + typedef VcoreDPL::DB::SqlConnection::RowID RowID; + +protected: + boost::optional<std::string> m_orClause; + Row m_row; + + class PrepareVisitor { + public: + std::string m_columnNames; + std::string m_values; + + template<typename ColumnType> + void Visit(const char* name, const ColumnType&, bool isSet) + { + if ( isSet ) + { + if ( !m_columnNames.empty() ) + { + m_columnNames += ", "; + m_values += ", "; + } + m_columnNames += name; + m_values += "?"; + } + } + }; + + void Prepare() + { + if ( !this->m_command ) + { + this->m_commandString = "INSERT "; + if ( !!m_orClause ) + { + this->m_commandString += " OR " + *m_orClause + " "; + } + this->m_commandString += "INTO "; + this->m_commandString += TableDefinition::GetName(); + + PrepareVisitor visitor; + m_row.VisitColumns(visitor); + + this->m_commandString += " ( " + visitor.m_columnNames + " ) "; + this->m_commandString += "VALUES ( " + visitor.m_values + " )"; + + VcoreLogD("Prepared SQL command %s", this->m_commandString.c_str()); + this->m_command = TableDefinition::AllocTableDataCommand( + this->m_commandString.c_str(), + Query<TableDefinition>::m_interface); + } + } + + void Bind() + { + BindVisitor visitor(this->m_command); + m_row.VisitColumns(visitor); + } + +public: + explicit Insert( + IOrmInterface* interface = NULL, + const boost::optional<std::string>& orClause = boost::optional<std::string>()) : + Query<TableDefinition>(interface), + m_orClause(orClause) + { + } + + void Values(const Row& row) + { + if ( this->m_command ) + { + if ( !row.IsSignatureMatching(m_row) ) + { + ThrowMsg(Exception::SelectReuseWithDifferentQuerySignature, + "Current ORM implementation doesn't allow to reuse Insert instance " + "with different query signature."); + } + } + m_row = row; + } + + RowID Execute() + { + Prepare(); + Bind(); + this->m_command->Step(); + + RowID result = TableDefinition::GetLastInsertRowID( + Query<TableDefinition>::m_interface); + + this->m_command->Reset(); + return result; + } +}; + +template<typename TableDefinition> +class __attribute__ ((visibility("hidden"))) Select : public QueryWithWhereClause<TableDefinition> +{ +public: + typedef typename TableDefinition::ColumnList ColumnList; + typedef typename TableDefinition::Row Row; + + typedef std::list<Row> RowList; +protected: + boost::optional<std::string> m_orderBy; + std::string m_JoinClause; + bool m_distinctResults; + + void Prepare(const char* selectColumnName) + { + if ( !this->m_command ) + { + this->m_commandString = "SELECT "; + if (m_distinctResults) + this->m_commandString += "DISTINCT "; + this->m_commandString += selectColumnName; + this->m_commandString += " FROM "; + this->m_commandString += TableDefinition::GetName(); + + this->m_commandString += m_JoinClause; + + QueryWithWhereClause<TableDefinition>::Prepare(); + + if ( !!m_orderBy ) + { + this->m_commandString += " ORDER BY " + *m_orderBy; + } + + this->m_command = TableDefinition::AllocTableDataCommand( + this->m_commandString.c_str(), + Query<TableDefinition>::m_interface); + + VcoreLogD("Prepared SQL command %s", this->m_commandString.c_str()); + } + } + + void Bind() + { + this->m_bindArgumentIndex = 1; + QueryWithWhereClause<TableDefinition>::Bind(); + } + + template<typename ColumnType> + ColumnType GetColumn(ColumnIndex columnIndex) + { + return GetColumnFromCommand<ColumnType>(columnIndex, this->m_command); + } + + Row GetRow() + { + Row row; + FillRowUtil<ColumnList, Row>::FillRow(row, this->m_command); + return row; + } + + template<typename ColumnList, typename CustomRow> + CustomRow GetCustomRow() + { + CustomRow row; + FillCustomRowUtil<ColumnList, CustomRow>::FillCustomRow(row, this->m_command); + return row; + } + +public: + + explicit Select(IOrmInterface *interface = NULL) : + QueryWithWhereClause<TableDefinition>(interface), + m_distinctResults(false) + { + } + + void Distinct() + { + m_distinctResults = true; + } + + template<typename CompoundType> + void OrderBy(const CompoundType&) + { + m_orderBy = OrderingUtils::OrderByInternal<typename CompoundType::Type>(); + } + + void OrderBy(const std::string & orderBy) //backward compatibility + { + m_orderBy = orderBy; + } + + void OrderBy(const char * orderBy) //backward compatibility + { + m_orderBy = std::string(orderBy); + } + + template<typename ColumnList, typename Expression> + void Join(const Expression& expression) { + std::string usedTableNames = TableDefinition::GetName(); + if (!m_JoinClause.empty()) + usedTableNames += m_JoinClause; + + this->m_JoinClause += " JOIN "; + this->m_JoinClause += JoinUtil<ColumnList>::GetJoinTableName(usedTableNames); + this->m_JoinClause += " ON "; + this->m_JoinClause += expression.GetString(); + } + + template<typename ColumnData> + typename ColumnData::ColumnType GetSingleValue() + { + Prepare(ColumnData::GetColumnName()); + Bind(); + this->m_command->Step(); + + typename ColumnData::ColumnType result = + GetColumn<typename ColumnData::ColumnType>(0); + + this->m_command->Reset(); + return result; + } + + //TODO return range - pair of custom iterators + template<typename ColumnData> + std::list<typename ColumnData::ColumnType> GetValueList() + { + Prepare(ColumnData::GetColumnName()); + Bind(); + + std::list<typename ColumnData::ColumnType> resultList; + + while (this->m_command->Step()) + resultList.push_back(GetColumn<typename ColumnData::ColumnType>(0)); + + this->m_command->Reset(); + return resultList; + } + + Row GetSingleRow() + { + Prepare("*"); + Bind(); + this->m_command->Step(); + + Row result = GetRow(); + + this->m_command->Reset(); + return result; + } + + //TODO return range - pair of custom iterators + RowList GetRowList() + { + Prepare("*"); + Bind(); + + RowList resultList; + + while (this->m_command->Step()) + resultList.push_back(GetRow()); + + this->m_command->Reset(); + return resultList; + } + + template<typename ColumnList, typename CustomRow> + CustomRow GetCustomSingleRow() + { + Prepare(JoinUtil<ColumnList>::GetColumnNames().c_str()); + Bind(); + this->m_command->Step(); + + CustomRow result = GetCustomRow<ColumnList, CustomRow>(); + + this->m_command->Reset(); + return result; + } + + template<typename ColumnList, typename CustomRow> + std::list<CustomRow> GetCustomRowList() + { + Prepare(JoinUtil<ColumnList>::GetColumnNames().c_str()); + Bind(); + + std::list<CustomRow> resultList; + + while (this->m_command->Step()) + resultList.push_back(GetCustomRow<ColumnList, CustomRow>()); + + this->m_command->Reset(); + return resultList; + } +}; + +template<typename TableDefinition> +class __attribute__ ((visibility("hidden"))) Update : public QueryWithWhereClause<TableDefinition> { +public: + typedef typename TableDefinition::Row Row; + +protected: + boost::optional<std::string> m_orClause; + Row m_row; + + class PrepareVisitor { + public: + std::string m_setExpressions; + + template<typename ColumnType> + void Visit(const char* name, const ColumnType&, bool isSet) + { + if ( isSet ) + { + if ( !m_setExpressions.empty() ) + { + m_setExpressions += ", "; + } + m_setExpressions += name; + m_setExpressions += " = "; + m_setExpressions += "?"; + } + } + }; + + void Prepare() + { + if ( !this->m_command ) + { + this->m_commandString = "UPDATE "; + if ( !!m_orClause ) + { + this->m_commandString += " OR " + *m_orClause + " "; + } + this->m_commandString += TableDefinition::GetName(); + this->m_commandString += " SET "; + + // got through row columns and values + PrepareVisitor visitor; + m_row.VisitColumns(visitor); + + if(visitor.m_setExpressions.empty()) + { + ThrowMsg(Exception::EmptyUpdateStatement, "No SET expressions in update statement"); + } + + this->m_commandString += visitor.m_setExpressions; + + // where + QueryWithWhereClause<TableDefinition>::Prepare(); + + this->m_command = TableDefinition::AllocTableDataCommand( + this->m_commandString.c_str(), + Query<TableDefinition>::m_interface); + VcoreLogD("Prepared SQL command %s", this->m_commandString.c_str()); + } + } + + void Bind() + { + BindVisitor visitor(this->m_command); + m_row.VisitColumns(visitor); + + this->m_bindArgumentIndex = visitor.m_bindArgumentIndex; + QueryWithWhereClause<TableDefinition>::Bind(); + } + + +public: + explicit Update(IOrmInterface *interface = NULL, + const boost::optional<std::string>& orClause = boost::optional<std::string>()) : + QueryWithWhereClause<TableDefinition>(interface), + m_orClause(orClause) + { + } + + void Values(const Row& row) + { + if ( this->m_command ) + { + if ( !row.IsSignatureMatching(m_row) ) + { + ThrowMsg(Exception::SelectReuseWithDifferentQuerySignature, + "Current ORM implementation doesn't allow to reuse Update instance " + "with different query signature."); + } + } + m_row = row; + } + + void Execute() + { + Prepare(); + Bind(); + this->m_command->Step(); + this->m_command->Reset(); + } +}; + +} //namespace ORM +} //namespace DB +} //namespace VcoreDPL + +#endif // DPL_ORM_H diff --git a/vcore/src/dpl/db/include/dpl/db/orm_generator.h b/vcore/src/dpl/db/include/dpl/db/orm_generator.h new file mode 100644 index 0000000..dd1b0dd --- /dev/null +++ b/vcore/src/dpl/db/include/dpl/db/orm_generator.h @@ -0,0 +1,382 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file orm_generator.h + * @author Bartosz Janiak (b.janiak@samsung.com) + * @version 1.0 + * @brief Macro definitions for generating the DPL-ORM table definitions from database definitions. + */ + +#ifndef ORM_GENERATOR_DATABASE_NAME +#error You need to define database name in ORM_GENERATOR_DATABASE_NAME define before you include orm_generator.h file +#endif + +#include <dpl/db/orm_interface.h> + +#define ORM_GENERATOR_DATABASE_NAME_LOCAL <ORM_GENERATOR_DATABASE_NAME> + +#ifdef DPL_ORM_GENERATOR_H +#warning orm_generator.h is included multiply times. Make sure it has different ORM_GENERATOR_DATABASE_NAME set. +#endif + +#define DPL_ORM_GENERATOR_H + + +#include <boost/optional.hpp> +#include <dpl/string.h> +#include <dpl/type_list.h> +#include <dpl/db/sql_connection.h> +#include <dpl/db/orm.h> +#include <dpl/assert.h> +#include <string> + +/* + +This is true only when exactly one db is available. + +#if (defined DECLARE_COLUMN) || (defined INT) || (defined TINYINT) || \ + (defined INTEGER) || (defined BIGINT) || defined(VARCHAR) || defined(TEXT) || \ + (defined SQL) || (defined TABLE_CONSTRAINTS) || (defined OPTIONAL) || \ + (defined DATABASE_START) || (defined DATABASE_END) || (defined CREATE_TABLE) || \ + (defined COLUMN) || (defined COLUMN_NOT_NULL) || (defined CREATE_TABLE_END) + +#error This file temporarily defines many macros with generic names. To avoid name clash please include \ + this file as early as possible. If this is not possible please report this problem to DPL developers. + +#endif +*/ + +namespace VcoreDPL { +namespace DB { +namespace ORM { + +// Global macros + +#define STRINGIFY(s) _str(s) +#define _str(s) #s +#define DECLARE_COLUMN(FIELD, TYPE) \ + struct FIELD { \ + typedef TYPE ColumnType; \ + static const char* GetTableName() { return GetName(); } \ + static const char* GetColumnName() { return STRINGIFY(FIELD); } \ + static void SetRowField(Row& row, const TYPE& _value) { row.Set_##FIELD(_value);} \ + }; + +#define INT int +#define TINYINT int +#define INTEGER int //TODO: should be long long? +#define BIGINT int //TODO: should be long long? +#define VARCHAR(x) VcoreDPL::String +#define TEXT VcoreDPL::String + +#define SQL(...) +#define TABLE_CONSTRAINTS(...) +#define OPTIONAL(type) boost::optional< type > +#define DATABASE_START(db_name) \ + namespace db_name \ + { \ + class ScopedTransaction \ + { \ + bool m_commited; \ + IOrmInterface *m_interface; \ + \ + public: \ + ScopedTransaction(IOrmInterface *interface) : \ + m_commited(false), \ + m_interface(interface) \ + { \ + Assert(interface != NULL); \ + m_interface->TransactionBegin(); \ + } \ + \ + ~ScopedTransaction() \ + { \ + if (!m_commited) \ + m_interface->TransactionRollback(); \ + } \ + \ + void Commit() \ + { \ + m_interface->TransactionCommit(); \ + m_commited = true; \ + } \ + }; + +#define DATABASE_END() } + +// RowBase ostream operator<< declaration + +#define CREATE_TABLE(name) \ + namespace name { \ + class RowBase; \ + inline std::ostream& operator<<(std::ostream& ostr, const RowBase& row); \ + } +#define COLUMN_NOT_NULL(name, type, ...) +#define COLUMN(name, type, ...) +#define CREATE_TABLE_END() + +#include ORM_GENERATOR_DATABASE_NAME_LOCAL + +#undef CREATE_TABLE +#undef COLUMN_NOT_NULL +#undef COLUMN +#undef CREATE_TABLE_END + +#undef DATABASE_START +#define DATABASE_START(db_name) namespace db_name { + +// RowBase class + +#define CREATE_TABLE(name) namespace name { class RowBase { \ + public: friend std::ostream& operator<<(std::ostream&, const RowBase&); +#define COLUMN_NOT_NULL(name, type, ...) \ + protected: type name; bool m_##name##_set; \ + public: void Set_##name(const type& _value) { \ + m_##name##_set = true; \ + this->name = _value; \ + } \ + public: type Get_##name() const { \ + if ( !m_##name##_set ) { \ + ThrowMsg(Exception::RowFieldNotInitialized, \ + "You tried to read a row field that hasn't been set yet."); \ + } \ + return name; \ + } + +#define COLUMN(name, type, ...) \ + protected: OPTIONAL(type) name; bool m_##name##_set; \ + public: void Set_##name(const OPTIONAL(type)& _value) { \ + m_##name##_set = true; \ + this->name = _value; \ + } \ + public: OPTIONAL(type) Get_##name() const { \ + if ( !m_##name##_set ) { \ + ThrowMsg(Exception::RowFieldNotInitialized, \ + "You tried to read a row field that hasn't been set yet."); \ + } \ + return name; \ + } +#define CREATE_TABLE_END() }; } + +#include ORM_GENERATOR_DATABASE_NAME_LOCAL + +#undef CREATE_TABLE +#undef COLUMN_NOT_NULL +#undef COLUMN +#undef CREATE_TABLE_END + +// RowBase ostream operator<< + +#define CREATE_TABLE(name) std::ostream& name::operator<<(std::ostream& ostr, const RowBase& row) { using ::operator<< ; ostr << STRINGIFY(name) << " ("; +#define COLUMN_NOT_NULL(name, type, ...) ostr << " '" << row.name << "'" ; +#define COLUMN(name, type, ...) ostr << " '" << row.name << "'" ; +#define CREATE_TABLE_END() ostr << " )" ; return ostr; } + +#include ORM_GENERATOR_DATABASE_NAME_LOCAL + +#undef CREATE_TABLE +#undef COLUMN_NOT_NULL +#undef COLUMN +#undef CREATE_TABLE_END + +// RowBase2 class (== RowBase + operator==) + +#define CREATE_TABLE(name) namespace name { class RowBase2 : public RowBase { \ + public: bool operator==(const RowBase2& row) const { return true +#define COLUMN_NOT_NULL(name, type, ...) && (this->name == row.name) +#define COLUMN(name, type, ...) && (this->name == row.name) +#define CREATE_TABLE_END() ; } }; } + +#include ORM_GENERATOR_DATABASE_NAME_LOCAL + +#undef CREATE_TABLE +#undef COLUMN_NOT_NULL +#undef COLUMN +#undef CREATE_TABLE_END + +// RowBase3 class (== RowBase2 + operator<) + +#define CREATE_TABLE(name) namespace name { class RowBase3 : public RowBase2 { \ + public: bool operator<(const RowBase3& row) const { +#define COLUMN_NOT_NULL(name, type, ...) if (this->name < row.name) { return true; } if (this->name > row.name) { return false; } +#define COLUMN(name, type, ...) if (this->name < row.name) { return true; } if (this->name > row.name) { return false; } +#define CREATE_TABLE_END() return false; } }; } + +#include ORM_GENERATOR_DATABASE_NAME_LOCAL + +#undef CREATE_TABLE +#undef COLUMN_NOT_NULL +#undef COLUMN +#undef CREATE_TABLE_END + +// RowBase4 class (== RowBase3 + IsSignatureMatching ) + +#define CREATE_TABLE(name) namespace name { class RowBase4 : public RowBase3 { \ + public: bool IsSignatureMatching(const RowBase4& row) const { return true +#define COLUMN_NOT_NULL(name, type, ...) && (this->m_##name##_set == row.m_##name##_set) +#define COLUMN(name, type, ...) && (this->m_##name##_set == row.m_##name##_set) +#define CREATE_TABLE_END() ; } }; } + +#include ORM_GENERATOR_DATABASE_NAME_LOCAL + +#undef CREATE_TABLE +#undef COLUMN_NOT_NULL +#undef COLUMN +#undef CREATE_TABLE_END + +// RowBase5 class (== RowBase4 + default constructor) + +#define CREATE_TABLE(name) namespace name { class RowBase5 : public RowBase4 { \ + public: RowBase5() { +#define COLUMN_NOT_NULL(name, type, ...) m_##name##_set = false; +#define COLUMN(name, type, ...) m_##name##_set = false; +#define CREATE_TABLE_END() } }; } + +#include ORM_GENERATOR_DATABASE_NAME_LOCAL + +#undef CREATE_TABLE +#undef COLUMN_NOT_NULL +#undef COLUMN +#undef CREATE_TABLE_END + +// Row class (== RowBase5 + ForEachColumn ) + +#define CREATE_TABLE(name) namespace name { class Row : public RowBase5 { \ + public: template<typename Visitor> \ + void VisitColumns(Visitor& visitor) const { +#define COLUMN_NOT_NULL(name, type, ...) visitor.Visit(STRINGIFY(name), this->name, this->m_##name##_set); +#define COLUMN(name, type, ...) visitor.Visit(STRINGIFY(name), this->name, this->m_##name##_set); +#define CREATE_TABLE_END() } }; } + +#include ORM_GENERATOR_DATABASE_NAME_LOCAL + +#undef CREATE_TABLE +#undef COLUMN_NOT_NULL +#undef COLUMN +#undef CREATE_TABLE_END + +// Field structure declarations + +#define CREATE_TABLE(name) namespace name { \ + static const char* GetName() { return STRINGIFY(name); } +#define COLUMN_NOT_NULL(name, type, ...) DECLARE_COLUMN(name, type) +#define COLUMN(name, type, ...) DECLARE_COLUMN(name, OPTIONAL(type)) +#define CREATE_TABLE_END() } + +#include ORM_GENERATOR_DATABASE_NAME_LOCAL + +#undef CREATE_TABLE +#undef COLUMN_NOT_NULL +#undef COLUMN +#undef CREATE_TABLE_END + +// ColumnList typedef + +#define CREATE_TABLE(name) namespace name { typedef VcoreDPL::TypeListDecl< +#define COLUMN_NOT_NULL(name, type, ...) name, +#define COLUMN(name, type, ...) name, +#define CREATE_TABLE_END() VcoreDPL::TypeListGuard>::Type ColumnList; } + +#include ORM_GENERATOR_DATABASE_NAME_LOCAL + +#undef CREATE_TABLE +#undef COLUMN_NOT_NULL +#undef COLUMN +#undef CREATE_TABLE_END + +// TableDefinition struct + +#define CREATE_TABLE(table_name) \ + namespace table_name { \ + struct TableDefinition { \ + typedef table_name::ColumnList ColumnList; \ + typedef table_name::Row Row; \ + static const char* GetName() { return STRINGIFY(table_name); } \ + static VcoreDPL::DB::SqlConnection::DataCommand *AllocTableDataCommand( \ + const std::string &statement, \ + IOrmInterface *interface) \ + { \ + Assert(interface != NULL); \ + return interface->AllocDataCommand(statement); \ + } \ + static void FreeTableDataCommand( \ + VcoreDPL::DB::SqlConnection::DataCommand *command, \ + IOrmInterface *interface) \ + { \ + Assert(interface != NULL); \ + interface->FreeDataCommand(command); \ + } \ + static VcoreDPL::DB::SqlConnection::RowID GetLastInsertRowID( \ + IOrmInterface *interface) \ + { \ + Assert(interface != NULL); \ + return interface->GetLastInsertRowID(); \ + } \ + }; \ + } + +#define COLUMN_NOT_NULL(name, type, ...) +#define COLUMN(name, type, ...) +#define CREATE_TABLE_END() + +#include ORM_GENERATOR_DATABASE_NAME_LOCAL + +#undef CREATE_TABLE +#undef COLUMN_NOT_NULL +#undef COLUMN +#undef CREATE_TABLE_END + +// Query typedefs + +#define CREATE_TABLE(name) \ + namespace name { \ + typedef Select<TableDefinition> Select; \ + typedef Insert<TableDefinition> Insert; \ + typedef Delete<TableDefinition> Delete; \ + typedef Update<TableDefinition> Update; \ + } +#define COLUMN_NOT_NULL(name, type, ...) +#define COLUMN(name, type, ...) +#define CREATE_TABLE_END() + +#include ORM_GENERATOR_DATABASE_NAME_LOCAL + +#undef CREATE_TABLE +#undef COLUMN_NOT_NULL +#undef COLUMN +#undef CREATE_TABLE_END + + +// Global undefs +#undef INT +#undef TINYINT +#undef INTEGER +#undef BIGINT +#undef VARCHAR +#undef TEXT + +#undef SQL +#undef TABLE_CONSTRAINTS +#undef OPTIONAL +#undef DATABASE_START +#undef DATABASE_END + +} //namespace ORM +} //namespace DB +} //namespace VcoreDPL + +#undef ORM_GENERATOR_DATABASE_NAME +#undef ORM_GENERATOR_DATABASE_NAME_LOCAL diff --git a/vcore/src/dpl/db/include/dpl/db/orm_interface.h b/vcore/src/dpl/db/include/dpl/db/orm_interface.h new file mode 100644 index 0000000..025c642 --- /dev/null +++ b/vcore/src/dpl/db/include/dpl/db/orm_interface.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file orm_interface.h + * @author Lukasz Marek (l.marek@samsung.com) + * @version 1.0 + */ + +#include <string> +#include <dpl/db/sql_connection.h> + +#ifndef DPL_ORM_INTERFACE_H +#define DPL_ORM_INTERFACE_H + +namespace VcoreDPL { +namespace DB { +namespace ORM { +class IOrmInterface +{ + public: + virtual ~IOrmInterface() {} + virtual VcoreDPL::DB::SqlConnection::DataCommand *AllocDataCommand( + const std::string &statement) = 0; + virtual void FreeDataCommand(VcoreDPL::DB::SqlConnection::DataCommand *command) + = 0; + virtual void TransactionBegin() = 0; + virtual void TransactionCommit() = 0; + virtual void TransactionRollback() = 0; + virtual VcoreDPL::DB::SqlConnection::RowID GetLastInsertRowID() = 0; +}; +} +} +} + +#endif diff --git a/vcore/src/dpl/db/include/dpl/db/orm_macros.h b/vcore/src/dpl/db/include/dpl/db/orm_macros.h new file mode 100644 index 0000000..a038523 --- /dev/null +++ b/vcore/src/dpl/db/include/dpl/db/orm_macros.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file orm_macros.h + * @author Bartosz Janiak (b.janiak@samsung.com) + * @version 1.0 + * @brief Macro definitions for generating the SQL input file from + * database definition. + */ + +//Do not include this file directly! It is used only for SQL code generation. + +#define CREATE_TABLE(name) CREATE TABLE name( +#define COLUMN(name, type, ...) name type __VA_ARGS__, +#define COLUMN_NOT_NULL(name, type, ...) name type __VA_ARGS__ not null, +#define SQL(...) __VA_ARGS__ +#define TABLE_CONSTRAINTS(...) __VA_ARGS__, +#define CREATE_TABLE_END() CHECK(1) ); +#define DATABASE_START(db_name) +#define DATABASE_END() + diff --git a/vcore/src/dpl/db/include/dpl/db/sql_connection.h b/vcore/src/dpl/db/include/dpl/db/sql_connection.h new file mode 100644 index 0000000..56714ee --- /dev/null +++ b/vcore/src/dpl/db/include/dpl/db/sql_connection.h @@ -0,0 +1,519 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file sql_connection.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of SQL connection + */ +#ifndef DPL_SQL_CONNECTION_H +#define DPL_SQL_CONNECTION_H + +#include <dpl/noncopyable.h> +#include <dpl/exception.h> +#include <dpl/availability.h> +#include <memory> +#include <boost/optional.hpp> +#include <dpl/string.h> +#include <dpl/log/vcore_log.h> +#include <sqlite3.h> +#include <string> +#include <dpl/assert.h> +#include <memory> +#include <stdint.h> + +namespace VcoreDPL { +namespace DB { +/** + * SQL connection class + */ +class SqlConnection +{ + public: + /** + * SQL Exception classes + */ + class Exception + { + public: + DECLARE_EXCEPTION_TYPE(VcoreDPL::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, SyntaxError) + DECLARE_EXCEPTION_TYPE(Base, ConnectionBroken) + DECLARE_EXCEPTION_TYPE(Base, InternalError) + DECLARE_EXCEPTION_TYPE(Base, InvalidColumn) + }; + + typedef int ColumnIndex; + typedef int ArgumentIndex; + + /* + * SQL processed data command + */ + class DataCommand : + private Noncopyable + { + private: + SqlConnection *m_masterConnection; + sqlite3_stmt *m_stmt; + + void CheckBindResult(int result); + void CheckColumnIndex(SqlConnection::ColumnIndex column); + + DataCommand(SqlConnection *connection, const char *buffer); + + friend class SqlConnection; + + public: + virtual ~DataCommand(); + + /** + * Bind null to the prepared statement argument + * + * @param position Index of argument to bind value to + */ + void BindNull(ArgumentIndex position); + + /** + * Bind int to the prepared statement argument + * + * @param position Index of argument to bind value to + * @param value Value to bind + */ + void BindInteger(ArgumentIndex position, int value); + + /** + * Bind int8_t to the prepared statement argument + * + * @param position Index of argument to bind value to + * @param value Value to bind + */ + void BindInt8(ArgumentIndex position, int8_t value); + + /** + * Bind int16 to the prepared statement argument + * + * @param position Index of argument to bind value to + * @param value Value to bind + */ + void BindInt16(ArgumentIndex position, int16_t value); + + /** + * Bind int32 to the prepared statement argument + * + * @param position Index of argument to bind value to + * @param value Value to bind + */ + void BindInt32(ArgumentIndex position, int32_t value); + + /** + * Bind int64 to the prepared statement argument + * + * @param position Index of argument to bind value to + * @param value Value to bind + */ + void BindInt64(ArgumentIndex position, int64_t value); + + /** + * Bind float to the prepared statement argument + * + * @param position Index of argument to bind value to + * @param value Value to bind + */ + void BindFloat(ArgumentIndex position, float value); + + /** + * Bind double to the prepared statement argument + * + * @param position Index of argument to bind value to + * @param value Value to bind + */ + void BindDouble(ArgumentIndex position, double value); + + /** + * Bind string to the prepared statement argument + * + * @param position Index of argument to bind value to + * @param value Value to bind + */ + void BindString(ArgumentIndex position, const char *value); + + /** + * Bind string to the prepared statement argument + * + * @param position Index of argument to bind value to + * @param value Value to bind + */ + void BindString(ArgumentIndex position, const String& value); + + /** + * Bind optional int to the prepared statement argument. + * If optional is not set null will be bound + * + * @param position Index of argument to bind value to + * @param value Value to bind + */ + void BindInteger(ArgumentIndex position, const boost::optional<int> &value); + + /** + * Bind optional int8 to the prepared statement argument. + * If optional is not set null will be bound + * + * @param position Index of argument to bind value to + * @param value Value to bind + */ + void BindInt8(ArgumentIndex position, const boost::optional<int8_t> &value); + + /** + * Bind optional int16 to the prepared statement argument. + * If optional is not set null will be bound + * + * @param position Index of argument to bind value to + * @param value Value to bind + */ + void BindInt16(ArgumentIndex position, const boost::optional<int16_t> &value); + + /** + * Bind optional int32 to the prepared statement argument. + * If optional is not set null will be bound + * + * @param position Index of argument to bind value to + * @param value Value to bind + */ + void BindInt32(ArgumentIndex position, const boost::optional<int32_t> &value); + + /** + * Bind optional int64 to the prepared statement argument. + * If optional is not set null will be bound + * + * @param position Index of argument to bind value to + * @param value Value to bind + */ + void BindInt64(ArgumentIndex position, const boost::optional<int64_t> &value); + + /** + * Bind optional float to the prepared statement argument. + * If optional is not set null will be bound + * + * @param position Index of argument to bind value to + * @param value Value to bind + */ + void BindFloat(ArgumentIndex position, const boost::optional<float> &value); + + /** + * Bind optional double to the prepared statement argument. + * If optional is not set null will be bound + * + * @param position Index of argument to bind value to + * @param value Value to bind + */ + void BindDouble(ArgumentIndex position, const boost::optional<double> &value); + + /** + * Bind optional string to the prepared statement argument. + * If optional is not set null will be bound + * + * @param position Index of argument to bind value to + * @param value Value to bind + */ + void BindString(ArgumentIndex position, const boost::optional<String> &value); + + /** + * Execute the prepared statement and/or move + * to the next row of the result + * + * @return True when there was a row returned + */ + bool Step(); + + /** + * Reset prepared statement's arguments + * All parameters will become null + */ + void Reset(); + + /** + * Checks whether column value is null + * + * @throw Exception::InvalidColumn + */ + bool IsColumnNull(ColumnIndex column); + + /** + * Get integer value from column in current row. + * + * @throw Exception::InvalidColumn + */ + int GetColumnInteger(ColumnIndex column); + + /** + * Get int8 value from column in current row. + * + * @throw Exception::InvalidColumn + */ + int8_t GetColumnInt8(ColumnIndex column); + + /** + * Get int16 value from column in current row. + * + * @throw Exception::InvalidColumn + */ + int16_t GetColumnInt16(ColumnIndex column); + /** + * Get int32 value from column in current row. + * + * @throw Exception::InvalidColumn + */ + int32_t GetColumnInt32(ColumnIndex column); + + /** + * Get int64 value from column in current row. + * + * @throw Exception::InvalidColumn + */ + int64_t GetColumnInt64(ColumnIndex column); + + /** + * Get float value from column in current row. + * + * @throw Exception::InvalidColumn + */ + float GetColumnFloat(ColumnIndex column); + + /** + * Get double value from column in current row. + * + * @throw Exception::InvalidColumn + */ + double GetColumnDouble(ColumnIndex column); + + /** + * Get string value from column in current row. + * + * @throw Exception::InvalidColumn + */ + std::string GetColumnString(ColumnIndex column); + + /** + * Get optional integer value from column in current row. + * + * @throw Exception::InvalidColumn + */ + boost::optional<int> GetColumnOptionalInteger(ColumnIndex column); + + /** + * Get optional int8 value from column in current row. + * + * @throw Exception::InvalidColumn + */ + boost::optional<int8_t> GetColumnOptionalInt8(ColumnIndex column); + + /** + * Get optional int16value from column in current row. + * + * @throw Exception::InvalidColumn + */ + boost::optional<int16_t> GetColumnOptionalInt16(ColumnIndex column); + + /** + * Get optional int32 value from column in current row. + * + * @throw Exception::InvalidColumn + */ + boost::optional<int32_t> GetColumnOptionalInt32(ColumnIndex column); + + /** + * Get optional int64 value from column in current row. + * + * @throw Exception::InvalidColumn + */ + boost::optional<int64_t> GetColumnOptionalInt64(ColumnIndex column); + + /** + * Get optional float value from column in current row. + * + * @throw Exception::InvalidColumn + */ + boost::optional<float> GetColumnOptionalFloat(ColumnIndex column); + + /** + * Get optional double value from column in current row. + * + * @throw Exception::InvalidColumn + */ + boost::optional<double> GetColumnOptionalDouble(ColumnIndex column); + + /** + * Get optional string value from column in current row. + * + * @throw Exception::InvalidColumn + */ + boost::optional<String> GetColumnOptionalString(ColumnIndex column); + }; + + // Move on copy semantics + typedef std::auto_ptr<DataCommand> DataCommandAutoPtr; + + // Open flags + class Flag + { + public: + enum Type + { + None = 1 << 0, + UseLucene = 1 << 1 + }; + + enum Option + { + RO = SQLITE_OPEN_NOMUTEX | SQLITE_OPEN_READONLY, + /** + * *TODO: please remove CREATE option from RW flag when all places + * that need that switched do CRW + */ + RW = SQLITE_OPEN_NOMUTEX | SQLITE_OPEN_READWRITE | + SQLITE_OPEN_CREATE, + CRW = RW | SQLITE_OPEN_CREATE + }; + }; + + // RowID + typedef sqlite3_int64 RowID; + + /** + * Synchronization object used to synchronize SQL connection + * to the same database across different threads and processes + */ + class SynchronizationObject + { + public: + virtual ~SynchronizationObject() {} + + /** + * Synchronizes SQL connection for multiple clients. + */ + virtual void Synchronize() = 0; + + /** + * Notify all waiting clients that the connection is no longer locked. + */ + virtual void NotifyAll() = 0; + }; + + protected: + sqlite3 *m_connection; + + // Options + bool m_usingLucene; + + // Stored data procedures + int m_dataCommandsCount; + + // Synchronization object + std::unique_ptr<SynchronizationObject> m_synchronizationObject; + + virtual void Connect(const std::string &address, + Flag::Type = Flag::None, Flag::Option = Flag::RO); + virtual void Disconnect(); + + void TurnOnForeignKeys(); + + static SynchronizationObject *AllocDefaultSynchronizationObject(); + + public: + /** + * Open SQL connection + * + * Synchronization is archieved by using provided asynchronization object. + * If synchronizationObject is set to NULL, so synchronization is performed. + * Ownership of the synchronization object is transfered to sql connection + * object. + * + * @param address Database file name + * @param flags Open flags + * @param synchronizationObject A synchronization object to use. + */ + explicit SqlConnection(const std::string &address = std::string(), + Flag::Type flags = Flag::None, + Flag::Option options = Flag::RO, + SynchronizationObject *synchronizationObject = + AllocDefaultSynchronizationObject()); + + /** + * Destructor + */ + virtual ~SqlConnection(); + + /** + * Execute SQL command without result + * + * @param format + * @param ... + */ + void ExecCommand(const char *format, ...) DPL_DEPRECATED_WITH_MESSAGE( + "To prevent sql injection do not use this \ + method for direct sql execution"); + + /** + * Execute BEGIN; command to start new transaction + * + */ + void BeginTransaction(); + + /** + * Execute ROLLBACK; command to discard changes made + * + */ + void RollbackTransaction(); + + /** + * Execute COMMIT; command to commit changes in database + * + */ + void CommitTransaction(); + + /** + * Prepare stored procedure + * + * @param format SQL statement + * @return Data command representing stored procedure + */ + DataCommandAutoPtr PrepareDataCommand(const char *format, ...); + + /** + * Check whether given table exists + * + * @param tableName Name of the table to check + * @return True if given table name exists + */ + bool CheckTableExist(const char *tableName); + + /** + * Get last insert operation new row id + * + * @return Row ID + */ + RowID GetLastInsertRowID() const; + + private: + int db_util_open_with_options(const char *pszFilePath, sqlite3 **ppDB, + int flags, const char *zVfs); + int db_util_close(sqlite3 *pDB); + +}; +} // namespace DB +} // namespace VcoreDPL + +#endif // DPL_SQL_CONNECTION_H diff --git a/vcore/src/dpl/db/include/dpl/db/thread_database_support.h b/vcore/src/dpl/db/include/dpl/db/thread_database_support.h new file mode 100644 index 0000000..5c82ae5 --- /dev/null +++ b/vcore/src/dpl/db/include/dpl/db/thread_database_support.h @@ -0,0 +1,300 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file thread_database_support.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk) + * @version 1.0 + * @brief This file contains the declaration of thread database support + */ + +#ifndef DPL_THREAD_DATABASE_SUPPORT_H +#define DPL_THREAD_DATABASE_SUPPORT_H + +#include <string> +#include <dpl/db/sql_connection.h> +#include <dpl/db/orm_interface.h> +#include <dpl/thread.h> +#include <dpl/assert.h> +#include <stdint.h> + +namespace VcoreDPL { +namespace DB { +/** + * Thread database support + * + * Associate database connection with thread lifecycle + * + */ + +class ThreadDatabaseSupport : + public VcoreDPL::DB::ORM::IOrmInterface +{ + private: + typedef VcoreDPL::DB::SqlConnection *SqlConnectionPtr; + typedef VcoreDPL::ThreadLocalVariable<SqlConnectionPtr> TLVSqlConnectionPtr; + typedef VcoreDPL::ThreadLocalVariable<size_t> TLVSizeT; + typedef VcoreDPL::ThreadLocalVariable<bool> TLVBool; + + TLVSqlConnectionPtr m_connection; + TLVBool m_linger; + TLVSizeT m_refCounter; + TLVSizeT m_transactionDepth; + TLVSizeT m_attachCount; + TLVBool m_transactionCancel; + std::string m_address; + VcoreDPL::DB::SqlConnection::Flag::Type m_flags; + + TLVSqlConnectionPtr &Connection() + { + return m_connection; + } + + TLVBool &Linger() + { + return m_linger; + } + + TLVSizeT &RefCounter() + { + return m_refCounter; + } + + TLVSizeT &TransactionDepth() + { + return m_transactionDepth; + } + + TLVSizeT &AttachCount() + { + return m_attachCount; + } + + TLVBool &TransactionCancel() + { + return m_transactionCancel; + } + + void CheckedConnectionDelete() + { + Assert(!Connection().IsNull()); + Assert(*Linger() == true); + + if (*RefCounter() > 0 || *AttachCount() > 0) { + return; + } + + // Destroy connection + VcoreLogD("Destroying thread database connection: %s", m_address.c_str()); + + delete *Connection(); + + // Blocking destroy + Connection().GuardValue(false); + Linger().GuardValue(false); + RefCounter().GuardValue(false); + TransactionCancel().GuardValue(false); + TransactionDepth().GuardValue(false); + AttachCount().GuardValue(false); + + Connection().Reset(); + Linger().Reset(); + RefCounter().Reset(); + TransactionCancel().Reset(); + TransactionDepth().Reset(); + AttachCount().Reset(); + } + + void TransactionUnref() + { + VcoreLogD("Unref transaction"); + + if (--(*TransactionDepth()) == 0) { + VcoreLogD("Transaction is finalized"); + + if (*TransactionCancel()) { + VcoreLogD("Transaction will be rolled back"); + (*Connection())->RollbackTransaction(); + } else { + VcoreLogD("Transaction will be commited"); + (*Connection())->CommitTransaction(); + } + } + } + + public: + ThreadDatabaseSupport(const std::string &address, + VcoreDPL::DB::SqlConnection::Flag::Type flags) : + m_address(address), + m_flags(flags) + {} + + virtual ~ThreadDatabaseSupport() + {} + + void AttachToThread( + VcoreDPL::DB::SqlConnection::Flag::Option options = + VcoreDPL::DB::SqlConnection::Flag::RO) + { + Linger() = false; + + if (!Connection().IsNull()) { + // Add reference + ++*AttachCount(); + return; + } + + // Initialize SQL connection described in traits + VcoreLogD("Attaching thread database connection: %s", m_address.c_str()); + + Connection() = new VcoreDPL::DB::SqlConnection( + m_address.c_str(), m_flags, options); + + RefCounter() = 0; + + AttachCount() = 1; + + //Init Transaction related variables + TransactionDepth() = 0; + TransactionCancel() = false; + + // Blocking destroy + Connection().GuardValue(true); + Linger().GuardValue(true); + RefCounter().GuardValue(true); + TransactionDepth().GuardValue(true); + AttachCount().GuardValue(true); + TransactionCancel().GuardValue(true); + } + + void DetachFromThread() + { + // Calling thread must support thread database connections + Assert(!Connection().IsNull()); + + // Remove reference + --*AttachCount(); + + if (*AttachCount() > 0) { + return; + } + + // It must not be in linger state yet + Assert(*Linger() == false); + + VcoreLogD("Detaching thread database connection: %s", m_address.c_str()); + + // Enter linger state + *Linger() = true; + + // Checked delete + CheckedConnectionDelete(); + } + + bool IsAttached() + { + return !AttachCount().IsNull() && *AttachCount() > 0; + } + + VcoreDPL::DB::SqlConnection::DataCommand *AllocDataCommand( + const std::string &statement) + { + // Calling thread must support thread database connections + Assert(!Connection().IsNull()); + + // Calling thread must not be in linger state + Assert(*Linger() == false); + + // Add reference + ++*RefCounter(); + + // Create new unmanaged data command + return (*Connection())->PrepareDataCommand(statement.c_str()).release(); + } + + void FreeDataCommand(VcoreDPL::DB::SqlConnection::DataCommand *command) + { + // Calling thread must support thread database connections + Assert(!Connection().IsNull()); + + // Delete data command + delete command; + + // Unreference SQL connection + --*RefCounter(); + + // If it is linger state, connection may be destroyed + if (*Linger() == true) { + CheckedConnectionDelete(); + } + } + + void TransactionBegin() + { + // Calling thread must support thread database connections + Assert(!Connection().IsNull()); + + VcoreLogD("Begin transaction"); + + // Addref transaction + if (++(*TransactionDepth()) == 1) { + VcoreLogD("Transaction is initialized"); + + TransactionCancel() = false; + (*Connection())->BeginTransaction(); + } + } + + void TransactionCommit() + { + // Calling thread must support thread database connections + Assert(!Connection().IsNull()); + + VcoreLogD("Commit transaction"); + + // Unref transation + TransactionUnref(); + } + + void TransactionRollback() + { + // Calling thread must support thread database connections + Assert(!Connection().IsNull()); + + // Cancel and unref transaction + TransactionCancel() = true; + TransactionUnref(); + } + + VcoreDPL::DB::SqlConnection::RowID GetLastInsertRowID() + { + // Calling thread must support thread database connections + Assert(!Connection().IsNull()); + + return (*Connection())->GetLastInsertRowID(); + } + + bool CheckTableExist(const char *name) + { + // Calling thread must support thread database connections + Assert(!Connection().IsNull()); + + return (*Connection())->CheckTableExist(name); + } +}; +} +} + +#endif // DPL_THREAD_DATABASE_SUPPORT_H diff --git a/vcore/src/dpl/db/src/naive_synchronization_object.cpp b/vcore/src/dpl/db/src/naive_synchronization_object.cpp new file mode 100644 index 0000000..f67694a --- /dev/null +++ b/vcore/src/dpl/db/src/naive_synchronization_object.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file naive_synchronization_object.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of SQL naive + * synchronization object + */ +#include <stddef.h> +#include <dpl/db/naive_synchronization_object.h> +#include <dpl/thread.h> + +namespace { + unsigned int seed = time(NULL); +} + +namespace VcoreDPL { +namespace DB { +void NaiveSynchronizationObject::Synchronize() +{ + // Sleep for about 10ms - 30ms + Thread::MiliSleep(10 + rand_r(&seed) % 20); +} + +void NaiveSynchronizationObject::NotifyAll() +{ + // No need to inform about anything +} +} // namespace DB +} // namespace VcoreDPL diff --git a/vcore/src/dpl/db/src/orm.cpp b/vcore/src/dpl/db/src/orm.cpp new file mode 100644 index 0000000..6e79d46 --- /dev/null +++ b/vcore/src/dpl/db/src/orm.cpp @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file orm.cpp + * @author Bartosz Janiak (b.janiak@samsung.com) + * @version 1.0 + * @brief Static definitions and function template specialziations of + * DPL-ORM. + */ +#include <stddef.h> +#include <dpl/db/orm.h> + +namespace VcoreDPL { +namespace DB { +namespace ORM { +namespace RelationTypes { +const char Equal[] = "="; +const char LessThan[] = "<"; +const char And[] = "AND"; +const char Or[] = "OR"; +const char Is[] = "IS"; +const char In[] = "IN"; +} + +template<> +int GetColumnFromCommand<int>(ColumnIndex columnIndex, + DataCommand *command) +{ + return command->GetColumnInteger(columnIndex); +} + +template<> +VcoreDPL::String GetColumnFromCommand<VcoreDPL::String>(ColumnIndex columnIndex, + DataCommand *command) +{ + return VcoreDPL::FromUTF8String(command->GetColumnString(columnIndex)); +} + +template<> +OptionalInteger GetColumnFromCommand<OptionalInteger>(ColumnIndex columnIndex, + DataCommand *command) +{ + return command->GetColumnOptionalInteger(columnIndex); +} + +template<> +OptionalString GetColumnFromCommand<OptionalString>(ColumnIndex columnIndex, + DataCommand *command) +{ + return command->GetColumnOptionalString(columnIndex); +} + +template<> +double GetColumnFromCommand<double>(ColumnIndex columnIndex, + DataCommand *command) +{ + return command->GetColumnDouble(columnIndex); +} + +void DataCommandUtils::BindArgument(DataCommand *command, + ArgumentIndex index, + int argument) +{ + command->BindInteger(index, argument); +} + +void DataCommandUtils::BindArgument(DataCommand *command, + ArgumentIndex index, + const OptionalInteger& argument) +{ + command->BindInteger(index, argument); +} + +void DataCommandUtils::BindArgument(DataCommand *command, + ArgumentIndex index, + const VcoreDPL::String& argument) +{ + command->BindString(index, argument); +} + +void DataCommandUtils::BindArgument(DataCommand *command, + ArgumentIndex index, + const OptionalString& argument) +{ + command->BindString(index, argument); +} +} +} +} diff --git a/vcore/src/dpl/db/src/sql_connection.cpp b/vcore/src/dpl/db/src/sql_connection.cpp new file mode 100644 index 0000000..9da8266 --- /dev/null +++ b/vcore/src/dpl/db/src/sql_connection.cpp @@ -0,0 +1,896 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file sql_connection.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of SQL connection + */ +#include <stddef.h> +#include <dpl/db/sql_connection.h> +#include <dpl/db/naive_synchronization_object.h> +#include <dpl/free_deleter.h> +#include <memory> +#include <dpl/noncopyable.h> +#include <dpl/assert.h> +#include <unistd.h> +#include <cstdio> +#include <cstdarg> + +namespace VcoreDPL { +namespace DB { +namespace // anonymous +{ +class ScopedNotifyAll : + public Noncopyable +{ + private: + SqlConnection::SynchronizationObject *m_synchronizationObject; + + public: + explicit ScopedNotifyAll( + SqlConnection::SynchronizationObject *synchronizationObject) : + m_synchronizationObject(synchronizationObject) + {} + + ~ScopedNotifyAll() + { + if (!m_synchronizationObject) { + return; + } + + VcoreLogD("Notifying after successful synchronize"); + m_synchronizationObject->NotifyAll(); + } +}; +} // namespace anonymous + +SqlConnection::DataCommand::DataCommand(SqlConnection *connection, + const char *buffer) : + m_masterConnection(connection), + m_stmt(NULL) +{ + Assert(connection != NULL); + + // Notify all after potentially synchronized database connection access + ScopedNotifyAll notifyAll(connection->m_synchronizationObject.get()); + + for (;;) { + int ret = sqlite3_prepare_v2(connection->m_connection, + buffer, strlen(buffer), + &m_stmt, NULL); + + if (ret == SQLITE_OK) { + VcoreLogD("Data command prepared successfuly"); + break; + } else if (ret == SQLITE_BUSY) { + VcoreLogD("Collision occurred while preparing SQL command"); + + // Synchronize if synchronization object is available + if (connection->m_synchronizationObject) { + VcoreLogD("Performing synchronization"); + connection->m_synchronizationObject->Synchronize(); + continue; + } + + // No synchronization object defined. Fail. + } + + // Fatal error + const char *error = sqlite3_errmsg(m_masterConnection->m_connection); + + VcoreLogD("SQL prepare data command failed"); + VcoreLogD(" Statement: %s", buffer); + VcoreLogD(" Error: %s", error); + + ThrowMsg(Exception::SyntaxError, error); + } + + VcoreLogD("Prepared data command: %s", buffer); + + // Increment stored data command count + ++m_masterConnection->m_dataCommandsCount; +} + +SqlConnection::DataCommand::~DataCommand() +{ + VcoreLogD("SQL data command finalizing"); + + if (sqlite3_finalize(m_stmt) != SQLITE_OK) { + VcoreLogD("Failed to finalize data command"); + } + + // Decrement stored data command count + --m_masterConnection->m_dataCommandsCount; +} + +void SqlConnection::DataCommand::CheckBindResult(int result) +{ + if (result != SQLITE_OK) { + const char *error = sqlite3_errmsg( + m_masterConnection->m_connection); + + VcoreLogD("Failed to bind SQL statement parameter"); + VcoreLogD(" Error: %s", error); + + ThrowMsg(Exception::SyntaxError, error); + } +} + +void SqlConnection::DataCommand::BindNull( + SqlConnection::ArgumentIndex position) +{ + CheckBindResult(sqlite3_bind_null(m_stmt, position)); + VcoreLogD("SQL data command bind null: [%i]", position); +} + +void SqlConnection::DataCommand::BindInteger( + SqlConnection::ArgumentIndex position, + int value) +{ + CheckBindResult(sqlite3_bind_int(m_stmt, position, value)); + VcoreLogD("SQL data command bind integer: [%i] -> %i", position, value); +} + +void SqlConnection::DataCommand::BindInt8( + SqlConnection::ArgumentIndex position, + int8_t value) +{ + CheckBindResult(sqlite3_bind_int(m_stmt, position, + static_cast<int>(value))); + VcoreLogD("SQL data command bind int8: [%i] -> %i", position, value); +} + +void SqlConnection::DataCommand::BindInt16( + SqlConnection::ArgumentIndex position, + int16_t value) +{ + CheckBindResult(sqlite3_bind_int(m_stmt, position, + static_cast<int>(value))); + VcoreLogD("SQL data command bind int16: [%i] -> %i", position, value); +} + +void SqlConnection::DataCommand::BindInt32( + SqlConnection::ArgumentIndex position, + int32_t value) +{ + CheckBindResult(sqlite3_bind_int(m_stmt, position, + static_cast<int>(value))); + VcoreLogD("SQL data command bind int32: [%i] -> %i", position, value); +} + +void SqlConnection::DataCommand::BindInt64( + SqlConnection::ArgumentIndex position, + int64_t value) +{ + CheckBindResult(sqlite3_bind_int64(m_stmt, position, + static_cast<sqlite3_int64>(value))); + VcoreLogD("SQL data command bind int64: [%i] -> %lli", position, value); +} + +void SqlConnection::DataCommand::BindFloat( + SqlConnection::ArgumentIndex position, + float value) +{ + CheckBindResult(sqlite3_bind_double(m_stmt, position, + static_cast<double>(value))); + VcoreLogD("SQL data command bind float: [%i] -> %f", position, value); +} + +void SqlConnection::DataCommand::BindDouble( + SqlConnection::ArgumentIndex position, + double value) +{ + CheckBindResult(sqlite3_bind_double(m_stmt, position, value)); + VcoreLogD("SQL data command bind double: [%i] -> %f", position, value); +} + +void SqlConnection::DataCommand::BindString( + SqlConnection::ArgumentIndex position, + const char *value) +{ + if (!value) { + BindNull(position); + return; + } + + // Assume that text may disappear + CheckBindResult(sqlite3_bind_text(m_stmt, position, + value, strlen(value), + SQLITE_TRANSIENT)); + + VcoreLogD("SQL data command bind string: [%i] -> %s", position, value); +} + +void SqlConnection::DataCommand::BindString( + SqlConnection::ArgumentIndex position, + const String &value) +{ + BindString(position, ToUTF8String(value).c_str()); +} + +void SqlConnection::DataCommand::BindInteger( + SqlConnection::ArgumentIndex position, + const boost::optional<int> &value) +{ + if (!value) { + BindNull(position); + } else { + BindInteger(position, *value); + } +} + +void SqlConnection::DataCommand::BindInt8( + SqlConnection::ArgumentIndex position, + const boost::optional<int8_t> &value) +{ + if (!value) { + BindNull(position); + } else { + BindInt8(position, *value); + } +} + +void SqlConnection::DataCommand::BindInt16( + SqlConnection::ArgumentIndex position, + const boost::optional<int16_t> &value) +{ + if (!value) { + BindNull(position); + } else { + BindInt16(position, *value); + } +} + +void SqlConnection::DataCommand::BindInt32( + SqlConnection::ArgumentIndex position, + const boost::optional<int32_t> &value) +{ + if (!value) { + BindNull(position); + } else { + BindInt32(position, *value); + } +} + +void SqlConnection::DataCommand::BindInt64( + SqlConnection::ArgumentIndex position, + const boost::optional<int64_t> &value) +{ + if (!value) { + BindNull(position); + } else { + BindInt64(position, *value); + } +} + +void SqlConnection::DataCommand::BindFloat( + SqlConnection::ArgumentIndex position, + const boost::optional<float> &value) +{ + if (!value) { + BindNull(position); + } else { + BindFloat(position, *value); + } +} + +void SqlConnection::DataCommand::BindDouble( + SqlConnection::ArgumentIndex position, + const boost::optional<double> &value) +{ + if (!value) { + BindNull(position); + } else { + BindDouble(position, *value); + } +} + +void SqlConnection::DataCommand::BindString( + SqlConnection::ArgumentIndex position, + const boost::optional<String> &value) +{ + if (!!value) { + BindString(position, ToUTF8String(*value).c_str()); + } else { + BindNull(position); + } +} + +bool SqlConnection::DataCommand::Step() +{ + // Notify all after potentially synchronized database connection access + ScopedNotifyAll notifyAll( + m_masterConnection->m_synchronizationObject.get()); + + for (;;) { + int ret = sqlite3_step(m_stmt); + + if (ret == SQLITE_ROW) { + VcoreLogD("SQL data command step ROW"); + return true; + } else if (ret == SQLITE_DONE) { + VcoreLogD("SQL data command step DONE"); + return false; + } else if (ret == SQLITE_BUSY) { + VcoreLogD("Collision occurred while executing SQL command"); + + // Synchronize if synchronization object is available + if (m_masterConnection->m_synchronizationObject) { + VcoreLogD("Performing synchronization"); + + m_masterConnection-> + m_synchronizationObject->Synchronize(); + + continue; + } + + // No synchronization object defined. Fail. + } + + // Fatal error + const char *error = sqlite3_errmsg(m_masterConnection->m_connection); + + VcoreLogD("SQL step data command failed"); + VcoreLogD(" Error: %s", error); + + ThrowMsg(Exception::InternalError, error); + } +} + +void SqlConnection::DataCommand::Reset() +{ + /* + * According to: + * http://www.sqlite.org/c3ref/stmt.html + * + * if last sqlite3_step command on this stmt returned an error, + * then sqlite3_reset will return that error, althought it is not an error. + * So sqlite3_reset allways succedes. + */ + sqlite3_reset(m_stmt); + + VcoreLogD("SQL data command reset"); +} + +void SqlConnection::DataCommand::CheckColumnIndex( + SqlConnection::ColumnIndex column) +{ + if (column < 0 || column >= sqlite3_column_count(m_stmt)) { + ThrowMsg(Exception::InvalidColumn, "Column index is out of bounds"); + } +} + +bool SqlConnection::DataCommand::IsColumnNull( + SqlConnection::ColumnIndex column) +{ + VcoreLogD("SQL data command get column type: [%i]", column); + CheckColumnIndex(column); + return sqlite3_column_type(m_stmt, column) == SQLITE_NULL; +} + +int SqlConnection::DataCommand::GetColumnInteger( + SqlConnection::ColumnIndex column) +{ + VcoreLogD("SQL data command get column integer: [%i]", column); + CheckColumnIndex(column); + int value = sqlite3_column_int(m_stmt, column); + VcoreLogD(" Value: %i", value); + return value; +} + +int8_t SqlConnection::DataCommand::GetColumnInt8( + SqlConnection::ColumnIndex column) +{ + VcoreLogD("SQL data command get column int8: [%i]", column); + CheckColumnIndex(column); + int8_t value = static_cast<int8_t>(sqlite3_column_int(m_stmt, column)); + VcoreLogD(" Value: %i", value); + return value; +} + +int16_t SqlConnection::DataCommand::GetColumnInt16( + SqlConnection::ColumnIndex column) +{ + VcoreLogD("SQL data command get column int16: [%i]", column); + CheckColumnIndex(column); + int16_t value = static_cast<int16_t>(sqlite3_column_int(m_stmt, column)); + VcoreLogD(" Value: %i", value); + return value; +} + +int32_t SqlConnection::DataCommand::GetColumnInt32( + SqlConnection::ColumnIndex column) +{ + VcoreLogD("SQL data command get column int32: [%i]", column); + CheckColumnIndex(column); + int32_t value = static_cast<int32_t>(sqlite3_column_int(m_stmt, column)); + VcoreLogD(" Value: %i", value); + return value; +} + +int64_t SqlConnection::DataCommand::GetColumnInt64( + SqlConnection::ColumnIndex column) +{ + VcoreLogD("SQL data command get column int64: [%i]", column); + CheckColumnIndex(column); + int64_t value = static_cast<int64_t>(sqlite3_column_int64(m_stmt, column)); + VcoreLogD(" Value: %lli", value); + return value; +} + +float SqlConnection::DataCommand::GetColumnFloat( + SqlConnection::ColumnIndex column) +{ + VcoreLogD("SQL data command get column float: [%i]", column); + CheckColumnIndex(column); + float value = static_cast<float>(sqlite3_column_double(m_stmt, column)); + VcoreLogD(" Value: %f", value); + return value; +} + +double SqlConnection::DataCommand::GetColumnDouble( + SqlConnection::ColumnIndex column) +{ + VcoreLogD("SQL data command get column double: [%i]", column); + CheckColumnIndex(column); + double value = sqlite3_column_double(m_stmt, column); + VcoreLogD(" Value: %f", value); + return value; +} + +std::string SqlConnection::DataCommand::GetColumnString( + SqlConnection::ColumnIndex column) +{ + VcoreLogD("SQL data command get column string: [%i]", column); + CheckColumnIndex(column); + + const char *value = reinterpret_cast<const char *>( + sqlite3_column_text(m_stmt, column)); + + VcoreLogD(" Value: %s", value); + + if (value == NULL) { + return std::string(); + } + + return std::string(value); +} + +boost::optional<int> SqlConnection::DataCommand::GetColumnOptionalInteger( + SqlConnection::ColumnIndex column) +{ + VcoreLogD("SQL data command get column optional integer: [%i]", column); + CheckColumnIndex(column); + if (sqlite3_column_type(m_stmt, column) == SQLITE_NULL) { + return boost::optional<int>(); + } + int value = sqlite3_column_int(m_stmt, column); + VcoreLogD(" Value: %i", value); + return boost::optional<int>(value); +} + +boost::optional<int8_t> SqlConnection::DataCommand::GetColumnOptionalInt8( + SqlConnection::ColumnIndex column) +{ + VcoreLogD("SQL data command get column optional int8: [%i]", column); + CheckColumnIndex(column); + if (sqlite3_column_type(m_stmt, column) == SQLITE_NULL) { + return boost::optional<int8_t>(); + } + int8_t value = static_cast<int8_t>(sqlite3_column_int(m_stmt, column)); + VcoreLogD(" Value: %i", value); + return boost::optional<int8_t>(value); +} + +boost::optional<int16_t> SqlConnection::DataCommand::GetColumnOptionalInt16( + SqlConnection::ColumnIndex column) +{ + VcoreLogD("SQL data command get column optional int16: [%i]", column); + CheckColumnIndex(column); + if (sqlite3_column_type(m_stmt, column) == SQLITE_NULL) { + return boost::optional<int16_t>(); + } + int16_t value = static_cast<int16_t>(sqlite3_column_int(m_stmt, column)); + VcoreLogD(" Value: %i", value); + return boost::optional<int16_t>(value); +} + +boost::optional<int32_t> SqlConnection::DataCommand::GetColumnOptionalInt32( + SqlConnection::ColumnIndex column) +{ + VcoreLogD("SQL data command get column optional int32: [%i]", column); + CheckColumnIndex(column); + if (sqlite3_column_type(m_stmt, column) == SQLITE_NULL) { + return boost::optional<int32_t>(); + } + int32_t value = static_cast<int32_t>(sqlite3_column_int(m_stmt, column)); + VcoreLogD(" Value: %i", value); + return boost::optional<int32_t>(value); +} + +boost::optional<int64_t> SqlConnection::DataCommand::GetColumnOptionalInt64( + SqlConnection::ColumnIndex column) +{ + VcoreLogD("SQL data command get column optional int64: [%i]", column); + CheckColumnIndex(column); + if (sqlite3_column_type(m_stmt, column) == SQLITE_NULL) { + return boost::optional<int64_t>(); + } + int64_t value = static_cast<int64_t>(sqlite3_column_int64(m_stmt, column)); + VcoreLogD(" Value: %lli", value); + return boost::optional<int64_t>(value); +} + +boost::optional<float> SqlConnection::DataCommand::GetColumnOptionalFloat( + SqlConnection::ColumnIndex column) +{ + VcoreLogD("SQL data command get column optional float: [%i]", column); + CheckColumnIndex(column); + if (sqlite3_column_type(m_stmt, column) == SQLITE_NULL) { + return boost::optional<float>(); + } + float value = static_cast<float>(sqlite3_column_double(m_stmt, column)); + VcoreLogD(" Value: %f", value); + return boost::optional<float>(value); +} + +boost::optional<double> SqlConnection::DataCommand::GetColumnOptionalDouble( + SqlConnection::ColumnIndex column) +{ + VcoreLogD("SQL data command get column optional double: [%i]", column); + CheckColumnIndex(column); + if (sqlite3_column_type(m_stmt, column) == SQLITE_NULL) { + return boost::optional<double>(); + } + double value = sqlite3_column_double(m_stmt, column); + VcoreLogD(" Value: %f", value); + return boost::optional<double>(value); +} + +boost::optional<String> SqlConnection::DataCommand::GetColumnOptionalString( + SqlConnection::ColumnIndex column) +{ + VcoreLogD("SQL data command get column optional string: [%i]", column); + CheckColumnIndex(column); + if (sqlite3_column_type(m_stmt, column) == SQLITE_NULL) { + return boost::optional<String>(); + } + const char *value = reinterpret_cast<const char *>( + sqlite3_column_text(m_stmt, column)); + VcoreLogD(" Value: %s", value); + String s = FromUTF8String(value); + return boost::optional<String>(s); +} + +void SqlConnection::Connect(const std::string &address, + Flag::Type type, + Flag::Option flag) +{ + if (m_connection != NULL) { + VcoreLogD("Already connected."); + return; + } + VcoreLogD("Connecting to DB: %s...", address.c_str()); + + // Connect to database + int result; + if (type & Flag::UseLucene) { + result = db_util_open_with_options( + address.c_str(), + &m_connection, + flag, + NULL); + + m_usingLucene = true; + VcoreLogD("Lucene index enabled"); + } else { + result = sqlite3_open_v2( + address.c_str(), + &m_connection, + flag, + NULL); + + m_usingLucene = false; + VcoreLogD("Lucene index disabled"); + } + + if (result == SQLITE_OK) { + VcoreLogD("Connected to DB"); + } else { + VcoreLogD("Failed to connect to DB!"); + ThrowMsg(Exception::ConnectionBroken, address); + } + + // Enable foreign keys + TurnOnForeignKeys(); +} + +void SqlConnection::Disconnect() +{ + if (m_connection == NULL) { + VcoreLogD("Already disconnected."); + return; + } + + VcoreLogD("Disconnecting from DB..."); + + // All stored data commands must be deleted before disconnect + AssertMsg(m_dataCommandsCount == 0, + "All stored procedures must be deleted" + " before disconnecting SqlConnection"); + + int result; + + if (m_usingLucene) { + result = db_util_close(m_connection); + } else { + result = sqlite3_close(m_connection); + } + + if (result != SQLITE_OK) { + const char *error = sqlite3_errmsg(m_connection); + VcoreLogD("SQL close failed"); + VcoreLogD(" Error: %s", error); + Throw(Exception::InternalError); + } + + m_connection = NULL; + + VcoreLogD("Disconnected from DB"); +} + +bool SqlConnection::CheckTableExist(const char *tableName) +{ + if (m_connection == NULL) { + VcoreLogD("Cannot execute command. Not connected to DB!"); + return false; + } + + DataCommandAutoPtr command = + PrepareDataCommand("select tbl_name from sqlite_master where name=?;"); + + command->BindString(1, tableName); + + if (!command->Step()) { + VcoreLogD("No matching records in table"); + return false; + } + + return command->GetColumnString(0) == tableName; +} + +SqlConnection::SqlConnection(const std::string &address, + Flag::Type flag, + Flag::Option option, + SynchronizationObject *synchronizationObject) : + m_connection(NULL), + m_usingLucene(false), + m_dataCommandsCount(0), + m_synchronizationObject(synchronizationObject) +{ + VcoreLogD("Opening database connection to: %s", address.c_str()); + + // Connect to DB + SqlConnection::Connect(address, flag, option); + + if (!m_synchronizationObject) { + VcoreLogD("No synchronization object defined"); + } +} + +SqlConnection::~SqlConnection() +{ + VcoreLogD("Closing database connection"); + + // Disconnect from DB + Try + { + SqlConnection::Disconnect(); + } + Catch(Exception::Base) + { + VcoreLogD("Failed to disconnect from database"); + } +} + +void SqlConnection::ExecCommand(const char *format, ...) +{ + if (m_connection == NULL) { + VcoreLogD("Cannot execute command. Not connected to DB!"); + return; + } + + if (format == NULL) { + VcoreLogD("Null query!"); + ThrowMsg(Exception::SyntaxError, "Null statement"); + } + + char *rawBuffer; + + va_list args; + va_start(args, format); + + if (vasprintf(&rawBuffer, format, args) == -1) { + rawBuffer = NULL; + } + + va_end(args); + + std::unique_ptr<char[],free_deleter> buffer(rawBuffer); + + if (!buffer) { + VcoreLogD("Failed to allocate statement string"); + return; + } + + VcoreLogD("Executing SQL command: %s", buffer.get()); + + // Notify all after potentially synchronized database connection access + ScopedNotifyAll notifyAll(m_synchronizationObject.get()); + + for (;;) { + char *errorBuffer; + + int ret = sqlite3_exec(m_connection, + buffer.get(), + NULL, + NULL, + &errorBuffer); + + std::string errorMsg; + + // Take allocated error buffer + if (errorBuffer != NULL) { + errorMsg = errorBuffer; + sqlite3_free(errorBuffer); + } + + if (ret == SQLITE_OK) { + return; + } + + if (ret == SQLITE_BUSY) { + VcoreLogD("Collision occurred while executing SQL command"); + + // Synchronize if synchronization object is available + if (m_synchronizationObject) { + VcoreLogD("Performing synchronization"); + m_synchronizationObject->Synchronize(); + continue; + } + + // No synchronization object defined. Fail. + } + + // Fatal error + VcoreLogD("Failed to execute SQL command. Error: %s", errorMsg.c_str()); + ThrowMsg(Exception::SyntaxError, errorMsg); + } +} + +SqlConnection::DataCommandAutoPtr SqlConnection::PrepareDataCommand( + const char *format, + ...) +{ + if (m_connection == NULL) { + VcoreLogD("Cannot execute data command. Not connected to DB!"); + return DataCommandAutoPtr(); + } + + char *rawBuffer; + + va_list args; + va_start(args, format); + + if (vasprintf(&rawBuffer, format, args) == -1) { + rawBuffer = NULL; + } + + va_end(args); + + std::unique_ptr<char[],free_deleter> buffer(rawBuffer); + + if (!buffer) { + VcoreLogD("Failed to allocate statement string"); + return DataCommandAutoPtr(); + } + + VcoreLogD("Executing SQL data command: %s", buffer.get()); + + return DataCommandAutoPtr(new DataCommand(this, buffer.get())); +} + +SqlConnection::RowID SqlConnection::GetLastInsertRowID() const +{ + return static_cast<RowID>(sqlite3_last_insert_rowid(m_connection)); +} + +void SqlConnection::TurnOnForeignKeys() +{ + ExecCommand("PRAGMA foreign_keys = ON;"); +} + +void SqlConnection::BeginTransaction() +{ + ExecCommand("BEGIN;"); +} + +void SqlConnection::RollbackTransaction() +{ + ExecCommand("ROLLBACK;"); +} + +void SqlConnection::CommitTransaction() +{ + ExecCommand("COMMIT;"); +} + +SqlConnection::SynchronizationObject * +SqlConnection::AllocDefaultSynchronizationObject() +{ + return new NaiveSynchronizationObject(); +} + +int SqlConnection::db_util_open_with_options(const char *pszFilePath, sqlite3 **ppDB, + int flags, const char *zVfs) +{ + int mode; + + if((pszFilePath == NULL) || (ppDB == NULL)) { + VcoreLogW("sqlite3 handle null error"); + return SQLITE_ERROR; + } + + mode = R_OK; + + if((geteuid() != 0) && (access(pszFilePath, mode))) { + if(errno == EACCES) { + VcoreLogD("file access permission error"); + return SQLITE_PERM; + } + } + + /* Open DB */ + int rc = sqlite3_open_v2(pszFilePath, ppDB, flags, zVfs); + if (SQLITE_OK != rc) { + VcoreLogE("sqlite3_open_v2 error(%d)",rc); + return rc; + } + + //rc = __db_util_open(*ppDB); + + return rc; +} + + +int SqlConnection::db_util_close(sqlite3 *pDB) +{ + char *pszErrorMsg = NULL; + + /* Close DB */ + int rc = sqlite3_close(pDB); + if (SQLITE_OK != rc) { + VcoreLogW("Fail to change journal mode: %s\n", pszErrorMsg); + sqlite3_free(pszErrorMsg); + return rc; + } + + return SQLITE_OK; +} + +} // namespace DB +} // namespace VcoreDPL diff --git a/vcore/src/vcore/SoupMessageSendAsync.cpp b/vcore/src/dpl/db/src/thread_database_support.cpp index d8bb132..101640f 100644 --- a/vcore/src/vcore/SoupMessageSendAsync.cpp +++ b/vcore/src/dpl/db/src/thread_database_support.cpp @@ -13,3 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +/* + * @file thread_database_support.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk) + * @version 1.0 + * @brief This file contains the definition of thread database support + */ +#include <stddef.h> +#include <dpl/db/thread_database_support.h>
\ No newline at end of file diff --git a/vcore/src/dpl/log/include/dpl/log/abstract_log_provider.h b/vcore/src/dpl/log/include/dpl/log/abstract_log_provider.h new file mode 100644 index 0000000..9061156 --- /dev/null +++ b/vcore/src/dpl/log/include/dpl/log/abstract_log_provider.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file abstract_log_provider.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of abstract log provider + */ +#ifndef DPL_ABSTRACT_LOG_PROVIDER_H +#define DPL_ABSTRACT_LOG_PROVIDER_H + +namespace VcoreDPL { +namespace Log { +class AbstractLogProvider +{ + public: + virtual ~AbstractLogProvider() {} + + virtual void Debug(const char *message, + const char *fileName, + int line, + const char *function) = 0; + virtual void Info(const char *message, + const char *fileName, + int line, + const char *function) = 0; + virtual void Warning(const char *message, + const char *fileName, + int line, + const char *function) = 0; + virtual void Error(const char *message, + const char *fileName, + int line, + const char *function) = 0; + virtual void Pedantic(const char *message, + const char *fileName, + int line, + const char *function) = 0; + + protected: + static const char *LocateSourceFileName(const char *filename); +}; +} +} // namespace VcoreDPL + +#endif // DPL_ABSTRACT_LOG_PROVIDER_H diff --git a/vcore/src/dpl/log/include/dpl/log/dlog_log_provider.h b/vcore/src/dpl/log/include/dpl/log/dlog_log_provider.h new file mode 100644 index 0000000..263d1e3 --- /dev/null +++ b/vcore/src/dpl/log/include/dpl/log/dlog_log_provider.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file dlog_log_provider.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of DLOG log provider + */ +#ifndef DPL_DLOG_LOG_PROVIDER_H +#define DPL_DLOG_LOG_PROVIDER_H + +#include <dpl/log/abstract_log_provider.h> +#include <dpl/scoped_free.h> +#include <string> + +namespace VcoreDPL { +namespace Log { +class DLOGLogProvider : + public AbstractLogProvider +{ + private: + VcoreDPL::ScopedFree<char> m_tag; + + static std::string FormatMessage(const char *message, + const char *filename, + int line, + const char *function); + + public: + DLOGLogProvider(); + virtual ~DLOGLogProvider(); + + virtual void Debug(const char *message, + const char *fileName, + int line, + const char *function); + virtual void Info(const char *message, + const char *fileName, + int line, + const char *function); + virtual void Warning(const char *message, + const char *fileName, + int line, + const char *function); + virtual void Error(const char *message, + const char *fileName, + int line, + const char *function); + virtual void Pedantic(const char *message, + const char *fileName, + int line, + const char *function); + + // Set global Tag according to DLOG + void SetTag(const char *tag); +}; +} +} // namespace VcoreDPL + +#endif // DPL_DLOG_LOG_PROVIDER_H diff --git a/vcore/src/dpl/log/include/dpl/log/log.h b/vcore/src/dpl/log/include/dpl/log/log.h new file mode 100644 index 0000000..43f4844 --- /dev/null +++ b/vcore/src/dpl/log/include/dpl/log/log.h @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file log.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of log system + */ +#ifndef DPL_LOG_H +#define DPL_LOG_H + +#include <dpl/singleton.h> +#include <dpl/noncopyable.h> +#include <dpl/log/abstract_log_provider.h> +#include <dpl/log/dlog_log_provider.h> +#include <dpl/log/old_style_log_provider.h> +#include <sstream> +#include <list> + +namespace VcoreDPL { +namespace Log { +/** + * DPL log system + * + * To switch logs into old style, export + * DPL_USE_OLD_STYLE_LOGS before application start + */ +class LogSystem : + private Noncopyable +{ + private: + typedef std::list<AbstractLogProvider *> AbstractLogProviderPtrList; + AbstractLogProviderPtrList m_providers; + + DLOGLogProvider *m_dlogProvider; + OldStyleLogProvider *m_oldStyleProvider; + + bool m_isLoggingEnabled; + + public: + bool IsLoggingEnabled() const; + LogSystem(); + virtual ~LogSystem(); + + /** + * Log debug message + */ + void Debug(const char *message, + const char *filename, + int line, + const char *function); + + /** + * Log info message + */ + void Info(const char *message, + const char *filename, + int line, + const char *function); + + /** + * Log warning message + */ + void Warning(const char *message, + const char *filename, + int line, + const char *function); + + /** + * Log error message + */ + void Error(const char *message, + const char *filename, + int line, + const char *function); + + /** + * Log pedantic message + */ + void Pedantic(const char *message, + const char *filename, + int line, + const char *function); + + /** + * Set default's DLOG provider Tag + */ + void SetTag(const char *tag); + + /** + * Add abstract provider to providers list + * + * @notice Ownership is transfered to LogSystem and deleted upon exit + */ + void AddProvider(AbstractLogProvider *provider); + + /** + * Remove abstract provider from providers list + */ + void RemoveProvider(AbstractLogProvider *provider); +}; + +/* + * Replacement low overhead null logging class + */ +class NullStream +{ + public: + NullStream() {} + + template <typename T> + NullStream& operator<<(const T&) + { + return *this; + } +}; + +/** + * Log system singleton + */ +typedef Singleton<LogSystem> LogSystemSingleton; +} +} // namespace VcoreDPL + +// +// Log support +// +// + +#ifdef DPL_LOGS_ENABLED + #define DPL_MACRO_FOR_LOGGING(message, function) \ + do \ + { \ + if (VcoreDPL::Log::LogSystemSingleton::Instance().IsLoggingEnabled()) \ + { \ + std::ostringstream platformLog; \ + platformLog << message; \ + VcoreDPL::Log::LogSystemSingleton::Instance().function( \ + platformLog.str().c_str(), \ + __FILE__, __LINE__, __FUNCTION__); \ + } \ + } while (0) +#else +/* avoid warnings about unused variables */ + #define DPL_MACRO_FOR_LOGGING(message, function) \ + do { \ + VcoreDPL::Log::NullStream ns; \ + ns << message; \ + } while (0) +#endif + +#define LogDebug(message) DPL_MACRO_FOR_LOGGING(message, Debug) +#define LogInfo(message) DPL_MACRO_FOR_LOGGING(message, Info) +#define LogWarning(message) DPL_MACRO_FOR_LOGGING(message, Warning) +#define LogError(message) DPL_MACRO_FOR_LOGGING(message, Error) +#define LogPedantic(message) DPL_MACRO_FOR_LOGGING(message, Pedantic) + +#endif // DPL_LOG_H diff --git a/vcore/src/dpl/log/include/dpl/log/old_style_log_provider.h b/vcore/src/dpl/log/include/dpl/log/old_style_log_provider.h new file mode 100644 index 0000000..fc14c7f --- /dev/null +++ b/vcore/src/dpl/log/include/dpl/log/old_style_log_provider.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file old_style_log_provider.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of old style log provider + */ +#ifndef DPL_OLD_STYLE_LOG_PROVIDER_H +#define DPL_OLD_STYLE_LOG_PROVIDER_H + +#include <dpl/log/abstract_log_provider.h> +#include <string> + +namespace VcoreDPL { +namespace Log { +class OldStyleLogProvider : + public AbstractLogProvider +{ + private: + bool m_showDebug; + bool m_showInfo; + bool m_showWarning; + bool m_showError; + bool m_showPedantic; + bool m_printStdErr; + + static std::string FormatMessage(const char *message, + const char *filename, + int line, + const char *function); + + public: + OldStyleLogProvider(bool showDebug, + bool showInfo, + bool showWarning, + bool showError, + bool showPedantic); + OldStyleLogProvider(bool showDebug, + bool showInfo, + bool showWarning, + bool showError, + bool showPedantic, + bool printStdErr); + virtual ~OldStyleLogProvider() {} + + virtual void Debug(const char *message, + const char *fileName, + int line, + const char *function); + virtual void Info(const char *message, + const char *fileName, + int line, + const char *function); + virtual void Warning(const char *message, + const char *fileName, + int line, + const char *function); + virtual void Error(const char *message, + const char *fileName, + int line, + const char *function); + virtual void Pedantic(const char *message, + const char *fileName, + int line, + const char *function); +}; +} +} // namespace VcoreDPL + +#endif // DPL_OLD_STYLE_LOG_PROVIDER_H diff --git a/vcore/src/dpl/log/include/dpl/log/vcore_log.h b/vcore/src/dpl/log/include/dpl/log/vcore_log.h new file mode 100644 index 0000000..01116bf --- /dev/null +++ b/vcore/src/dpl/log/include/dpl/log/vcore_log.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef VCORE_LOG_H +#define VCORE_LOG_H + +#ifdef LOG_TAG +#undef LOG_TAG +#endif +#define LOG_TAG "CERT_SVC_VCORE" + +#include <dlog.h> + +#define COLOR_ERROR "\033[38;5;160;1m" // bold red +#define COLOR_WARNING "\033[38;5;202;1m" // bold orange +#define COLOR_INFO "\033[38;5;243;1m" // bold light gray +#define COLOR_DEBUG "\033[38;5;243;0m" // normal light gray +#define COLOR_END "\033[0m" + +#define INTERNAL_SECURE_LOG __extension__ SECURE_SLOG +#define VCORE_LOG(priority, color, format, ...) \ +do { \ + INTERNAL_SECURE_LOG(priority, LOG_TAG, color format "%s", __VA_ARGS__); \ +} while(0) + + +/* + * Please use following macros + */ +#define VcoreLogD(...) VCORE_LOG(LOG_DEBUG, COLOR_DEBUG, __VA_ARGS__, COLOR_END) +#define VcoreLogI(...) VCORE_LOG(LOG_INFO, COLOR_INFO, __VA_ARGS__, COLOR_END) +#define VcoreLogW(...) VCORE_LOG(LOG_WARN, COLOR_WARNING, __VA_ARGS__, COLOR_END) +#define VcoreLogE(...) VCORE_LOG(LOG_ERROR, COLOR_ERROR, __VA_ARGS__, COLOR_END) + +#endif diff --git a/vcore/src/dpl/log/include/dpl/log/wrt_log.h b/vcore/src/dpl/log/include/dpl/log/wrt_log.h new file mode 100644 index 0000000..b0a3d2e --- /dev/null +++ b/vcore/src/dpl/log/include/dpl/log/wrt_log.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef VCORE_WRT_LOG_H +#define VCORE_WRT_LOG_H + +#ifdef LOG_TAG +#undef LOG_TAG +#endif +#define LOG_TAG "CERT_SVC_VCORE" + +#include <dlog.h> + +#define COLOR_ERROR "\033[38;5;160;1m" // bold red +#define COLOR_WARNING "\033[38;5;202;1m" // bold orange +#define COLOR_INFO "\033[38;5;243;1m" // bold light gray +#define COLOR_DEBUG "\033[38;5;243;0m" // normal light gray +#define COLOR_END "\033[0m" + +#define INTERNAL_SECURE_LOG __extension__ SECURE_SLOG +#define WRT_LOG(priority, color, format, ...) \ +do { \ + INTERNAL_SECURE_LOG(priority, LOG_TAG, color format "%s", __VA_ARGS__); \ +} while(0) + + +/* + * Please use following macros + */ +#define WrtLogD(...) WRT_LOG(LOG_DEBUG, COLOR_DEBUG, __VA_ARGS__, COLOR_END) +#define WrtLogI(...) WRT_LOG(LOG_INFO, COLOR_INFO, __VA_ARGS__, COLOR_END) +#define WrtLogW(...) WRT_LOG(LOG_WARN, COLOR_WARNING, __VA_ARGS__, COLOR_END) +#define WrtLogE(...) WRT_LOG(LOG_ERROR, COLOR_ERROR, __VA_ARGS__, COLOR_END) + +#endif diff --git a/vcore/src/dpl/log/src/abstract_log_provider.cpp b/vcore/src/dpl/log/src/abstract_log_provider.cpp new file mode 100644 index 0000000..05a80f7 --- /dev/null +++ b/vcore/src/dpl/log/src/abstract_log_provider.cpp @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file abstract_log_provider.cpp + * @author Pawel Sikorski (p.sikorski@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of abstract log provider + */ +#include <stddef.h> +#include <dpl/log/abstract_log_provider.h> +#include <cstring> + +namespace VcoreDPL { +namespace Log { +const char *AbstractLogProvider::LocateSourceFileName(const char *filename) +{ + const char *ptr = strrchr(filename, '/'); + return ptr != NULL ? ptr + 1 : filename; +} +} +} diff --git a/vcore/src/dpl/log/src/dlog_log_provider.cpp b/vcore/src/dpl/log/src/dlog_log_provider.cpp new file mode 100644 index 0000000..8958fe0 --- /dev/null +++ b/vcore/src/dpl/log/src/dlog_log_provider.cpp @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file dlog_log_provider.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of DLOG log provider + */ +#include <stddef.h> +#include <dpl/log/dlog_log_provider.h> +#include <cstring> +#include <sstream> +#include <dlog.h> + +#ifdef SECURE_LOG + #define INTERNAL_DLP_LOG_ SECURE_LOG +#else + #define INTERNAL_DLP_LOG_ LOG +#endif + +/* + * The __extension__ keyword in the following define is required because + * macros used here from dlog.h use non-standard extension that cause + * gcc to show unwanted warnings when compiling with -pedantic switch. + */ +#define INTERNAL_DLP_LOG __extension__ INTERNAL_DLP_LOG_ + +namespace VcoreDPL { +namespace Log { +std::string DLOGLogProvider::FormatMessage(const char *message, + const char *filename, + int line, + const char *function) +{ + std::ostringstream val; + + val << std::string("[") << + LocateSourceFileName(filename) << std::string(":") << line << + std::string("] ") << function << std::string("(): ") << message; + + return val.str(); +} + +DLOGLogProvider::DLOGLogProvider() +{} + +DLOGLogProvider::~DLOGLogProvider() +{} + +void DLOGLogProvider::SetTag(const char *tag) +{ + m_tag.Reset(strdup(tag)); +} + +void DLOGLogProvider::Debug(const char *message, + const char *filename, + int line, + const char *function) +{ + INTERNAL_DLP_LOG(LOG_DEBUG, m_tag.Get(), "%s", + FormatMessage(message, filename, line, function).c_str()); +} + +void DLOGLogProvider::Info(const char *message, + const char *filename, + int line, + const char *function) +{ + INTERNAL_DLP_LOG(LOG_INFO, m_tag.Get(), "%s", + FormatMessage(message, filename, line, function).c_str()); +} + +void DLOGLogProvider::Warning(const char *message, + const char *filename, + int line, + const char *function) +{ + INTERNAL_DLP_LOG(LOG_WARN, m_tag.Get(), "%s", + FormatMessage(message, filename, line, function).c_str()); +} + +void DLOGLogProvider::Error(const char *message, + const char *filename, + int line, + const char *function) +{ + INTERNAL_DLP_LOG(LOG_ERROR, m_tag.Get(), "%s", + FormatMessage(message, filename, line, function).c_str()); +} + +void DLOGLogProvider::Pedantic(const char *message, + const char *filename, + int line, + const char *function) +{ + INTERNAL_DLP_LOG(LOG_DEBUG, "DPL", "%s", + FormatMessage(message, filename, line, function).c_str()); +} +} +} // namespace VcoreDPL + +#undef INTERNAL_DLP_LOG +#undef INTERNAL_DLP_LOG_ + diff --git a/vcore/src/dpl/log/src/log.cpp b/vcore/src/dpl/log/src/log.cpp new file mode 100644 index 0000000..283b849 --- /dev/null +++ b/vcore/src/dpl/log/src/log.cpp @@ -0,0 +1,222 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file log.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of log system + */ +#include <stddef.h> +#include <dpl/log/log.h> +#include <dpl/singleton_impl.h> + +IMPLEMENT_SINGLETON(VcoreDPL::Log::LogSystem) + +namespace VcoreDPL { +namespace Log { +namespace // anonymous +{ +const char *OLD_STYLE_LOGS_ENV_NAME = "DPL_USE_OLD_STYLE_LOGS"; +const char *OLD_STYLE_PEDANTIC_LOGS_ENV_NAME = + "DPL_USE_OLD_STYLE_PEDANTIC_LOGS"; +const char *OLD_STYLE_LOGS_MASK_ENV_NAME = "DPL_USE_OLD_STYLE_LOGS_MASK"; +const char *DPL_LOG_OFF = "DPL_LOG_OFF"; +} // namespace anonymous + +bool LogSystem::IsLoggingEnabled() const +{ + return m_isLoggingEnabled; +} + +LogSystem::LogSystem() : + m_dlogProvider(NULL), + m_oldStyleProvider(NULL), + m_isLoggingEnabled(!getenv(DPL_LOG_OFF)) +{ + bool oldStyleLogs = false; + bool oldStyleDebugLogs = true; + bool oldStyleInfoLogs = true; + bool oldStyleWarningLogs = true; + bool oldStyleErrorLogs = true; + bool oldStylePedanticLogs = false; + + // Check environment settings about pedantic logs + const char *value = getenv(OLD_STYLE_LOGS_ENV_NAME); + + if (value != NULL && !strcmp(value, "1")) { + oldStyleLogs = true; + } + + value = getenv(OLD_STYLE_PEDANTIC_LOGS_ENV_NAME); + + if (value != NULL && !strcmp(value, "1")) { + oldStylePedanticLogs = true; + } + + value = getenv(OLD_STYLE_LOGS_MASK_ENV_NAME); + + if (value != NULL) { + size_t len = strlen(value); + + if (len >= 1) { + if (value[0] == '0') { + oldStyleDebugLogs = false; + } else if (value[0] == '1') { + oldStyleDebugLogs = true; + } + } + + if (len >= 2) { + if (value[1] == '0') { + oldStyleInfoLogs = false; + } else if (value[1] == '1') { + oldStyleInfoLogs = true; + } + } + + if (len >= 3) { + if (value[2] == '0') { + oldStyleWarningLogs = false; + } else if (value[2] == '1') { + oldStyleWarningLogs = true; + } + } + + if (len >= 4) { + if (value[3] == '0') { + oldStyleErrorLogs = false; + } else if (value[3] == '1') { + oldStyleErrorLogs = true; + } + } + } + + // Setup default DLOG and old style logging + if (oldStyleLogs) { + // Old style + m_oldStyleProvider = new OldStyleLogProvider(oldStyleDebugLogs, + oldStyleInfoLogs, + oldStyleWarningLogs, + oldStyleErrorLogs, + oldStylePedanticLogs); + AddProvider(m_oldStyleProvider); + } else { + // DLOG + m_dlogProvider = new DLOGLogProvider(); + AddProvider(m_dlogProvider); + } +} + +LogSystem::~LogSystem() +{ + // Delete all providers + for (AbstractLogProviderPtrList::iterator iterator = m_providers.begin(); + iterator != m_providers.end(); + ++iterator) + { + delete *iterator; + } + + m_providers.clear(); + + // And even default providers + m_dlogProvider = NULL; + m_oldStyleProvider = NULL; +} + +void LogSystem::SetTag(const char* tag) +{ + if (m_dlogProvider != NULL) { + m_dlogProvider->SetTag(tag); + } +} + +void LogSystem::AddProvider(AbstractLogProvider *provider) +{ + m_providers.push_back(provider); +} + +void LogSystem::RemoveProvider(AbstractLogProvider *provider) +{ + m_providers.remove(provider); +} + +void LogSystem::Debug(const char *message, + const char *filename, + int line, + const char *function) +{ + for (AbstractLogProviderPtrList::iterator iterator = m_providers.begin(); + iterator != m_providers.end(); + ++iterator) + { + (*iterator)->Debug(message, filename, line, function); + } +} + +void LogSystem::Info(const char *message, + const char *filename, + int line, + const char *function) +{ + for (AbstractLogProviderPtrList::iterator iterator = m_providers.begin(); + iterator != m_providers.end(); + ++iterator) + { + (*iterator)->Info(message, filename, line, function); + } +} + +void LogSystem::Warning(const char *message, + const char *filename, + int line, + const char *function) +{ + for (AbstractLogProviderPtrList::iterator iterator = m_providers.begin(); + iterator != m_providers.end(); + ++iterator) + { + (*iterator)->Warning(message, filename, line, function); + } +} + +void LogSystem::Error(const char *message, + const char *filename, + int line, + const char *function) +{ + for (AbstractLogProviderPtrList::iterator iterator = m_providers.begin(); + iterator != m_providers.end(); + ++iterator) + { + (*iterator)->Error(message, filename, line, function); + } +} + +void LogSystem::Pedantic(const char *message, + const char *filename, + int line, + const char *function) +{ + for (AbstractLogProviderPtrList::iterator iterator = m_providers.begin(); + iterator != m_providers.end(); + ++iterator) + { + (*iterator)->Pedantic(message, filename, line, function); + } +} +} +} // namespace VcoreDPL diff --git a/vcore/src/dpl/log/src/old_style_log_provider.cpp b/vcore/src/dpl/log/src/old_style_log_provider.cpp new file mode 100644 index 0000000..d13c66e --- /dev/null +++ b/vcore/src/dpl/log/src/old_style_log_provider.cpp @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file old_style_log_provider.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of old style log provider + */ +#include <stddef.h> +#include <dpl/log/old_style_log_provider.h> +#include <dpl/colors.h> +#include <cstdio> +#include <cstring> +#include <sstream> +#include <sys/time.h> +#include <unistd.h> + +namespace VcoreDPL { +namespace Log { +namespace // anonymous +{ +using namespace VcoreDPL::Colors::Text; +const char *DEBUG_BEGIN = GREEN_BEGIN; +const char *DEBUG_END = GREEN_END; +const char *INFO_BEGIN = CYAN_BEGIN; +const char *INFO_END = CYAN_END; +const char *ERROR_BEGIN = RED_BEGIN; +const char *ERROR_END = RED_END; +const char *WARNING_BEGIN = BOLD_GOLD_BEGIN; +const char *WARNING_END = BOLD_GOLD_END; +const char *PEDANTIC_BEGIN = PURPLE_BEGIN; +const char *PEDANTIC_END = PURPLE_END; + +std::string GetFormattedTime() +{ + timeval tv; + tm localNowTime; + + gettimeofday(&tv, NULL); + localtime_r(&tv.tv_sec, &localNowTime); + + char format[64]; + snprintf(format, + sizeof(format), + "%02i:%02i:%02i.%03i", + localNowTime.tm_hour, + localNowTime.tm_min, + localNowTime.tm_sec, + static_cast<int>(tv.tv_usec / 1000)); + return format; +} +} // namespace anonymous + +std::string OldStyleLogProvider::FormatMessage(const char *message, + const char *filename, + int line, + const char *function) +{ + std::ostringstream val; + + val << std::string("[") << GetFormattedTime() << std::string("] [") << + static_cast<unsigned long>(pthread_self()) << "/" << + static_cast<int>(getpid()) << std::string("] [") << + LocateSourceFileName(filename) << std::string(":") << line << + std::string("] ") << function << std::string("(): ") << message; + + return val.str(); +} + +OldStyleLogProvider::OldStyleLogProvider(bool showDebug, + bool showInfo, + bool showWarning, + bool showError, + bool showPedantic) : + m_showDebug(showDebug), + m_showInfo(showInfo), + m_showWarning(showWarning), + m_showError(showError), + m_showPedantic(showPedantic), + m_printStdErr(false) +{} + +OldStyleLogProvider::OldStyleLogProvider(bool showDebug, + bool showInfo, + bool showWarning, + bool showError, + bool showPedantic, + bool printStdErr) : + m_showDebug(showDebug), + m_showInfo(showInfo), + m_showWarning(showWarning), + m_showError(showError), + m_showPedantic(showPedantic), + m_printStdErr(printStdErr) +{} + +void OldStyleLogProvider::Debug(const char *message, + const char *filename, + int line, + const char *function) +{ + if (m_showDebug) { + if (m_printStdErr) { + fprintf(stderr, "%s%s%s\n", DEBUG_BEGIN, + FormatMessage(message, filename, line, + function).c_str(), DEBUG_END); + } else { + fprintf(stdout, "%s%s%s\n", DEBUG_BEGIN, + FormatMessage(message, filename, line, + function).c_str(), DEBUG_END); + } + } +} + +void OldStyleLogProvider::Info(const char *message, + const char *filename, + int line, + const char *function) +{ + if (m_showInfo) { + if (m_printStdErr) { + fprintf(stderr, "%s%s%s\n", INFO_BEGIN, + FormatMessage(message, filename, line, + function).c_str(), INFO_END); + } else { + fprintf(stdout, "%s%s%s\n", INFO_BEGIN, + FormatMessage(message, filename, line, + function).c_str(), INFO_END); + } + } +} + +void OldStyleLogProvider::Warning(const char *message, + const char *filename, + int line, + const char *function) +{ + if (m_showWarning) { + if (m_printStdErr) { + fprintf(stderr, "%s%s%s\n", WARNING_BEGIN, + FormatMessage(message, filename, line, + function).c_str(), WARNING_END); + } else { + fprintf(stdout, "%s%s%s\n", WARNING_BEGIN, + FormatMessage(message, filename, line, + function).c_str(), WARNING_END); + } + } +} + +void OldStyleLogProvider::Error(const char *message, + const char *filename, + int line, + const char *function) +{ + if (m_showError) { + if (m_printStdErr) { + fprintf(stderr, "%s%s%s\n", ERROR_BEGIN, + FormatMessage(message, filename, line, + function).c_str(), ERROR_END); + } else { + fprintf(stdout, "%s%s%s\n", ERROR_BEGIN, + FormatMessage(message, filename, line, + function).c_str(), ERROR_END); + } + } +} + +void OldStyleLogProvider::Pedantic(const char *message, + const char *filename, + int line, + const char *function) +{ + if (m_showPedantic) { + if (m_printStdErr) { + fprintf(stderr, "%s%s%s\n", PEDANTIC_BEGIN, + FormatMessage(message, filename, line, + function).c_str(), PEDANTIC_END); + } else { + fprintf(stdout, "%s%s%s\n", PEDANTIC_BEGIN, + FormatMessage(message, filename, line, + function).c_str(), PEDANTIC_END); + } + } +} +} +} // namespace VcoreDPL diff --git a/vcore/src/dpl/test/include/dpl/test/abstract_input_parser.h b/vcore/src/dpl/test/include/dpl/test/abstract_input_parser.h new file mode 100644 index 0000000..a7043ea --- /dev/null +++ b/vcore/src/dpl/test/include/dpl/test/abstract_input_parser.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file abstract_input_parser.h + * @author Tomasz Iwanek (t.iwanek@samsung.com) + * @brief Simple parser abstraction to be included into reader + */ + +#ifndef ABSTRACT_INPUT_PARSER_H +#define ABSTRACT_INPUT_PARSER_H + +#include <dpl/exception.h> + +#include <memory> + +namespace VcoreDPL { + +/** + * Abstract class of parser that produces some higher level abstraction + * basing on incoming tokens + */ +template<class Result, class Token> class AbstractInputParser +{ +public: + class Exception + { + public: + DECLARE_EXCEPTION_TYPE(VcoreDPL::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, ParserError) + }; + + typedef Result ResultType; + typedef Token TokenType; + + virtual ~AbstractInputParser() {} + + virtual void ConsumeToken(std::unique_ptr<Token> && token) = 0; + virtual bool IsStateValid() = 0; + virtual Result GetResult() const = 0; +}; + +} + +#endif diff --git a/vcore/src/dpl/test/include/dpl/test/abstract_input_reader.h b/vcore/src/dpl/test/include/dpl/test/abstract_input_reader.h new file mode 100644 index 0000000..cf7bd7b --- /dev/null +++ b/vcore/src/dpl/test/include/dpl/test/abstract_input_reader.h @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file abstract_input_reader.h + * @author Tomasz Iwanek (t.iwanek@samsung.com) + * @brief Simple output reader template + * + * This generic skeleton for parser which assume being composed from abstract two logical components: + * + * - parser, + * - tokenizer/lexer, + * which implements token flow logic. Logic of components may be arbitrary. See depending change for uses. + * + * Components are created at start time of reader (constructor which moves arguments). + * Virtuality (abstract base classes) are for enforcing same token type. + * I assumed it's more clear than writen static asserts in code enforcing this. + */ + +#ifndef ABSTRACT_INPUT_READER_H +#define ABSTRACT_INPUT_READER_H + +#include <memory> + +#include <dpl/test/abstract_input_tokenizer.h> +#include <dpl/test/abstract_input_parser.h> +#include <dpl/abstract_input.h> + +namespace VcoreDPL { + +/** + * Base reader class that can be used with any AbstractInput instance + * + * This class is encapsulation class for tokenizer and reader subelements + * and contains basic calculation pattern + * + * There a waste in form of virtuality for parser and tokenizer + * -> this for forcing same tokenT type in both components + */ +template<class ResultT, class TokenT> class AbstractInputReader +{ +public: + typedef ResultT TokenType; + typedef TokenT ResultType; + typedef AbstractInputParser<ResultT, TokenT> ParserBase; + typedef AbstractInputTokenizer<TokenT> TokenizerBase; + + class Exception + { + public: + typedef typename TokenizerBase::Exception::TokenizerError TokenizerError; + typedef typename ParserBase::Exception::ParserError ParserError; + }; + + AbstractInputReader(std::shared_ptr<AbstractInput> ia, + std::unique_ptr<ParserBase> && parser, + std::unique_ptr<TokenizerBase> && tokenizer) + : m_parser(std::move(parser)), m_tokenizer(std::move(tokenizer)) + { + m_tokenizer->Reset(ia); + } + + virtual ~AbstractInputReader() {} + + ResultT ReadInput() + { + typedef typename Exception::TokenizerError TokenizerError; + typedef typename Exception::ParserError ParserError; + + while(true) + { + std::unique_ptr<TokenT> token = m_tokenizer->GetNextToken(); + if(!token) + { + if(!m_tokenizer->IsStateValid()) + { + ThrowMsg(TokenizerError, "Tokenizer error"); + } + if(!m_parser->IsStateValid()) + { + ThrowMsg(ParserError, "Parser error"); + } + + return m_parser->GetResult(); + } + m_parser->ConsumeToken(std::move(token)); + } + } + +protected: + std::unique_ptr<ParserBase> m_parser; + std::unique_ptr<TokenizerBase> m_tokenizer; +}; + +} + +#endif diff --git a/vcore/src/dpl/test/include/dpl/test/abstract_input_tokenizer.h b/vcore/src/dpl/test/include/dpl/test/abstract_input_tokenizer.h new file mode 100644 index 0000000..03e00a9 --- /dev/null +++ b/vcore/src/dpl/test/include/dpl/test/abstract_input_tokenizer.h @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file abstract_input_tokenizer.h + * @author Tomasz Iwanek (t.iwanek@samsung.com) + * @brief Simple tokenizer abstraction + */ + +#ifndef ABSTRACT_INPUT_TOKENIZER_H +#define ABSTRACT_INPUT_TOKENIZER_H + +#include <memory> +#include <string> + +#include <dpl/abstract_input.h> +#include <dpl/exception.h> + +namespace VcoreDPL { + +/** + * Tokenizer abstract base class + * + * This class is supposed to accept AbstractInput in constructor + * and produce tokens until end of source. If parsing ends in invalid state + * then IsStateValid() should return false + */ +template<class Token> class AbstractInputTokenizer +{ +public: + class Exception + { + public: + DECLARE_EXCEPTION_TYPE(VcoreDPL::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, TokenizerError) + }; + + typedef Token TokenType; + + AbstractInputTokenizer() {} + virtual ~AbstractInputTokenizer() {} + + /** + * @brief Reset resets data source + * @param wia AbstractWaitableInputAdapter instance + */ + virtual void Reset(std::shared_ptr<AbstractInput> wia) + { + m_input = wia; + } + + /** + * @brief GetNextToken + * + * Parses next token. + * Returns pointer to token + * @throw TokenizerError in condition of input source error + * If returned empty pointer IsStateValid() == true -> end of input + * IsStateValid() == false -> error + * + * @param token token to be set + * @return + */ + virtual std::unique_ptr<Token> GetNextToken() = 0; + virtual bool IsStateValid() = 0; + +protected: + std::shared_ptr<AbstractInput> m_input; +}; + +} + +#endif diff --git a/vcore/src/dpl/test/include/dpl/test/process_pipe.h b/vcore/src/dpl/test/include/dpl/test/process_pipe.h new file mode 100644 index 0000000..bfc124b --- /dev/null +++ b/vcore/src/dpl/test/include/dpl/test/process_pipe.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file process_pipe.h + * @author Tomasz Iwanek (t.iwanek@samsung.com) + * @version 1.0 + * @brief This file is the implementation pipe from process + */ +#ifndef PROCESS_PIPE_H +#define PROCESS_PIPE_H + +#include <dpl/file_input.h> +#include <dpl/exception.h> + +#include <cstdio> + +namespace VcoreDPL { + +class ProcessPipe : public FileInput +{ +public: + class Exception + { + public: + DECLARE_EXCEPTION_TYPE(VcoreDPL::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, DoubleOpen) + }; + + enum class PipeErrorPolicy + { + NONE, + OFF, + PIPE + }; + + explicit ProcessPipe(PipeErrorPolicy err = PipeErrorPolicy::NONE); + virtual ~ProcessPipe(); + + void Open(const std::string &command); + void Close(); + +private: + FILE * m_file; + PipeErrorPolicy m_errPolicy; +}; + +} + +#endif // PROCESS_PIPE_H diff --git a/vcore/src/dpl/test/include/dpl/test/test_results_collector.h b/vcore/src/dpl/test/include/dpl/test/test_results_collector.h new file mode 100644 index 0000000..5d86ef6 --- /dev/null +++ b/vcore/src/dpl/test/include/dpl/test/test_results_collector.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file test_results_collector.h + * @author Lukasz Wrzosek (l.wrzosek@samsung.com) + * @version 1.0 + * @brief Header file with declaration of TestResultsCollectorBase + */ + +#ifndef DPL_TEST_RESULTS_COLLECTOR_H +#define DPL_TEST_RESULTS_COLLECTOR_H + +#include <dpl/noncopyable.h> +#include <dpl/availability.h> +#include <vector> +#include <list> +#include <map> +#include <string> +#include <memory> + +namespace VcoreDPL { +namespace Test { +class TestResultsCollectorBase; +typedef std::shared_ptr<TestResultsCollectorBase> +TestResultsCollectorBasePtr; + +class TestResultsCollectorBase : + private VcoreDPL::Noncopyable +{ + public: + typedef TestResultsCollectorBase* (*CollectorConstructorFunc)(); + typedef std::list<std::string> TestCaseIdList; + struct FailStatus + { + enum Type + { + NONE, + FAILED, + IGNORED, + INTERNAL + }; + }; + + virtual ~TestResultsCollectorBase() {} + + virtual bool Configure() + { + return true; + } + virtual void Start(int count) { DPL_UNUSED_PARAM(count); } + virtual void Finish() { } + virtual void CollectCurrentTestGroupName(const std::string& /*groupName*/) + {} + + virtual void CollectTestsCasesList(const TestCaseIdList& /*list*/) {} + virtual void CollectResult(const std::string& id, + const std::string& description, + const FailStatus::Type status = FailStatus::NONE, + const std::string& reason = "") = 0; + virtual std::string CollectorSpecificHelp() const + { + return ""; + } + virtual bool ParseCollectorSpecificArg (const std::string& /*arg*/) + { + return false; + } + + static TestResultsCollectorBase* Create(const std::string& name); + static void RegisterCollectorConstructor( + const std::string& name, + CollectorConstructorFunc + constructor); + static std::vector<std::string> GetCollectorsNames(); + + private: + typedef std::map<std::string, CollectorConstructorFunc> ConstructorsMap; + static ConstructorsMap m_constructorsMap; +}; +} +} + +#endif /* DPL_TEST_RESULTS_COLLECTOR_H */ diff --git a/vcore/src/dpl/test/include/dpl/test/test_runner.h b/vcore/src/dpl/test/include/dpl/test/test_runner.h new file mode 100644 index 0000000..3b980e1 --- /dev/null +++ b/vcore/src/dpl/test/include/dpl/test/test_runner.h @@ -0,0 +1,231 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file test_runner.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @author Lukasz Wrzosek (l.wrzosek@samsung.com) + * @version 1.0 + * @brief This file is the header file of test runner + */ +#ifndef DPL_TEST_RUNNER_H +#define DPL_TEST_RUNNER_H + +#include <dpl/singleton.h> +#include <dpl/availability.h> +#include <dpl/test/test_results_collector.h> + +#include <atomic> +#include <sstream> +#include <string> +#include <vector> +#include <list> +#include <set> +#include <map> + +namespace VcoreDPL { +namespace Test { +class TestRunner +{ + typedef std::map<std::string, TestResultsCollectorBasePtr> + TestResultsCollectors; + TestResultsCollectors m_collectors; + + std::string m_startTestId; + bool m_runIgnored; + + public: + TestRunner() + : m_runIgnored(false) + , m_allowChildLogs(false) + , m_terminate(false) + , m_totalAssertions(0) + {} + + typedef void (*TestCase)(); + + private: + struct TestCaseStruct + { + std::string name; + TestCase proc; + + bool operator <(const TestCaseStruct &other) const + { + return name < other.name; + } + + bool operator ==(const TestCaseStruct &other) const + { + return name == other.name; + } + + TestCaseStruct(const std::string &n, TestCase p) : + name(n), + proc(p) + {} + }; + + typedef std::list<TestCaseStruct> TestCaseStructList; + typedef std::map<std::string, TestCaseStructList> TestCaseGroupMap; + TestCaseGroupMap m_testGroups; + + typedef std::set<std::string> SelectedTestNameSet; + SelectedTestNameSet m_selectedTestNamesSet; + typedef std::set<std::string> SelectedTestGroupSet; + SelectedTestGroupSet m_selectedTestGroupSet; + std::string m_currentGroup; + + // Terminate without any logs. + // Some test requires to call fork function. + // Child process must not produce any logs and should die quietly. + bool m_allowChildLogs; + bool m_terminate; + + std::atomic<int> m_totalAssertions; + + void Banner(); + void InvalidArgs(const std::string& message = "Invalid arguments!"); + void Usage(); + + bool filterGroupsByXmls(const std::vector<std::string> & files); + bool filterByXML(std::map<std::string, bool> & casesMap); + void normalizeXMLTag(std::string& str, const std::string& testcase); + + enum Status { FAILED, IGNORED, PASS }; + + Status RunTestCase(const TestCaseStruct& testCase); + + void RunTests(); + + void CollectResult(const std::string& id, + const std::string& description, + const TestResultsCollectorBase::FailStatus::Type status + = TestResultsCollectorBase::FailStatus::NONE, + const std::string& reason = std::string()); + + public: + class TestFailed + { + private: + std::string m_message; + + public: + TestFailed() + {} + + //! \brief Failed test message creator + //! + //! \param[in] aTest string for tested expression + //! \param[in] aFile source file name + //! \param[in] aLine source file line + //! \param[in] aMessage error message + TestFailed(const char* aTest, + const char* aFile, + int aLine, + const std::string &aMessage); + + TestFailed(const std::string &message); + + std::string GetMessage() const + { + return m_message; + } + }; + + class Ignored + { + private: + std::string m_message; + + public: + Ignored() + {} + + Ignored(const std::string &message) : + m_message(message) + {} + + std::string GetMessage() const + { + return m_message; + } + }; + + void MarkAssertion(); + + void RegisterTest(const char *testName, TestCase proc); + void InitGroup(const char* name); + + int ExecTestRunner(int argc, char *argv[]); + typedef std::vector<std::string> ArgsList; + int ExecTestRunner(const ArgsList& args); + bool getRunIgnored() const; + // The runner will terminate as soon as possible (after current test). + void Terminate(); + bool GetAllowChildLogs(); +}; + +typedef VcoreDPL::Singleton<TestRunner> TestRunnerSingleton; +} +} // namespace VcoreDPL + +#define RUNNER_TEST_GROUP_INIT(GroupName) \ + static int Static##GroupName##Init() \ + { \ + VcoreDPL::Test::TestRunnerSingleton::Instance().InitGroup(#GroupName); \ + return 0; \ + } \ + const int DPL_UNUSED Static##GroupName##InitVar = \ + Static##GroupName##Init(); + +#define RUNNER_TEST(Proc) \ + void Proc(); \ + static int Static##Proc##Init() \ + { \ + VcoreDPL::Test::TestRunnerSingleton::Instance().RegisterTest(#Proc, &Proc);\ + return 0; \ + } \ + const int DPL_UNUSED Static##Proc##InitVar = Static##Proc##Init(); \ + void Proc() + +#define RUNNER_ASSERT_MSG(test, message) \ + do \ + { \ + VcoreDPL::Test::TestRunnerSingleton::Instance().MarkAssertion(); \ + \ + if (!(test)) \ + { \ + std::ostringstream assertMsg; \ + assertMsg << message; \ + throw VcoreDPL::Test::TestRunner::TestFailed(#test, \ + __FILE__, \ + __LINE__, \ + assertMsg.str()); \ + } \ + } while (0) + +#define RUNNER_ASSERT(test) RUNNER_ASSERT_MSG(test, "") + +#define RUNNER_FAIL RUNNER_ASSERT(false) + +#define RUNNER_IGNORED_MSG(message) \ + do { \ + std::ostringstream assertMsg; \ + assertMsg << message; \ + throw VcoreDPL::Test::TestRunner::Ignored( assertMsg.str() ); \ + } while (0) + +#endif // DPL_TEST_RUNNER_H diff --git a/vcore/src/dpl/test/include/dpl/test/test_runner_child.h b/vcore/src/dpl/test/include/dpl/test/test_runner_child.h new file mode 100644 index 0000000..86bf17e --- /dev/null +++ b/vcore/src/dpl/test/include/dpl/test/test_runner_child.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file test_runner_child.h + * @author Bartlomiej Grzelewski (b.grzelewski@samsung.com) + * @version 1.0 + * @brief This file is the header file of test runner + */ +#ifndef DPL_TEST_RUNNER_CHILD_H +#define DPL_TEST_RUNNER_CHILD_H + +#include <dpl/test/test_runner.h> + +namespace VcoreDPL { +namespace Test { + +class PipeWrapper : VcoreDPL::Noncopyable +{ + public: + enum Usage { + READONLY, + WRITEONLY + }; + + enum Status { + SUCCESS, + TIMEOUT, + ERROR + }; + + PipeWrapper(); + + bool isReady(); + + void setUsage(Usage usage); + + virtual ~PipeWrapper(); + + Status send(int code, std::string &message); + + Status receive(int &code, std::string &data, time_t deadline); + + void closeAll(); + + protected: + + std::string toBinaryString(int data); + + void closeHelp(int desc); + + Status writeHelp(const void *buffer, int size); + + Status readHelp(void *buf, int size, time_t deadline); + + static const int PIPE_CLOSED = -1; + + int m_pipefd[2]; +}; + +void RunChildProc(TestRunner::TestCase procChild); +} // namespace Test +} // namespace VcoreDPL + +#define RUNNER_CHILD_TEST(Proc) \ + void Proc(); \ + void Proc##Child(); \ + static int Static##Proc##Init() \ + { \ + VcoreDPL::Test::TestRunnerSingleton::Instance().RegisterTest(#Proc, &Proc); \ + return 0; \ + } \ + const int DPL_UNUSED Static##Proc##InitVar = Static##Proc##Init(); \ + void Proc(){ \ + VcoreDPL::Test::RunChildProc(&Proc##Child); \ + } \ + void Proc##Child() + +#endif // DPL_TEST_RUNNER_CHILD_H diff --git a/vcore/src/dpl/test/include/dpl/test/test_runner_multiprocess.h b/vcore/src/dpl/test/include/dpl/test/test_runner_multiprocess.h new file mode 100644 index 0000000..3fbf6f7 --- /dev/null +++ b/vcore/src/dpl/test/include/dpl/test/test_runner_multiprocess.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file test_runner_multiprocess.h + * @author Marcin Niesluchowski (m.niesluchow@samsung.com) + * @version 1.0 + * @brief This file is the header file of multiprocess test runner + */ +#ifndef DPL_TEST_RUNNER_MULTIPROCESS_H +#define DPL_TEST_RUNNER_MULTIPROCESS_H + +#include <dpl/test/test_runner_child.h> + +namespace VcoreDPL { +namespace Test { + +class SimplePipeWrapper : + public PipeWrapper +{ + public: + SimplePipeWrapper(); + + virtual ~SimplePipeWrapper(); + + Status send(std::string &message); + Status receive(std::string &data, bool &empty, time_t deadline); +}; + +void RunMultiProc(TestRunner::TestCase procMulti); +} // namespace Test +} // namespace VcoreDPL + +#define RUNNER_MULTIPROCESS_TEST(Proc) \ + void Proc(); \ + void Proc##Multi(); \ + static int Static##Proc##Init() \ + { \ + VcoreDPL::Test::TestRunnerSingleton::Instance().RegisterTest(#Proc, &Proc); \ + return 0; \ + } \ + const int DPL_UNUSED Static##Proc##InitVar = Static##Proc##Init(); \ + void Proc(){ \ + VcoreDPL::Test::RunMultiProc(&Proc##Multi); \ + } \ + void Proc##Multi() + +#endif // DPL_TEST_RUNNER_MULTIPROCESS_H diff --git a/vcore/src/dpl/test/include/dpl/test/value_separated_parser.h b/vcore/src/dpl/test/include/dpl/test/value_separated_parser.h new file mode 100644 index 0000000..d679610 --- /dev/null +++ b/vcore/src/dpl/test/include/dpl/test/value_separated_parser.h @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file value_separated_parser.h + * @author Tomasz Iwanek (t.iwanek@samsung.com) + * @brief Parser for some value seperated files/data + */ + +#ifndef VALUE_SEPARATED_PARSER_H +#define VALUE_SEPARATED_PARSER_H + +#include<string> +#include<vector> +#include<memory> + +#include<dpl/test/value_separated_tokens.h> +#include<dpl/test/abstract_input_parser.h> + +namespace VcoreDPL { + +typedef std::vector<std::string> VSLine; +typedef std::vector<VSLine> VSResult; +typedef std::shared_ptr<VSResult> VSResultPtr; + +/** + * Value Seperated parser + * + * Requires following policy class: + * + * template<VSResultPtr> + * struct CSVParserPolicy + * { + * static bool SkipLine(VSLine & ); + * static bool Validate(VSResultPtr& result); + * }; + */ +template<class ParserPolicy> +class VSParser : public AbstractInputParser<VSResultPtr, VSToken> +{ +public: + VSParser() : m_switchLine(true), m_result(new VSResult()) {} + + void ConsumeToken(std::unique_ptr<VSToken> && token) + { + if(m_switchLine) + { + m_result->push_back(VSLine()); + m_switchLine = false; + } + if(token->isNewLine()) + { + if(ParserPolicy::SkipLine(*m_result->rbegin())) + { + m_result->pop_back(); + } + m_switchLine = true; + } + else + { + m_result->rbegin()->push_back(token->cell()); + } + } + + bool IsStateValid() + { + return ParserPolicy::Validate(m_result); + } + + VSResultPtr GetResult() const + { + return m_result; + } + +private: + bool m_switchLine; + VSResultPtr m_result; +}; + +} + +#endif diff --git a/vcore/src/dpl/test/include/dpl/test/value_separated_policies.h b/vcore/src/dpl/test/include/dpl/test/value_separated_policies.h new file mode 100644 index 0000000..7c758a0 --- /dev/null +++ b/vcore/src/dpl/test/include/dpl/test/value_separated_policies.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file value_separated_policies.h + * @author Tomasz Iwanek (t.iwanek@samsung.com) + * @brief Example policy classes for some value seperated files/data + */ + +#ifndef VALUE_SEPARATED_POLICIES_H +#define VALUE_SEPARATED_POLICIES_H + +#include<string> +#include<vector> +#include<memory> + +namespace VcoreDPL { + +struct CSVTokenizerPolicy +{ + static std::string GetSeperators(); //cells in line are separated by given characters + static bool SkipEmpty(); //if cell is empty, shoudl I skip? + static void PrepareValue(std::string &); //transform each value + static bool TryAgainAtEnd(int); //read is nonblocking so dat may not be yet available, should I retry? +}; + +struct CSVParserPolicy +{ + static bool SkipLine(const std::vector<std::string> & ); //should I skip whole readline? + static bool Validate(std::shared_ptr<std::vector<std::vector<std::string> > > & result); //validate and adjust output data +}; + +} + +#endif diff --git a/vcore/src/dpl/test/include/dpl/test/value_separated_reader.h b/vcore/src/dpl/test/include/dpl/test/value_separated_reader.h new file mode 100644 index 0000000..a85eb1e --- /dev/null +++ b/vcore/src/dpl/test/include/dpl/test/value_separated_reader.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file value_separated_reader.h + * @author Tomasz Iwanek (t.iwanek@samsung.com) + * @brief Reader for some value seperated files/data + * + * This is parser for files containing lines with values seperated with custom charaters. + * Purpose of this is to parse output similar to csv and hide (no need for rewriting) + * buffers, reads, code errors. Result is two dimensional array. + * + * Reader is designed as class configured with policies classes: + * http://en.wikipedia.org/wiki/Policy-based_design + */ + +#ifndef VALUE_SEPARATED_READER_H +#define VALUE_SEPARATED_READER_H + +#include<dpl/test/abstract_input_reader.h> +#include<dpl/test/value_separated_tokenizer.h> +#include<dpl/test/value_separated_parser.h> +#include<dpl/test/value_separated_tokens.h> +#include<dpl/test/value_separated_policies.h> + +namespace VcoreDPL { + +/** + * Reader for input with values separated with defined characters + * + * Usage: + * - define both policies classes for defining and customize exact behaviour of reader + * - make typedef for VSReader template instance with your policies + * + */ +template<class ParserPolicy, class TokenizerPolicy> +class VSReader : public AbstractInputReader<VSResultPtr, VSToken> +{ +public: + VSReader(std::shared_ptr<AbstractInput> wia) + : AbstractInputReader<VSResultPtr, VSToken>(wia, + std::unique_ptr<ParserBase>(new VSParser<ParserPolicy>()), + std::unique_ptr<TokenizerBase>(new VSTokenizer<TokenizerPolicy>())) + {} +}; + +typedef VSReader<CSVParserPolicy, CSVTokenizerPolicy> CSVReader; + +} + +#endif diff --git a/vcore/src/dpl/test/include/dpl/test/value_separated_tokenizer.h b/vcore/src/dpl/test/include/dpl/test/value_separated_tokenizer.h new file mode 100644 index 0000000..d45823f --- /dev/null +++ b/vcore/src/dpl/test/include/dpl/test/value_separated_tokenizer.h @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file value_separated_tokenizer.h + * @author Tomasz Iwanek (t.iwanek@samsung.com) + * @brief Tokenizer for some value seperated files/data + */ + +#ifndef VALUE_SEPARATED_TOKENIZER_H +#define VALUE_SEPARATED_TOKENIZER_H + +#include<dpl/test/abstract_input_tokenizer.h> +#include<dpl/test/value_separated_tokens.h> +#include<dpl/binary_queue.h> + + +namespace VcoreDPL { + +/** + * Value Sperated tokenizer + * + * Requires following policy class: + * + * struct TokenizerPolicy + * { + * static std::string GetSeperators(); + * static bool SkipEmpty(); + * static void PrepareValue(std::string & value); + * }; + */ +template<class TokenizerPolicy> +class VSTokenizer : public AbstractInputTokenizer<VSToken> +{ +public: + VSTokenizer() {} + + void Reset(std::shared_ptr<AbstractInput> ia) + { + AbstractInputTokenizer<VSToken>::Reset(ia); + m_queue.Clear(); + m_finished = false; + m_newline = false; + } + + std::unique_ptr<VSToken> GetNextToken() + { + std::unique_ptr<VSToken> token; + std::string data; + char byte; + int tryNumber = 0; + + while(true) + { + //check if newline was approched + if(m_newline) + { + token.reset(new VSToken()); + m_newline = false; + return token; + } + + //read next data + if(m_queue.Empty()) + { + if(m_finished) + { + return token; + } + else + { + auto baptr = m_input->Read(4096); + if(baptr.get() == 0) + { + ThrowMsg(Exception::TokenizerError, "Input read failed"); + } + if(baptr->Empty()) + { + if(TokenizerPolicy::TryAgainAtEnd(tryNumber)) + { + ++tryNumber; + continue; + } + m_finished = true; + return token; + } + m_queue.AppendMoveFrom(*baptr); + } + } + + //process + m_queue.FlattenConsume(&byte, 1); //queue uses pointer to consume bytes, this do not causes reallocations + if(byte == '\n') + { + m_newline = true; + if(!data.empty() || !TokenizerPolicy::SkipEmpty()) + { + ProduceString(token, data); + return token; + } + } + else if(TokenizerPolicy::GetSeperators().find(byte) != std::string::npos) + { + if(!data.empty() || !TokenizerPolicy::SkipEmpty()) + { + ProduceString(token, data); + return token; + } + } + else + { + data += byte; + } + } + } + + bool IsStateValid() + { + if(!m_queue.Empty() && m_finished) return false; + return true; + } + +protected: + void ProduceString(std::unique_ptr<VSToken> & token, std::string & data) + { + TokenizerPolicy::PrepareValue(data); + token.reset(new VSToken(data)); + } + + BinaryQueue m_queue; + bool m_finished; + bool m_newline; +}; + +} + +#endif diff --git a/vcore/src/dpl/test/include/dpl/test/value_separated_tokens.h b/vcore/src/dpl/test/include/dpl/test/value_separated_tokens.h new file mode 100644 index 0000000..f0e9938 --- /dev/null +++ b/vcore/src/dpl/test/include/dpl/test/value_separated_tokens.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file value_separated_tokens.h + * @author Tomasz Iwanek (t.iwanek@samsung.com) + * @brief Token class for some value seperated files/data + */ + +#ifndef VALUE_SEPARATED_TOKENS_H +#define VALUE_SEPARATED_TOKENS_H + +#include<string> + +namespace VcoreDPL { + +class VSToken +{ +public: + VSToken(const std::string & c); + VSToken(); //newline token - no new class to simplify + const std::string & cell() const; + + bool isNewLine(); +private: + bool m_newline; + std::string m_cell; +}; + +} + +#endif diff --git a/vcore/src/dpl/test/src/process_pipe.cpp b/vcore/src/dpl/test/src/process_pipe.cpp new file mode 100644 index 0000000..11023f7 --- /dev/null +++ b/vcore/src/dpl/test/src/process_pipe.cpp @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file process_pipe.cpp + * @author Tomasz Iwanek (t.iwanek@samsung.com) + * @version 1.0 + * @brief This file is the implementation pipe from process + */ + +#include<dpl/test/process_pipe.h> +#include<dpl/log/vcore_log.h> + +namespace VcoreDPL { + +ProcessPipe::ProcessPipe(PipeErrorPolicy err) : m_file(NULL), m_errPolicy(err) +{ +} + +ProcessPipe::~ProcessPipe() +{ +} + +void ProcessPipe::Open(const std::string & command) +{ + if(m_file != NULL) + { + ThrowMsg(Exception::DoubleOpen, "Trying to open pipe second time. Close it first"); + } + + std::string stdErrRedirection; + switch(m_errPolicy) + { + case PipeErrorPolicy::NONE: break; + case PipeErrorPolicy::OFF: stdErrRedirection = " 2>/dev/null"; break; + case PipeErrorPolicy::PIPE: stdErrRedirection = " 2>&1"; break; + default: break; + } + + std::string fcommand = command + stdErrRedirection; + FILE * file = popen(fcommand.c_str(), "r"); + + // Throw an exception if an error occurred + if (file == NULL) { + ThrowMsg(FileInput::Exception::OpenFailed, fcommand); + } + + // Save new descriptor + m_file = file; + m_fd = fileno(m_file); + + VcoreLogD("Opened pipe: %s", fcommand.c_str()); +} + +void ProcessPipe::Close() +{ + if (m_fd == -1) { + return; + } + + if (pclose(m_file) == -1) { + Throw(FileInput::Exception::CloseFailed); + } + + m_fd = -1; + m_file = NULL; + + VcoreLogD("Closed pipe"); +} + +} diff --git a/vcore/src/dpl/test/src/test_results_collector.cpp b/vcore/src/dpl/test/src/test_results_collector.cpp new file mode 100644 index 0000000..e64da8a --- /dev/null +++ b/vcore/src/dpl/test/src/test_results_collector.cpp @@ -0,0 +1,984 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file test_results_collector.h + * @author Lukasz Wrzosek (l.wrzosek@samsung.com) + * @version 1.0 + * @brief Implementation file some concrete TestResulstsCollector + */ +#include <cstddef> +#include <dpl/test/test_results_collector.h> +#include <dpl/colors.h> +#include <dpl/assert.h> +#include <dpl/foreach.h> +#include <dpl/scoped_fclose.h> +#include <dpl/exception.h> +#include <dpl/errno_string.h> +#include <dpl/lexical_cast.h> +#include <dpl/availability.h> + +#include <string> +#include <string.h> +#include <cstdio> +#include <fstream> +#include <sstream> +#include <cstdlib> + +#define GREEN_RESULT_OK "[%s%s%s]\n", BOLD_GREEN_BEGIN, " OK ", \ + BOLD_GREEN_END + +namespace VcoreDPL { +namespace Test { +namespace { +const char *DEFAULT_HTML_FILE_NAME = "index.html"; +const char *DEFAULT_TAP_FILE_NAME = "results.tap"; +const char *DEFAULT_XML_FILE_NAME = "results.xml"; + +bool ParseCollectorFileArg(const std::string &arg, std::string &filename) +{ + const std::string argname = "--file="; + if (arg.find(argname) == 0 ) { + filename = arg.substr(argname.size()); + return true; + } + return false; +} + +class Statistic +{ + public: + Statistic() : + m_failed(0), + m_ignored(0), + m_passed(0), + m_count(0) + {} + + void AddTest(TestResultsCollectorBase::FailStatus::Type type) + { + ++m_count; + switch (type) { + case TestResultsCollectorBase::FailStatus::INTERNAL: + case TestResultsCollectorBase::FailStatus::FAILED: ++m_failed; + break; + case TestResultsCollectorBase::FailStatus::IGNORED: ++m_ignored; + break; + case TestResultsCollectorBase::FailStatus::NONE: ++m_passed; + break; + default: + Assert(false && "Bad FailStatus"); + } + } + + std::size_t GetTotal() const + { + return m_count; + } + std::size_t GetPassed() const + { + return m_passed; + } + std::size_t GetSuccesed() const + { + return m_passed; + } + std::size_t GetFailed() const + { + return m_failed; + } + std::size_t GetIgnored() const + { + return m_ignored; + } + float GetPassedOrIgnoredPercend() const + { + float passIgnoredPercent = + 100.0f * (static_cast<float>(m_passed) + + static_cast<float>(m_ignored)) + / static_cast<float>(m_count); + return passIgnoredPercent; + } + + private: + std::size_t m_failed; + std::size_t m_ignored; + std::size_t m_passed; + std::size_t m_count; +}; + +class ConsoleCollector : + public TestResultsCollectorBase +{ + public: + static TestResultsCollectorBase* Constructor(); + + private: + ConsoleCollector() {} + + virtual void CollectCurrentTestGroupName(const std::string& name) + { + printf("Starting group %s\n", name.c_str()); + m_currentGroup = name; + } + + virtual void Finish() + { + using namespace VcoreDPL::Colors::Text; + + // Show result + FOREACH(group, m_groupsStats) { + PrintStats(group->first, group->second); + } + PrintStats("All tests together", m_stats); + } + + virtual void CollectResult(const std::string& id, + const std::string& /*description*/, + const FailStatus::Type status = FailStatus::NONE, + const std::string& reason = "") + { + using namespace VcoreDPL::Colors::Text; + std::string tmp = "'" + id + "' ..."; + + printf("Running test case %-60s", tmp.c_str()); + switch (status) { + case TestResultsCollectorBase::FailStatus::NONE: + printf(GREEN_RESULT_OK); + break; + case TestResultsCollectorBase::FailStatus::FAILED: + PrintfErrorMessage(" FAILED ", reason, true); + break; + case TestResultsCollectorBase::FailStatus::IGNORED: + PrintfIgnoredMessage("Ignored ", reason, true); + break; + case TestResultsCollectorBase::FailStatus::INTERNAL: + PrintfErrorMessage("INTERNAL", reason, true); + break; + default: + Assert(false && "Bad status"); + } + m_stats.AddTest(status); + m_groupsStats[m_currentGroup].AddTest(status); + } + + void PrintfErrorMessage(const char* type, + const std::string& message, + bool verbosity) + { + using namespace VcoreDPL::Colors::Text; + if (verbosity) { + printf("[%s%s%s] %s%s%s\n", + BOLD_RED_BEGIN, + type, + BOLD_RED_END, + BOLD_YELLOW_BEGIN, + message.c_str(), + BOLD_YELLOW_END); + } else { + printf("[%s%s%s]\n", + BOLD_RED_BEGIN, + type, + BOLD_RED_END); + } + } + + void PrintfIgnoredMessage(const char* type, + const std::string& message, + bool verbosity) + { + using namespace VcoreDPL::Colors::Text; + if (verbosity) { + printf("[%s%s%s] %s%s%s\n", + CYAN_BEGIN, + type, + CYAN_END, + BOLD_GOLD_BEGIN, + message.c_str(), + BOLD_GOLD_END); + } else { + printf("[%s%s%s]\n", + CYAN_BEGIN, + type, + CYAN_END); + } + } + + void PrintStats(const std::string& title, const Statistic& stats) + { + using namespace VcoreDPL::Colors::Text; + printf("\n%sResults [%s]: %s\n", BOLD_GREEN_BEGIN, + title.c_str(), BOLD_GREEN_END); + printf("%s%s%3d%s\n", + CYAN_BEGIN, + "Total tests: ", + stats.GetTotal(), + CYAN_END); + printf(" %s%s%3d%s\n", + CYAN_BEGIN, + "Succeeded: ", + stats.GetPassed(), + CYAN_END); + printf(" %s%s%3d%s\n", + CYAN_BEGIN, + "Failed: ", + stats.GetFailed(), + CYAN_END); + printf(" %s%s%3d%s\n", + CYAN_BEGIN, + "Ignored: ", + stats.GetIgnored(), + CYAN_END); + } + + Statistic m_stats; + std::map<std::string, Statistic> m_groupsStats; + std::string m_currentGroup; +}; + +TestResultsCollectorBase* ConsoleCollector::Constructor() +{ + return new ConsoleCollector(); +} + +class HtmlCollector : + public TestResultsCollectorBase +{ + public: + static TestResultsCollectorBase* Constructor(); + + private: + HtmlCollector() : m_filename(DEFAULT_HTML_FILE_NAME) {} + + virtual void CollectCurrentTestGroupName(const std::string& name) + { + fprintf(m_fp.Get(), "<b>Starting group %s", name.c_str()); + m_currentGroup = name; + } + + virtual bool Configure() + { + m_fp.Reset(fopen(m_filename.c_str(), "w")); + if (!m_fp) + return false; + + return true; + } + virtual std::string CollectorSpecificHelp() const + { + return "--file=<filename> - name of file for output\n" + " default - index.html\n"; + } + + virtual void Start(int count) + { + DPL_UNUSED_PARAM(count); + AssertMsg(!!m_fp, "File handle must not be null"); + fprintf(m_fp.Get(), + "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0" + "Transitional//EN\" " + "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\"" + ">\n"); + fprintf(m_fp.Get(), + "<html xmlns=\"http://www.w3.org/1999/xhtml\" " + "lang=\"en\" dir=\"ltr\">\n"); + fprintf(m_fp.Get(), "<body style=\"background-color: black;\">\n"); + fprintf(m_fp.Get(), "<pre>\n"); + fprintf(m_fp.Get(), "<font color=\"white\">\n"); + } + + virtual void Finish() + { + using namespace VcoreDPL::Colors::Html; + // Show result + FOREACH(group, m_groupsStats) { + PrintStats(group->first, group->second); + } + PrintStats("All tests together", m_stats); + fprintf(m_fp.Get(), "</font>\n"); + fprintf(m_fp.Get(), "</pre>\n"); + fprintf(m_fp.Get(), "</body>\n"); + fprintf(m_fp.Get(), "</html>\n"); + } + + virtual bool ParseCollectorSpecificArg(const std::string& arg) + { + return ParseCollectorFileArg(arg, m_filename); + } + + virtual void CollectResult(const std::string& id, + const std::string& /*description*/, + const FailStatus::Type status = FailStatus::NONE, + const std::string& reason = "") + { + using namespace VcoreDPL::Colors::Html; + std::string tmp = "'" + id + "' ..."; + + fprintf(m_fp.Get(), "Running test case %-100s", tmp.c_str()); + switch (status) { + case TestResultsCollectorBase::FailStatus::NONE: + fprintf(m_fp.Get(), GREEN_RESULT_OK); + break; + case TestResultsCollectorBase::FailStatus::FAILED: + PrintfErrorMessage(" FAILED ", reason, true); + break; + case TestResultsCollectorBase::FailStatus::IGNORED: + PrintfIgnoredMessage("Ignored ", reason, true); + break; + case TestResultsCollectorBase::FailStatus::INTERNAL: + PrintfErrorMessage("INTERNAL", reason, true); + break; + default: + Assert(false && "Bad status"); + } + m_groupsStats[m_currentGroup].AddTest(status); + m_stats.AddTest(status); + } + + void PrintfErrorMessage(const char* type, + const std::string& message, + bool verbosity) + { + using namespace VcoreDPL::Colors::Html; + if (verbosity) { + fprintf(m_fp.Get(), + "[%s%s%s] %s%s%s\n", + BOLD_RED_BEGIN, + type, + BOLD_RED_END, + BOLD_YELLOW_BEGIN, + message.c_str(), + BOLD_YELLOW_END); + } else { + fprintf(m_fp.Get(), + "[%s%s%s]\n", + BOLD_RED_BEGIN, + type, + BOLD_RED_END); + } + } + + void PrintfIgnoredMessage(const char* type, + const std::string& message, + bool verbosity) + { + using namespace VcoreDPL::Colors::Html; + + if (verbosity) { + fprintf(m_fp.Get(), + "[%s%s%s] %s%s%s\n", + CYAN_BEGIN, + type, + CYAN_END, + BOLD_GOLD_BEGIN, + message.c_str(), + BOLD_GOLD_END); + } else { + fprintf(m_fp.Get(), + "[%s%s%s]\n", + CYAN_BEGIN, + type, + CYAN_END); + } + } + + void PrintStats(const std::string& name, const Statistic& stats) + { + using namespace VcoreDPL::Colors::Html; + fprintf( + m_fp.Get(), "\n%sResults [%s]:%s\n", BOLD_GREEN_BEGIN, + name.c_str(), BOLD_GREEN_END); + fprintf( + m_fp.Get(), "%s%s%3d%s\n", CYAN_BEGIN, + "Total tests: ", stats.GetTotal(), CYAN_END); + fprintf( + m_fp.Get(), " %s%s%3d%s\n", CYAN_BEGIN, + "Succeeded: ", stats.GetPassed(), CYAN_END); + fprintf( + m_fp.Get(), " %s%s%3d%s\n", CYAN_BEGIN, + "Failed: ", stats.GetFailed(), CYAN_END); + fprintf( + m_fp.Get(), " %s%s%3d%s\n", CYAN_BEGIN, + "Ignored: ", stats.GetIgnored(), CYAN_END); + } + + std::string m_filename; + ScopedFClose m_fp; + Statistic m_stats; + std::string m_currentGroup; + std::map<std::string, Statistic> m_groupsStats; +}; + +TestResultsCollectorBase* HtmlCollector::Constructor() +{ + return new HtmlCollector(); +} + +class XmlCollector : + public TestResultsCollectorBase +{ + public: + static TestResultsCollectorBase* Constructor(); + + private: + XmlCollector() : m_filename(DEFAULT_XML_FILE_NAME) {} + + virtual void CollectCurrentTestGroupName(const std::string& name) + { + std::size_t pos = GetCurrentGroupPosition(); + if (std::string::npos != pos) { + GroupFinish(pos); + FlushOutput(); + m_stats = Statistic(); + } + + pos = m_outputBuffer.find("</testsuites>"); + if (std::string::npos == pos) { + ThrowMsg(VcoreDPL::Exception, "Could not find test suites closing tag"); + } + GroupStart(pos, name); + } + + void GroupStart(const std::size_t pos, const std::string& name) + { + std::stringstream groupHeader; + groupHeader << "\n\t<testsuite"; + groupHeader << " name=\"" << EscapeSpecialCharacters(name) << "\""; + groupHeader << R"( tests="1")"; // include SegFault + groupHeader << R"( failures="1")"; // include SegFault + groupHeader << R"( skipped="0")"; + groupHeader << ">"; + + groupHeader << "\n\t\t<testcase name=\"unknown\" status=\"FAILED\">"; + groupHeader << + "\n\t\t\t<failure type=\"FAILED\" message=\"segmentation fault\"/>"; + groupHeader << "\n\t\t</testcase>"; + + groupHeader << "\n\t</testsuite>"; + + m_outputBuffer.insert(pos - 1, groupHeader.str()); + } + + virtual bool Configure() + { + m_fp.Reset(fopen(m_filename.c_str(), "w")); + if (!m_fp) + return false; + + return true; + } + + virtual std::string CollectorSpecificHelp() const + { + return "--file=<filename> - name of file for output\n" + " default - results.xml\n"; + } + + virtual void Start(int count) + { + AssertMsg(!!m_fp, "File handle must not be null"); + m_outputBuffer.append("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"); + m_outputBuffer.append("<testsuites "); + if(count >= 0) + { + m_outputBuffer.append("total=\""); + m_outputBuffer.append(VcoreDPL::lexical_cast<std::string>(count)); + m_outputBuffer.append("\""); + } + m_outputBuffer.append(" >\n</testsuites>"); + FlushOutput(); + } + + virtual void Finish() + { + std::size_t pos = GetCurrentGroupPosition(); + if (std::string::npos != pos) { + GroupFinish(pos); + FlushOutput(); + } + } + + virtual bool ParseCollectorSpecificArg(const std::string& arg) + { + return ParseCollectorFileArg(arg, m_filename); + } + + virtual void CollectResult(const std::string& id, + const std::string& /*description*/, + const FailStatus::Type status = FailStatus::NONE, + const std::string& reason = "") + { + m_resultBuffer.erase(); + m_resultBuffer.append("\t\t<testcase name=\""); + m_resultBuffer.append(EscapeSpecialCharacters(id)); + m_resultBuffer.append("\""); + switch (status) { + case TestResultsCollectorBase::FailStatus::NONE: + m_resultBuffer.append(" status=\"OK\"/>\n"); + break; + case TestResultsCollectorBase::FailStatus::FAILED: + m_resultBuffer.append(" status=\"FAILED\">\n"); + PrintfErrorMessage("FAILED", EscapeSpecialCharacters(reason), true); + m_resultBuffer.append("\t\t</testcase>\n"); + break; + case TestResultsCollectorBase::FailStatus::IGNORED: + m_resultBuffer.append(" status=\"Ignored\">\n"); + PrintfIgnoredMessage("Ignored", EscapeSpecialCharacters( + reason), true); + m_resultBuffer.append("\t\t</testcase>\n"); + break; + case TestResultsCollectorBase::FailStatus::INTERNAL: + m_resultBuffer.append(" status=\"FAILED\">\n"); + PrintfErrorMessage("INTERNAL", EscapeSpecialCharacters( + reason), true); + m_resultBuffer.append("\t\t</testcase>"); + break; + default: + Assert(false && "Bad status"); + } + std::size_t group_pos = GetCurrentGroupPosition(); + if (std::string::npos == group_pos) { + ThrowMsg(VcoreDPL::Exception, "No current group set"); + } + + std::size_t last_case_pos = m_outputBuffer.find( + "<testcase name=\"unknown\"", + group_pos); + if (std::string::npos == last_case_pos) { + ThrowMsg(VcoreDPL::Exception, "Could not find SegFault test case"); + } + m_outputBuffer.insert(last_case_pos - 2, m_resultBuffer); + + m_stats.AddTest(status); + + UpdateGroupHeader(group_pos, + m_stats.GetTotal() + 1, // include SegFault + m_stats.GetFailed() + 1, // include SegFault + m_stats.GetIgnored()); + FlushOutput(); + } + + std::size_t GetCurrentGroupPosition() const + { + return m_outputBuffer.rfind("<testsuite "); + } + + void UpdateGroupHeader(const std::size_t groupPosition, + const unsigned int tests, + const unsigned int failures, + const unsigned int skipped) + { + UpdateElementAttribute(groupPosition, "tests", UIntToString(tests)); + UpdateElementAttribute(groupPosition, "failures", UIntToString(failures)); + UpdateElementAttribute(groupPosition, "skipped", UIntToString(skipped)); + } + + void UpdateElementAttribute(const std::size_t elementPosition, + const std::string& name, + const std::string& value) + { + std::string pattern = name + "=\""; + + std::size_t start = m_outputBuffer.find(pattern, elementPosition); + if (std::string::npos == start) { + ThrowMsg(VcoreDPL::Exception, + "Could not find attribute " << name << " beginning"); + } + + std::size_t end = m_outputBuffer.find("\"", start + pattern.length()); + if (std::string::npos == end) { + ThrowMsg(VcoreDPL::Exception, + "Could not find attribute " << name << " end"); + } + + m_outputBuffer.replace(start + pattern.length(), + end - start - pattern.length(), + value); + } + + std::string UIntToString(const unsigned int value) + { + std::stringstream result; + result << value; + return result.str(); + } + + void GroupFinish(const std::size_t groupPosition) + { + std::size_t segFaultStart = + m_outputBuffer.find("<testcase name=\"unknown\"", groupPosition); + if (std::string::npos == segFaultStart) { + ThrowMsg(VcoreDPL::Exception, + "Could not find SegFault test case start position"); + } + segFaultStart -= 2; // to erase tabs + + std::string closeTag = "</testcase>"; + std::size_t segFaultEnd = m_outputBuffer.find(closeTag, segFaultStart); + if (std::string::npos == segFaultEnd) { + ThrowMsg(VcoreDPL::Exception, + "Could not find SegFault test case end position"); + } + segFaultEnd += closeTag.length() + 1; // to erase new line + + m_outputBuffer.erase(segFaultStart, segFaultEnd - segFaultStart); + + UpdateGroupHeader(groupPosition, + m_stats.GetTotal(), + m_stats.GetFailed(), + m_stats.GetIgnored()); + } + + void FlushOutput() + { + int fd = fileno(m_fp.Get()); + if (-1 == fd) { + int error = errno; + ThrowMsg(VcoreDPL::Exception, VcoreDPL::GetErrnoString(error)); + } + + if (-1 == TEMP_FAILURE_RETRY(ftruncate(fd, 0L))) { + int error = errno; + ThrowMsg(VcoreDPL::Exception, VcoreDPL::GetErrnoString(error)); + } + + if (-1 == TEMP_FAILURE_RETRY(fseek(m_fp.Get(), 0L, SEEK_SET))) { + int error = errno; + ThrowMsg(VcoreDPL::Exception, VcoreDPL::GetErrnoString(error)); + } + + if (m_outputBuffer.size() != + fwrite(m_outputBuffer.c_str(), 1, m_outputBuffer.size(), + m_fp.Get())) + { + int error = errno; + ThrowMsg(VcoreDPL::Exception, VcoreDPL::GetErrnoString(error)); + } + + if (-1 == TEMP_FAILURE_RETRY(fflush(m_fp.Get()))) { + int error = errno; + ThrowMsg(VcoreDPL::Exception, VcoreDPL::GetErrnoString(error)); + } + } + + void PrintfErrorMessage(const char* type, + const std::string& message, + bool verbosity) + { + if (verbosity) { + m_resultBuffer.append("\t\t\t<failure type=\""); + m_resultBuffer.append(EscapeSpecialCharacters(type)); + m_resultBuffer.append("\" message=\""); + m_resultBuffer.append(EscapeSpecialCharacters(message)); + m_resultBuffer.append("\"/>\n"); + } else { + m_resultBuffer.append("\t\t\t<failure type=\""); + m_resultBuffer.append(EscapeSpecialCharacters(type)); + m_resultBuffer.append("\"/>\n"); + } + } + + void PrintfIgnoredMessage(const char* type, + const std::string& message, + bool verbosity) + { + if (verbosity) { + m_resultBuffer.append("\t\t\t<skipped type=\""); + m_resultBuffer.append(EscapeSpecialCharacters(type)); + m_resultBuffer.append("\" message=\""); + m_resultBuffer.append(EscapeSpecialCharacters(message)); + m_resultBuffer.append("\"/>\n"); + } else { + m_resultBuffer.append("\t\t\t<skipped type=\""); + m_resultBuffer.append(EscapeSpecialCharacters(type)); + m_resultBuffer.append("\"/>\n"); + } + } + + std::string EscapeSpecialCharacters(std::string s) + { + for (unsigned int i = 0; i < s.size();) { + switch (s[i]) { + case '"': + s.erase(i, 1); + s.insert(i, """); + i += 6; + break; + + case '&': + s.erase(i, 1); + s.insert(i, "&"); + i += 5; + break; + + case '<': + s.erase(i, 1); + s.insert(i, "<"); + i += 4; + break; + + case '>': + s.erase(i, 1); + s.insert(i, ">"); + i += 4; + break; + + case '\'': + s.erase(i, 1); + s.insert(i, "'"); + i += 5; + break; + default: + ++i; + break; + } + } + return s; + } + + std::string m_filename; + ScopedFClose m_fp; + Statistic m_stats; + std::string m_outputBuffer; + std::string m_resultBuffer; +}; + +TestResultsCollectorBase* XmlCollector::Constructor() +{ + return new XmlCollector(); +} + +class CSVCollector : + public TestResultsCollectorBase +{ + public: + static TestResultsCollectorBase* Constructor(); + + private: + CSVCollector() {} + + virtual void Start(int count) + { + DPL_UNUSED_PARAM(count); + printf("GROUP;ID;RESULT;REASON\n"); + } + + virtual void CollectCurrentTestGroupName(const std::string& name) + { + m_currentGroup = name; + } + + virtual void CollectResult(const std::string& id, + const std::string& /*description*/, + const FailStatus::Type status = FailStatus::NONE, + const std::string& reason = "") + { + std::string statusMsg = ""; + switch (status) { + case TestResultsCollectorBase::FailStatus::NONE: statusMsg = "OK"; + break; + case TestResultsCollectorBase::FailStatus::FAILED: statusMsg = "FAILED"; + break; + case TestResultsCollectorBase::FailStatus::IGNORED: statusMsg = + "IGNORED"; + break; + case TestResultsCollectorBase::FailStatus::INTERNAL: statusMsg = + "FAILED"; + break; + default: + Assert(false && "Bad status"); + } + printf("%s;%s;%s;%s\n", + m_currentGroup.c_str(), + id.c_str(), + statusMsg.c_str(), + reason.c_str()); + } + + std::string m_currentGroup; +}; + +TestResultsCollectorBase* CSVCollector::Constructor() +{ + return new CSVCollector(); +} +} + +class TAPCollector : + public TestResultsCollectorBase +{ + public: + static TestResultsCollectorBase* Constructor(); + + private: + TAPCollector() : m_filename(DEFAULT_TAP_FILE_NAME) {} + + virtual bool Configure() + { + m_output.open(m_filename.c_str(), std::ios_base::trunc); + if (m_output.fail()) + return false; + + return true; + } + virtual std::string CollectorSpecificHelp() const + { + std::string retVal = "--file=<filename> - name of file for output\n" + " default - "; + retVal += DEFAULT_TAP_FILE_NAME; + retVal += "\n"; + return retVal; + } + + virtual void Start(int count) + { + DPL_UNUSED_PARAM(count); + AssertMsg(m_output.good(), "Output file must be opened."); + m_output << "TAP version 13" << std::endl; + m_testIndex = 0; + } + + virtual void Finish() + { + m_output << "1.." << m_testIndex << std::endl; + m_output << m_collectedData.rdbuf(); + m_output.close(); + } + + virtual bool ParseCollectorSpecificArg(const std::string& arg) + { + return ParseCollectorFileArg(arg, m_filename); + } + + virtual void CollectResult(const std::string& id, + const std::string& description, + const FailStatus::Type status = FailStatus::NONE, + const std::string& reason = "") + { + m_testIndex++; + switch (status) { + case TestResultsCollectorBase::FailStatus::NONE: + LogBasicTAP(true, id, description); + endTAPLine(); + break; + case TestResultsCollectorBase::FailStatus::FAILED: + LogBasicTAP(false, id, description); + endTAPLine(); + break; + case TestResultsCollectorBase::FailStatus::IGNORED: + LogBasicTAP(true, id, description); + m_collectedData << " # skip " << reason; + endTAPLine(); + break; + case TestResultsCollectorBase::FailStatus::INTERNAL: + LogBasicTAP(true, id, description); + endTAPLine(); + m_collectedData << " ---" << std::endl; + m_collectedData << " message: " << reason << std::endl; + m_collectedData << " severity: Internal" << std::endl; + m_collectedData << " ..." << std::endl; + break; + default: + Assert(false && "Bad status"); + } + } + + void LogBasicTAP(bool isOK, const std::string& id, + const std::string& description) + { + if (!isOK) { + m_collectedData << "not "; + } + m_collectedData << "ok " << m_testIndex << " [" << + id << "] " << description; + } + + void endTAPLine() + { + m_collectedData << std::endl; + } + + std::string m_filename; + std::stringstream m_collectedData; + std::ofstream m_output; + int m_testIndex; +}; + +TestResultsCollectorBase* TAPCollector::Constructor() +{ + return new TAPCollector(); +} + +void TestResultsCollectorBase::RegisterCollectorConstructor( + const std::string& name, + TestResultsCollectorBase::CollectorConstructorFunc func) +{ + Assert(m_constructorsMap.find(name) == m_constructorsMap.end()); + m_constructorsMap[name] = func; +} + +TestResultsCollectorBase* TestResultsCollectorBase::Create( + const std::string& name) +{ + ConstructorsMap::iterator found = m_constructorsMap.find(name); + if (found != m_constructorsMap.end()) { + return found->second(); + } else { + return NULL; + } +} + +std::vector<std::string> TestResultsCollectorBase::GetCollectorsNames() +{ + std::vector<std::string> list; + FOREACH(it, m_constructorsMap) + { + list.push_back(it->first); + } + return list; +} + +TestResultsCollectorBase::ConstructorsMap TestResultsCollectorBase:: + m_constructorsMap; + +namespace { +static int RegisterCollectorConstructors(); +static const int RegisterHelperVariable = RegisterCollectorConstructors(); +int RegisterCollectorConstructors() +{ + (void)RegisterHelperVariable; + + TestResultsCollectorBase::RegisterCollectorConstructor( + "text", + &ConsoleCollector::Constructor); + TestResultsCollectorBase::RegisterCollectorConstructor( + "html", + &HtmlCollector::Constructor); + TestResultsCollectorBase::RegisterCollectorConstructor( + "csv", + &CSVCollector::Constructor); + TestResultsCollectorBase::RegisterCollectorConstructor( + "tap", + &TAPCollector::Constructor); + TestResultsCollectorBase::RegisterCollectorConstructor( + "xml", + &XmlCollector::Constructor); + + return 0; +} +} +} +} +#undef GREEN_RESULT_OK diff --git a/vcore/src/dpl/test/src/test_runner.cpp b/vcore/src/dpl/test/src/test_runner.cpp new file mode 100644 index 0000000..5002bfd --- /dev/null +++ b/vcore/src/dpl/test/src/test_runner.cpp @@ -0,0 +1,696 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file test_runner.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @author Lukasz Wrzosek (l.wrzosek@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of test runner + */ +#include <stddef.h> +#include <dpl/test/test_runner.h> +#include <dpl/test/test_results_collector.h> +#include <dpl/exception.h> +#include <dpl/free_deleter.h> +#include <memory> +#include <dpl/foreach.h> +#include <dpl/colors.h> +#include <pcrecpp.h> +#include <algorithm> +#include <cstdio> +#include <memory.h> +#include <libgen.h> +#include <cstring> +#include <cstdlib> + +#include <libxml/xpath.h> +#include <libxml/xpathInternals.h> +#include <libxml/parser.h> +#include <libxml/tree.h> + +#include <dpl/singleton_impl.h> +IMPLEMENT_SINGLETON(VcoreDPL::Test::TestRunner) + +namespace { + +std::string getXMLNode(xmlNodePtr node) +{ + std::string ret; + xmlChar * value = xmlNodeGetContent(node); + if (value != NULL) { + ret = std::string(reinterpret_cast<char*>(value)); + xmlFree(value); + } + return ret; +} + +} + + +namespace VcoreDPL { +namespace Test { +namespace // anonymous +{ +std::string BaseName(std::string aPath) +{ + std::unique_ptr<char[],free_deleter> path(strdup(aPath.c_str())); + if (NULL == path.get()) { + throw std::bad_alloc(); + } + char* baseName = basename(path.get()); + std::string retValue = baseName; + return retValue; +} +} // namespace anonymous + +//! \brief Failed test message creator +//! +//! \param[in] aTest string for tested expression +//! \param[in] aFile source file name +//! \param[in] aLine source file line +//! \param[in] aMessage error message +TestRunner::TestFailed::TestFailed(const char* aTest, + const char* aFile, + int aLine, + const std::string &aMessage) +{ + std::ostringstream assertMsg; + assertMsg << "[" << BaseName(aFile) << ":" << aLine + << "] Assertion failed (" + << aTest << ") " << aMessage; + m_message = assertMsg.str(); +} + +TestRunner::TestFailed::TestFailed(const std::string &message) +{ + m_message = message; +} + +void TestRunner::RegisterTest(const char *testName, TestCase proc) +{ + m_testGroups[m_currentGroup].push_back(TestCaseStruct(testName, proc)); +} + +void TestRunner::InitGroup(const char* name) +{ + m_currentGroup = name; +} + +void TestRunner::normalizeXMLTag(std::string& str, const std::string& testcase) +{ + //Add testcase if missing + std::string::size_type pos = str.find(testcase); + if(pos != 0) + { + str = testcase + "_" + str; + } + + //dpl test runner cannot have '-' character in name so it have to be replaced + // for TCT case to make comparision works + std::replace(str.begin(), str.end(), '-', '_'); +} + +bool TestRunner::filterGroupsByXmls(const std::vector<std::string> & files) +{ + DECLARE_EXCEPTION_TYPE(VcoreDPL::Exception, XMLError) + + const std::string idPath = "/test_definition/suite/set/testcase/@id"; + + bool success = true; + std::map<std::string, bool> casesMap; + + std::string testsuite; + if(!m_testGroups.empty()) + { + for(TestCaseGroupMap::const_iterator cit = m_testGroups.begin(); cit != m_testGroups.end(); ++cit) + { + if(!cit->second.empty()) + { + for(TestCaseStructList::const_iterator cj = cit->second.begin(); cj != cit->second.end(); ++cj) + { + std::string name = cj->name; + std::string::size_type st = name.find('_'); + if(st != std::string::npos) + { + name = name.substr(0, st); + testsuite = name; + break; + } + } + if(!testsuite.empty()) break; + } + } + } + + xmlInitParser(); + LIBXML_TEST_VERSION + xmlXPathInit(); + + Try + { + FOREACH(file, files) + { + xmlDocPtr doc; + xmlXPathContextPtr xpathCtx; + + doc = xmlReadFile(file->c_str(), NULL, 0); + if (doc == NULL) { + ThrowMsg(XMLError, "File Problem"); + } else { + //context + xpathCtx = xmlXPathNewContext(doc); + if (xpathCtx == NULL) { + ThrowMsg(XMLError, + "Error: unable to create new XPath context\n"); + } + xpathCtx->node = xmlDocGetRootElement(doc); + } + + std::string result; + xmlXPathObjectPtr xpathObject; + //get requested node's values + xpathObject = xmlXPathEvalExpression(BAD_CAST idPath.c_str(), xpathCtx); + if (xpathObject == NULL) + { + ThrowMsg(XMLError, "XPath evaluation failure: " << idPath); + } + xmlNodeSetPtr nodes = xpathObject->nodesetval; + unsigned size = (nodes) ? nodes->nodeNr : 0; + for(unsigned i = 0; i < size; ++i) + { + if (nodes->nodeTab[i]->type == XML_ATTRIBUTE_NODE) { + xmlNodePtr curNode = nodes->nodeTab[i]; + result = getXMLNode(curNode); + normalizeXMLTag(result, testsuite); + casesMap.insert(make_pair(result, false)); + } + } + //Cleanup of XPath data + xmlXPathFreeObject(xpathObject); + xmlXPathFreeContext(xpathCtx); + xmlFreeDoc(doc); + } + } + Catch(XMLError) + { + success = false; + } + xmlCleanupParser(); + + if(!filterByXML(casesMap)) + { + success = false; + } + + return success; +} + +bool TestRunner::filterByXML(std::map<std::string, bool> & casesMap) +{ + FOREACH(group, m_testGroups) { + TestCaseStructList newList; + FOREACH(iterator, group->second) + { + if (casesMap.find(iterator->name) != casesMap.end()) { + casesMap[iterator->name] = true; + newList.push_back(*iterator); + } + } + group->second = newList; + } + FOREACH(cs, casesMap) + { + if(cs->second == false) + { + return false; + } + } + return true; +} + +TestRunner::Status TestRunner::RunTestCase(const TestCaseStruct& testCase) +{ + try { + testCase.proc(); + } catch (const TestFailed &e) { + // Simple test failure + CollectResult(testCase.name, + "", + TestResultsCollectorBase::FailStatus::FAILED, + e.GetMessage()); + return FAILED; + } catch (const Ignored &e) { + if (m_runIgnored) { + // Simple test have to be implemented + CollectResult(testCase.name, + "", + TestResultsCollectorBase::FailStatus::IGNORED, + e.GetMessage()); + } + + return IGNORED; + } catch (const VcoreDPL::Exception &e) { + // DPL exception failure + CollectResult(testCase.name, + "", + TestResultsCollectorBase::FailStatus::INTERNAL, + "DPL exception:" + e.GetMessage() + "\n" + e.DumpToString()); + + return FAILED; + } catch (const std::exception &) { + // std exception failure + CollectResult(testCase.name, + "", + TestResultsCollectorBase::FailStatus::INTERNAL, + "std exception"); + + return FAILED; + } catch (...) { + // Unknown exception failure + CollectResult(testCase.name, + "", + TestResultsCollectorBase::FailStatus::INTERNAL, + "unknown exception"); + + return FAILED; + } + + CollectResult(testCase.name, + "", + TestResultsCollectorBase::FailStatus::NONE); + + // Everything OK + return PASS; +} + +void TestRunner::RunTests() +{ + using namespace VcoreDPL::Colors::Text; + + Banner(); + + unsigned count = 0; + FOREACH(group, m_testGroups) { + count += group->second.size(); + } + + std::for_each(m_collectors.begin(), + m_collectors.end(), + [count] (const TestResultsCollectors::value_type & collector) + { + collector.second->Start(count); + }); + + fprintf(stderr, "%sFound %d testcases...%s\n", GREEN_BEGIN, count, GREEN_END); + fprintf(stderr, "%s%s%s\n", GREEN_BEGIN, "Running tests...", GREEN_END); + FOREACH(group, m_testGroups) { + TestCaseStructList list = group->second; + if (!list.empty()) { + std::for_each( + m_collectors.begin(), + m_collectors.end(), + [&group](const TestResultsCollectors::value_type & collector) + { + collector.second-> + CollectCurrentTestGroupName(group->first); + }); + list.sort(); + + for (TestCaseStructList::const_iterator iterator = list.begin(); + iterator != list.end(); + ++iterator) + { + TestCaseStruct test = *iterator; + if (m_startTestId == test.name) { + m_startTestId = ""; + } + + if (m_startTestId.empty()) { + RunTestCase(test); + } + if (m_terminate == true) { + // Terminate quietly without any logs + return; + } + } + } + } + + std::for_each(m_collectors.begin(), + m_collectors.end(), + [] (const TestResultsCollectors::value_type & collector) + { + collector.second->Finish(); + }); + + // Finished + fprintf(stderr, "%s%s%s\n\n", GREEN_BEGIN, "Finished", GREEN_END); +} + +void TestRunner::CollectResult( + const std::string& id, + const std::string& description, + const TestResultsCollectorBase::FailStatus::Type status, + const std::string& reason) +{ + std::for_each(m_collectors.begin(), + m_collectors.end(), + [&](const TestResultsCollectors::value_type & collector) + { + collector.second->CollectResult(id, + description, + status, + reason); + }); +} + +void TestRunner::Banner() +{ + using namespace VcoreDPL::Colors::Text; + fprintf(stderr, + "%s%s%s\n", + BOLD_GREEN_BEGIN, + "DPL tests runner", + BOLD_GREEN_END); + fprintf(stderr, + "%s%s%s%s\n\n", + GREEN_BEGIN, + "Build: ", + __TIMESTAMP__, + GREEN_END); +} + +void TestRunner::InvalidArgs(const std::string& message) +{ + using namespace VcoreDPL::Colors::Text; + fprintf(stderr, + "%s%s%s\n", + BOLD_RED_BEGIN, + message.c_str(), + BOLD_RED_END); +} + +void TestRunner::Usage() +{ + fprintf(stderr, "Usage: runner [options]\n\n"); + fprintf(stderr, "Output type:\n"); + fprintf(stderr, " --output=<output type> --output=<output type> ...\n"); + fprintf(stderr, "\n possible output types:\n"); + FOREACH(type, TestResultsCollectorBase::GetCollectorsNames()) { + fprintf(stderr, " --output=%s\n", type->c_str()); + } + fprintf(stderr, "\n example:\n"); + fprintf(stderr, + " test-binary --output=text --output=xml --file=output.xml\n\n"); + fprintf(stderr, "Other parameters:\n"); + fprintf(stderr, + " --regexp='regexp'\t Only selected tests" + " which names match regexp run\n\n"); + fprintf(stderr, " --start=<test id>\tStart from concrete test id"); + fprintf(stderr, " --group=<group name>\t Run tests only from one group\n"); + fprintf(stderr, " --runignored\t Run also ignored tests\n"); + fprintf(stderr, " --list\t Show a list of Test IDs\n"); + fprintf(stderr, " --listgroups\t Show a list of Test Group names \n"); + fprintf(stderr, " --only-from-xml=<xml file>\t Run only testcases specified in XML file \n" + " XML name is taken from attribute id=\"part1_part2\" as whole.\n" + " If part1 is not found (no _) then it is implicitily " + "set according to suite part1 from binary tests\n"); + fprintf( + stderr, + " --listingroup=<group name>\t Show a list of Test IDS in one group\n"); + fprintf(stderr, " --allowchildlogs\t Allow to print logs from child process on screen.\n"); + fprintf(stderr, " When active child process will be able to print logs on stdout and stderr.\n"); + fprintf(stderr, " Both descriptors will be closed after test.\n"); + fprintf(stderr, " --help\t This help\n\n"); + std::for_each(m_collectors.begin(), + m_collectors.end(), + [] (const TestResultsCollectors::value_type & collector) + { + fprintf(stderr, + "Output %s has specific args:\n", + collector.first.c_str()); + fprintf(stderr, + "%s\n", + collector.second-> + CollectorSpecificHelp().c_str()); + }); + fprintf(stderr, "For bug reporting, please write to:\n"); + fprintf(stderr, "<p.dobrowolsk@samsung.com>\n"); +} + +int TestRunner::ExecTestRunner(int argc, char *argv[]) +{ + std::vector<std::string> args; + for (int i = 0; i < argc; ++i) { + args.push_back(argv[i]); + } + return ExecTestRunner(args); +} + +void TestRunner::MarkAssertion() +{ + ++m_totalAssertions; +} + +int TestRunner::ExecTestRunner(const ArgsList& value) +{ + m_runIgnored = false; + ArgsList args = value; + // Parse command line + if (args.size() == 1) { + InvalidArgs(); + Usage(); + return -1; + } + + args.erase(args.begin()); + + bool showHelp = false; + bool justList = false; + std::vector<std::string> xmlFiles; + + TestResultsCollectorBasePtr currentCollector; + + // Parse each argument + FOREACH(it, args) + { + std::string arg = *it; + const std::string regexp = "--regexp="; + const std::string output = "--output="; + const std::string groupId = "--group="; + const std::string runIgnored = "--runignored"; + const std::string listCmd = "--list"; + const std::string startCmd = "--start="; + const std::string listGroupsCmd = "--listgroups"; + const std::string listInGroup = "--listingroup="; + const std::string allowChildLogs = "--allowchildlogs"; + const std::string onlyFromXML = "--only-from-xml="; + + if (currentCollector) { + if (currentCollector->ParseCollectorSpecificArg(arg)) { + continue; + } + } + + if (arg.find(startCmd) == 0) { + arg.erase(0, startCmd.length()); + FOREACH(group, m_testGroups) { + FOREACH(tc, group->second) { + if (tc->name == arg) { + m_startTestId = arg; + break; + } + } + if (!m_startTestId.empty()) { + break; + } + } + if (!m_startTestId.empty()) { + continue; + } + InvalidArgs(); + fprintf(stderr, "Start test id has not been found\n"); + Usage(); + return 0; + } else if (arg.find(groupId) == 0) { + arg.erase(0, groupId.length()); + TestCaseGroupMap::iterator found = m_testGroups.find(arg); + if (found != m_testGroups.end()) { + std::string name = found->first; + TestCaseStructList newList = found->second; + m_testGroups.clear(); + m_testGroups[name] = newList; + } else { + fprintf(stderr, "Group %s not found\n", arg.c_str()); + InvalidArgs(); + Usage(); + return -1; + } + } else if (arg == runIgnored) { + m_runIgnored = true; + } else if (arg == listCmd) { + justList = true; + } else if (arg == listGroupsCmd) { + FOREACH(group, m_testGroups) { + printf("GR:%s\n", group->first.c_str()); + } + return 0; + } else if (arg.find(listInGroup) == 0) { + arg.erase(0, listInGroup.length()); + FOREACH(test, m_testGroups[arg]) { + printf("ID:%s\n", test->name.c_str()); + } + return 0; + } else if (arg.find(allowChildLogs) == 0) { + arg.erase(0, allowChildLogs.length()); + m_allowChildLogs = true; + } else if (arg == "--help") { + showHelp = true; + } else if (arg.find(output) == 0) { + arg.erase(0, output.length()); + if (m_collectors.find(arg) != m_collectors.end()) { + InvalidArgs( + "Multiple outputs of the same type are not supported!"); + Usage(); + return -1; + } + currentCollector.reset(TestResultsCollectorBase::Create(arg)); + if (!currentCollector) { + InvalidArgs("Unsupported output type!"); + Usage(); + return -1; + } + m_collectors[arg] = currentCollector; + } else if (arg.find(regexp) == 0) { + arg.erase(0, regexp.length()); + if (arg.length() == 0) { + InvalidArgs(); + Usage(); + return -1; + } + + if (arg[0] == '\'' && arg[arg.length() - 1] == '\'') { + arg.erase(0); + arg.erase(arg.length() - 1); + } + + if (arg.length() == 0) { + InvalidArgs(); + Usage(); + return -1; + } + + pcrecpp::RE re(arg.c_str()); + FOREACH(group, m_testGroups) { + TestCaseStructList newList; + FOREACH(iterator, group->second) + { + if (re.PartialMatch(iterator->name)) { + newList.push_back(*iterator); + } + } + group->second = newList; + } + } else if(arg.find(onlyFromXML) == 0) { + arg.erase(0, onlyFromXML.length()); + if (arg.length() == 0) { + InvalidArgs(); + Usage(); + return -1; + } + + if (arg[0] == '\'' && arg[arg.length() - 1] == '\'') { + arg.erase(0); + arg.erase(arg.length() - 1); + } + + if (arg.length() == 0) { + InvalidArgs(); + Usage(); + return -1; + } + + xmlFiles.push_back(arg); + } else { + InvalidArgs(); + Usage(); + return -1; + } + } + + if(!xmlFiles.empty()) + { + if(!filterGroupsByXmls(xmlFiles)) + { + fprintf(stderr, "XML file is not correct\n"); + return 0; + } + } + + if(justList) + { + FOREACH(group, m_testGroups) { + FOREACH(test, group->second) { + printf("ID:%s:%s\n", group->first.c_str(), test->name.c_str()); + } + } + return 0; + } + + currentCollector.reset(); + + // Show help + if (showHelp) { + Usage(); + return 0; + } + + if (m_collectors.empty()) { + TestResultsCollectorBasePtr collector( + TestResultsCollectorBase::Create("text")); + m_collectors["text"] = collector; + } + + for (auto it = m_collectors.begin(); it != m_collectors.end(); ++it) { + if (!it->second->Configure()) { + fprintf(stderr, "Could not configure selected output"); + return 0; + } + } + + // Run tests + RunTests(); + + return 0; +} + +bool TestRunner::getRunIgnored() const +{ + return m_runIgnored; +} + +void TestRunner::Terminate() +{ + m_terminate = true; +} + +bool TestRunner::GetAllowChildLogs() +{ + return m_allowChildLogs; +} + +} +} // namespace VcoreDPL diff --git a/vcore/src/dpl/test/src/test_runner_child.cpp b/vcore/src/dpl/test/src/test_runner_child.cpp new file mode 100644 index 0000000..0ebe86c --- /dev/null +++ b/vcore/src/dpl/test/src/test_runner_child.cpp @@ -0,0 +1,325 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file test_runner_child.cpp + * @author Bartlomiej Grzelewski (b.grzelewski@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of test runner + */ +#include <stddef.h> +#include <dpl/test/test_runner.h> +#include <dpl/test/test_runner_child.h> +#include <dpl/test/test_results_collector.h> +#include <dpl/binary_queue.h> +#include <dpl/exception.h> +#include <dpl/scoped_free.h> +#include <dpl/foreach.h> +#include <dpl/colors.h> +#include <pcrecpp.h> +#include <algorithm> +#include <cstdio> +#include <memory.h> +#include <libgen.h> +#include <cstring> +#include <cstdlib> +#include <ctime> +#include <unistd.h> +#include <poll.h> +#include <fcntl.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <sys/stat.h> + +namespace { +const int CHILD_TEST_FAIL = 0; +const int CHILD_TEST_PASS = 1; +const int CHILD_TEST_IGNORED = 2; + +int closeOutput() { + int devnull; + int retcode = -1; + if (-1 == (devnull = TEMP_FAILURE_RETRY(open("/dev/null", O_WRONLY)))) + return -1; + + // replace stdout with /dev/null + if (-1 == TEMP_FAILURE_RETRY(dup2(devnull, STDOUT_FILENO))) + goto end; + + // replace stderr with /dev/null + if (-1 == TEMP_FAILURE_RETRY(dup2(devnull, STDERR_FILENO))) + goto end; + + retcode = 0; + +end: + close(devnull); + return retcode; +} + +} // namespace anonymous + +namespace VcoreDPL { +namespace Test { + +PipeWrapper::PipeWrapper() +{ + if (-1 == pipe(m_pipefd)) { + m_pipefd[0] = PIPE_CLOSED; + m_pipefd[1] = PIPE_CLOSED; + } +} + +PipeWrapper::~PipeWrapper() +{ + closeHelp(0); + closeHelp(1); +} + +bool PipeWrapper::isReady() +{ + return m_pipefd[0] != PIPE_CLOSED || m_pipefd[1] != PIPE_CLOSED; +} + +void PipeWrapper::setUsage(Usage usage) +{ + if (usage == READONLY) { + closeHelp(1); + } + if (usage == WRITEONLY) { + closeHelp(0); + } +} + +PipeWrapper::Status PipeWrapper::send(int code, std::string &message) +{ + if (m_pipefd[1] == PIPE_CLOSED) { + return ERROR; + } + + std::ostringstream output; + output << toBinaryString(code); + output << toBinaryString(static_cast<int>(message.size())); + output << message; + + std::string binary = output.str(); + int size = binary.size(); + + if ((writeHelp(&size, + sizeof(int)) == ERROR) || + (writeHelp(binary.c_str(), size) == ERROR)) + { + return ERROR; + } + return SUCCESS; +} + +PipeWrapper::Status PipeWrapper::receive(int &code, std::string &data, time_t deadline) +{ + if (m_pipefd[0] == PIPE_CLOSED) { + return ERROR; + } + + int size; + Status ret; + + if ((ret = readHelp(&size, sizeof(int), deadline)) != SUCCESS) { + return ret; + } + + std::vector<char> buffer; + buffer.resize(size); + + if ((ret = readHelp(&buffer[0], size, deadline)) != SUCCESS) { + return ret; + } + + try { + VcoreDPL::BinaryQueue queue; + queue.AppendCopy(&buffer[0], size); + + queue.FlattenConsume(&code, sizeof(int)); + queue.FlattenConsume(&size, sizeof(int)); + + buffer.resize(size); + + queue.FlattenConsume(&buffer[0], size); + data.assign(buffer.begin(), buffer.end()); + } catch (VcoreDPL::BinaryQueue::Exception::Base &e) { + return ERROR; + } + return SUCCESS; +} + +void PipeWrapper::closeAll() +{ + closeHelp(0); + closeHelp(1); +} + +std::string PipeWrapper::toBinaryString(int data) +{ + char buffer[sizeof(int)]; + memcpy(buffer, &data, sizeof(int)); + return std::string(buffer, buffer + sizeof(int)); +} + +void PipeWrapper::closeHelp(int desc) +{ + if (m_pipefd[desc] != PIPE_CLOSED) { + TEMP_FAILURE_RETRY(close(m_pipefd[desc])); + m_pipefd[desc] = PIPE_CLOSED; + } +} + +PipeWrapper::Status PipeWrapper::writeHelp(const void *buffer, int size) +{ + int ready = 0; + const char *p = static_cast<const char *>(buffer); + while (ready != size) { + int ret = write(m_pipefd[1], &p[ready], size - ready); + + if (ret == -1 && (errno == EAGAIN || errno == EINTR)) { + continue; + } + + if (ret == -1) { + closeHelp(1); + return ERROR; + } + + ready += ret; + } + return SUCCESS; +} + +PipeWrapper::Status PipeWrapper::readHelp(void *buf, int size, time_t deadline) +{ + int ready = 0; + char *buffer = static_cast<char*>(buf); + while (ready != size) { + time_t wait = deadline - time(0); + wait = wait < 1 ? 1 : wait; + pollfd fds = { m_pipefd[0], POLLIN, 0 }; + + int pollReturn = poll(&fds, 1, wait * 1000); + + if (pollReturn == 0) { + return TIMEOUT; // Timeout + } + + if (pollReturn < -1) { + return ERROR; + } + + int ret = read(m_pipefd[0], &buffer[ready], size - ready); + + if (ret == -1 && (errno == EAGAIN || errno == EINTR)) { + continue; + } + + if (ret == -1 || ret == 0) { + closeHelp(0); + return ERROR; + } + + ready += ret; + } + return SUCCESS; +} + +void RunChildProc(TestRunner::TestCase procChild) +{ + PipeWrapper pipe; + if (!pipe.isReady()) { + throw TestRunner::TestFailed("Pipe creation failed"); + } + + pid_t pid = fork(); + + if (pid == -1) { + throw TestRunner::TestFailed("Child creation failed"); + } + + if (pid != 0) { + // parent code + pipe.setUsage(PipeWrapper::READONLY); + + int code; + std::string message; + + int pipeReturn = pipe.receive(code, message, time(0) + 10); + + if (pipeReturn != PipeWrapper::SUCCESS) { // Timeout or reading error + pipe.closeAll(); + kill(pid, SIGKILL); + } + + int status; + waitpid(pid, &status, 0); + + if (pipeReturn == PipeWrapper::TIMEOUT) { + throw TestRunner::TestFailed("Timeout"); + } + + if (pipeReturn == PipeWrapper::ERROR) { + throw TestRunner::TestFailed("Reading pipe error"); + } + + if (code == CHILD_TEST_FAIL) { + throw TestRunner::TestFailed(message); + } else if (code == CHILD_TEST_IGNORED) { + throw TestRunner::Ignored(message); + } + } else { + // child code + + // End Runner after current test + TestRunnerSingleton::Instance().Terminate(); + + int code = CHILD_TEST_PASS; + std::string msg; + + bool allowLogs = TestRunnerSingleton::Instance().GetAllowChildLogs(); + + close(STDIN_FILENO); + if (!allowLogs) { + closeOutput(); // if fails nothing we can do + } + + pipe.setUsage(PipeWrapper::WRITEONLY); + + try { + procChild(); + } catch (const VcoreDPL::Test::TestRunner::TestFailed &e) { + msg = e.GetMessage(); + code = CHILD_TEST_FAIL; + } catch (const VcoreDPL::Test::TestRunner::Ignored &e) { + msg = e.GetMessage(); + code = CHILD_TEST_IGNORED; + } catch (...) { // catch all exception generated by "user" code + msg = "unhandled exeception"; + code = CHILD_TEST_FAIL; + } + + if (allowLogs) { + closeOutput(); + } + + pipe.send(code, msg); + } +} +} // namespace Test +} // namespace VcoreDPL diff --git a/vcore/src/dpl/test/src/test_runner_multiprocess.cpp b/vcore/src/dpl/test/src/test_runner_multiprocess.cpp new file mode 100644 index 0000000..f377b1e --- /dev/null +++ b/vcore/src/dpl/test/src/test_runner_multiprocess.cpp @@ -0,0 +1,274 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file test_runner_multiprocess.cpp + * @author Marcin Niesluchowski (m.niesluchow@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of multiprocess test runner + */ + +#include <sys/file.h> +#include <dpl/test/test_runner.h> +#include <dpl/test/test_runner_child.h> +#include <dpl/test/test_runner_multiprocess.h> +#include <poll.h> +#include <limits.h> +#include <sys/wait.h> +#include <unistd.h> + +namespace { + +const int MULTI_TEST_ERROR = -1; +const int MULTI_TEST_PASS = 0; +const int MULTI_TEST_FAILED = 1; +const int MULTI_TEST_IGNORED = 2; +const int MULTI_TEST_INTERNAL = 3; + +} + +namespace VcoreDPL { +namespace Test { + +SimplePipeWrapper::SimplePipeWrapper() +: PipeWrapper() +{ + +} + +SimplePipeWrapper::~SimplePipeWrapper() +{ + +} + +PipeWrapper::Status SimplePipeWrapper::send(std::string &message) +{ + if (m_pipefd[1] == PIPE_CLOSED) { + return ERROR; + } + + if (message.size() > PIPE_BUF-1) { + return ERROR; + } + + char buffer[PIPE_BUF] = { 0 }; + + + for(unsigned int i = 0; i < message.size(); ++i) { + buffer[i] = message[i]; + } + + return writeHelp(buffer, PIPE_BUF); +} + +PipeWrapper::Status SimplePipeWrapper::receive(std::string &data, bool &empty, time_t deadline) +{ + if (m_pipefd[0] == PIPE_CLOSED) { + return ERROR; + } + + empty = false; + + data.resize(PIPE_BUF); + + char buffer[PIPE_BUF] = { 0 }; + + int ready = 0; + while (ready != PIPE_BUF) { + time_t wait = deadline - time(0); + wait = wait < 1 ? 1 : wait; + pollfd fds = { m_pipefd[0], POLLIN, 0 }; + + int pollReturn = poll(&fds, 1, wait * 1000); + + if (pollReturn == 0) { + return TIMEOUT; // Timeout + } + + if (pollReturn < -1) { + return ERROR; + } + int ret = read(m_pipefd[0], &buffer[ready], PIPE_BUF - ready); + if (ret == -1 && (errno == EAGAIN || errno == EINTR)) { + continue; + } + + if (ret == -1) { + closeHelp(0); + return ERROR; + } + if (ret == 0) { + empty = true; + break; + } + + ready += ret; + } + + + for(unsigned int i = 0; i < PIPE_BUF; ++i){ + if(buffer[i] == 0) { + data.resize(i); + return SUCCESS; + } + data[i] = buffer[i]; + } + + return ERROR; +} + +void RunMultiProc(TestRunner::TestCase procMulti) +{ + SimplePipeWrapper pipe; + int code = MULTI_TEST_PASS; + std::string msg = ""; + int pipeReturn; + + int waitStatus; + + pid_t top_pid = getpid(); + + if (!pipe.isReady()) { + throw TestRunner::TestFailed("Pipe creation failed"); + } + // pipe + + try { + procMulti(); + } catch (const TestRunner::TestFailed &e) { + code = MULTI_TEST_FAILED; + msg = e.GetMessage(); + } catch (const TestRunner::Ignored &e) { + code = MULTI_TEST_IGNORED; + msg = e.GetMessage(); + } catch (const VcoreDPL::Exception &e) { + code = MULTI_TEST_INTERNAL; + msg = "DPL exception:" + e.GetMessage(); + } catch (const std::exception &) { + code = MULTI_TEST_INTERNAL; + msg = "std exception"; + } catch (...) { + // Unknown exception failure + code = MULTI_TEST_INTERNAL; + msg = "unknown exception"; + } + + while (true) { + pid_t child_pid = wait(&waitStatus); + if (child_pid == -1) { + if (errno == ECHILD) { + if (top_pid == getpid()) { + std::string recMsg=""; + + pipe.setUsage(PipeWrapper::READONLY); + + bool empty=false; + while(true) { + pipeReturn = pipe.receive(recMsg, empty, time(0) + 10); + + if (empty) { + break; + } + if (pipeReturn == PipeWrapper::ERROR) { + pipe.closeAll(); + throw TestRunner::TestFailed("Reading pipe error"); + } else if (pipeReturn == PipeWrapper::TIMEOUT) { + pipe.closeAll(); + throw TestRunner::TestFailed("Timeout error"); + } + msg = msg + "\n" + recMsg; + } + pipe.closeAll(); + + switch(code) { + case MULTI_TEST_PASS: + return; + case MULTI_TEST_FAILED: + throw TestRunner::TestFailed(msg); + case MULTI_TEST_IGNORED: + throw TestRunner::Ignored(msg); + case MULTI_TEST_INTERNAL: + throw TestRunner::TestFailed(msg); + default: + throw TestRunner::TestFailed(msg); + } + } else { + pipe.setUsage(PipeWrapper::WRITEONLY); + + pipeReturn = pipe.send(msg); + + if (pipeReturn == PipeWrapper::ERROR) { + pipe.closeAll(); + code = MULTI_TEST_ERROR; + } + + exit(code); + } + } + } else if (WIFEXITED(waitStatus)) { + if ((signed char)WEXITSTATUS(waitStatus) == MULTI_TEST_FAILED) { + switch (code) { + case MULTI_TEST_PASS: + code = MULTI_TEST_FAILED; + break; + case MULTI_TEST_FAILED: + break; + case MULTI_TEST_IGNORED: + code = MULTI_TEST_FAILED; + break; + case MULTI_TEST_INTERNAL: + break; + default: + break; + } + } else if ((signed char)WEXITSTATUS(waitStatus) == MULTI_TEST_IGNORED) { + switch (code) { + case MULTI_TEST_PASS: + code = MULTI_TEST_IGNORED; + break; + case MULTI_TEST_FAILED: + break; + case MULTI_TEST_IGNORED: + break; + case MULTI_TEST_INTERNAL: + break; + default: + break; + } + } else if ((signed char)WEXITSTATUS(waitStatus) == MULTI_TEST_INTERNAL) { + switch (code) { + case MULTI_TEST_PASS: + code = MULTI_TEST_INTERNAL; + break; + case MULTI_TEST_FAILED: + code = MULTI_TEST_INTERNAL; + break; + case MULTI_TEST_IGNORED: + code = MULTI_TEST_INTERNAL; + break; + case MULTI_TEST_INTERNAL: + break; + default: + break; + } + } else if ((signed char)WEXITSTATUS(waitStatus) != MULTI_TEST_PASS) { + code = MULTI_TEST_ERROR; + msg = "PROCESS BAD CODE RETURN"; + } + } + } +} +} // namespace Test +} // namespace VcoreDPL diff --git a/vcore/src/dpl/test/src/value_separated_policies.cpp b/vcore/src/dpl/test/src/value_separated_policies.cpp new file mode 100644 index 0000000..4fc282a --- /dev/null +++ b/vcore/src/dpl/test/src/value_separated_policies.cpp @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file value_separated_policies.cpp + * @author Tomasz Iwanek (t.iwanek@samsung.com) + * @brief ... + */ + +#include<dpl/test/value_separated_policies.h> +#include<dpl/foreach.h> + +namespace VcoreDPL { + +std::string CSVTokenizerPolicy::GetSeperators() +{ + return ","; +} + +bool CSVTokenizerPolicy::SkipEmpty() +{ + return false; +} + +void CSVTokenizerPolicy::PrepareValue(std::string &) +{ +} + +bool CSVTokenizerPolicy::TryAgainAtEnd(int) +{ + return false; +} + +bool CSVParserPolicy::SkipLine(const std::vector<std::string> & ) +{ + return false; +} + +bool CSVParserPolicy::Validate(std::shared_ptr<std::vector<std::vector<std::string> > > & result) +{ + int num = -1; + FOREACH(r, *result) + { + int size = r->size(); + if(num != -1 && num != size) + return false; + + num = size; + } + return true; +} + +} diff --git a/vcore/src/dpl/test/src/value_separated_tokens.cpp b/vcore/src/dpl/test/src/value_separated_tokens.cpp new file mode 100644 index 0000000..03e4a45 --- /dev/null +++ b/vcore/src/dpl/test/src/value_separated_tokens.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file value_separated_tokens.cpp + * @author Tomasz Iwanek (t.iwanek@samsung.com) + * @brief ... + */ + +#include <dpl/test/value_separated_tokens.h> + +namespace VcoreDPL { + +VSToken::VSToken(const std::string & c) : m_newline(false), m_cell(c) +{ +} + +VSToken::VSToken() : m_newline(true) +{ +} + +const std::string & VSToken::cell() const +{ + return m_cell; +} + +bool VSToken::isNewLine() +{ + return m_newline; +} + +} diff --git a/vcore/src/server/include/cert-server-logic.h b/vcore/src/server/include/cert-server-logic.h new file mode 100644 index 0000000..a9960a5 --- /dev/null +++ b/vcore/src/server/include/cert-server-logic.h @@ -0,0 +1,50 @@ +/** + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file cert_svc_server_main.h + * @author Madhan A K (madhan.ak@samsung.com) + * @version 1.0 + * @brief cert-server routines. + */ + +#ifndef CERT_SVC_SERVER_MAIN_H_ +#define CERT_SVC_SERVER_MAIN_H_ + +#include <db-util.h> + +int getCertificateDetailFromStore(sqlite3 *db_handle, int storeType, int certType, const char* pGname, char* pCertBuffer, size_t *certLength); + +int getCertificateDetailFromSystemStore(sqlite3 *db_handle, const char* pGname, char* pCertBuffer, size_t *certLength); + +int deleteCertificateFromStore(sqlite3 *db_handle, int storeType, const char* pGname); + +int getCertificateStatusFromStore(sqlite3 *db_handle, int storeType, const char* pGname, int *status); + +int setCertificateStatusToStore(sqlite3 *db_handle, int storeType, int is_root_app, const char* pGname, int status); + +int checkAliasExistsInStore(sqlite3 *db_handle, int storeType, const char* alias, int *status); + +int installCertificateToStore(sqlite3 *db_handle, int storeType, const char* pGname, const char *common_name, const char *private_key_gname, const char *associated_gname, const char *pCertBuffer, size_t certLength, int certType); + +int getCertificateListFromStore(sqlite3 *db_handle, int reqType, int storeType, int is_root_app, char **ppCertListBuffer, size_t *bufferLen, int *certCount); + +int getCertificateAliasFromStore(sqlite3 *db_handle, int storeType, const char* pGname, char* alias); + +int loadCertificatesFromStore(sqlite3 *db_handle, int storeType, const char* pGname, char **ppCertBlockBuffer, size_t *bufferLen, int *certBlockCount); + +int update_ca_certificate_file(sqlite3 *db_handle, char *certBuffer, size_t certLength); + +#endif diff --git a/vcore/src/server/src/cert-server-logic.c b/vcore/src/server/src/cert-server-logic.c new file mode 100644 index 0000000..f23f42b --- /dev/null +++ b/vcore/src/server/src/cert-server-logic.c @@ -0,0 +1,1604 @@ +/** + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file cert-server-logic.c + * @author Madhan A K (madhan.ak@samsung.com) + * Kyungwook Tak (k.tak@samsung.com) + * @version 1.0 + * @brief cert-server logic. + */ +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <errno.h> +#include <string.h> +#include <glib.h> +#include <dirent.h> +#include <sys/smack.h> +#include <sys/socket.h> + +#include <ckmc/ckmc-manager.h> +#include <ckmc/ckmc-error.h> + +#include <cert-service.h> +#include <cert-service-debug.h> +#include <cert-svc/cerror.h> +#include <cert-svc/ccert.h> +#include <cert-svc-client.h> + +#include <cert-server-logic.h> + +char *add_shared_owner_prefix(const char *name) +{ + size_t alias_len = strlen(name) + strlen(ckmc_label_shared_owner) + strlen(ckmc_label_name_separator); + char *ckm_alias = (char *)malloc(alias_len + 1); + if (!ckm_alias) { + SLOGE("Failed to allocate memory"); + return NULL; + } + memset(ckm_alias, 0, alias_len + 1); + strncat(ckm_alias, ckmc_label_shared_owner, alias_len + 1); + strncat(ckm_alias, ckmc_label_name_separator, alias_len + 1 - strlen(ckmc_label_shared_owner)); + strncat(ckm_alias, name, alias_len + 1 - strlen(ckmc_label_shared_owner) + strlen(ckmc_label_name_separator)); + + return ckm_alias; +} + +int ckmc_remove_alias_with_shared_owner_prefix(const char *name, int *result) +{ + char *ckm_alias = add_shared_owner_prefix(name); + if (!ckm_alias) { + SLOGE("Failed to allocate memory"); + return CERTSVC_BAD_ALLOC; + } + + *result = ckmc_remove_alias(ckm_alias); + + free(ckm_alias); + + return CERTSVC_SUCCESS; +} + +char *get_complete_path(const char *str1, const char *str2) +{ + char *result = NULL; + int as_result; + + if (!str1 || !str2) + return NULL; + + if (str1[strlen(str1) - 1] != '/') + as_result = asprintf(&result, "%s/%s", str1, str2); + else + as_result = asprintf(&result, "%s%s", str1, str2); + + if (as_result >= CERTSVC_SUCCESS) + return result; + else + return NULL; +} + +/* TODO: root ssl file system refactor */ +int add_file_to_dir(const char* dir, const char* pGname, const char* pData, size_t dataLen) +{ + char *systemFile = get_complete_path(dir, pGname); + if (!systemFile) { + SLOGE("Failed to get system file path."); + return CERTSVC_FAIL; + } + + char realFile[FILENAME_MAX] = {0}; + if (!realpath(systemFile, realFile)) { + SLOGE("Failed to get realpath. systemFile[%s]", systemFile); + return CERTSVC_FAIL; + } + + FILE *stream = fopen(realFile, "ab"); + if (!stream) { + SLOGE("Fail to open file [%s]", realFile); + return CERTSVC_FAIL; + } + + if (fwrite(pData, sizeof(char), dataLen, stream) != dataLen) { + SLOGE("Fail to write file in system store."); + fclose(stream); + return CERTSVC_FAIL; + } + + fclose(stream); + return CERTSVC_SUCCESS; +} + +int add_file_to_system_cert_dir(const char* pGname, const char* pData, size_t dataLen) +{ + return add_file_to_dir(SYSTEM_CERT_DIR, pGname, pData, dataLen); +} + +/* TODO: root ssl file system refactor */ +int del_file_from_dir(const char* dir, const char *pGname) +{ + const char *systemFile = get_complete_path(dir, pGname); + if (!systemFile) { + SLOGE("Failed to construct source file path."); + return CERTSVC_FAIL; + } + + char realFile[FILENAME_MAX] = {0}; + if (!realpath(systemFile, realFile)) { + SLOGE("Failed to get realpath. systemFile[%s]", systemFile); + return CERTSVC_FAIL; + } + + /* instead of removing the file, the file is trimmed to zero size */ + FILE *stream = fopen(realFile, "wb"); + if (!stream) { + SLOGE("Failed to open the file for writing, [%s].", realFile); + return CERTSVC_FAIL; + } + + fclose(stream); + return CERTSVC_SUCCESS; +} + +int del_file_from_system_cert_dir(const char *pGname) +{ + return del_file_from_dir(SYSTEM_CERT_DIR, pGname); +} + +int execute_insert_update_query(sqlite3 *db_handle, char *query) +{ + if (!db_handle) { + SLOGE("Database not initialised."); + return CERTSVC_WRONG_ARGUMENT; + } + + if (!query) { + SLOGE("Query is NULL."); + return CERTSVC_WRONG_ARGUMENT; + } + + /* Begin transaction */ + int result = sqlite3_exec(db_handle, "BEGIN EXCLUSIVE", NULL, NULL, NULL); + if (result != SQLITE_OK) { + SLOGE("Failed to begin transaction."); + return CERTSVC_FAIL; + } + + /* Executing command */ + result = sqlite3_exec(db_handle, query, NULL, NULL, NULL); + if (result != SQLITE_OK) { + SLOGE("Failed to execute query (%s).", query); + return CERTSVC_FAIL; + } + + /* Committing the transaction */ + result = sqlite3_exec(db_handle, "COMMIT", NULL, NULL, NULL); + if (result) { + SLOGE("Failed to commit transaction. Roll back now."); + result = sqlite3_exec(db_handle, "ROLLBACK", NULL, NULL, NULL); + if (result != SQLITE_OK) + SLOGE("Failed to commit transaction. Roll back now."); + + return CERTSVC_FAIL; + } + + SLOGD("Transaction Commit and End."); + + return CERTSVC_SUCCESS; +} + +int execute_select_query(sqlite3 *db_handle, char *query, sqlite3_stmt **stmt) +{ + if (!db_handle || !query) + return CERTSVC_WRONG_ARGUMENT; + + sqlite3_stmt *stmts = NULL; + if (sqlite3_prepare_v2(db_handle, query, strlen(query), &stmts, NULL) != SQLITE_OK) { + SLOGE("sqlite3_prepare_v2 failed [%s].", query); + return CERTSVC_FAIL; + } + + *stmt = stmts; + return CERTSVC_SUCCESS; +} + +int write_to_file(const char *fileName, const char *mode_of_writing, const char *certBuffer, size_t certLength) +{ + int result = CERTSVC_SUCCESS; + FILE *fp_write = NULL; + + if (!certBuffer || certLength <= 0) { + SLOGE("Input buffer is NULL."); + return CERTSVC_WRONG_ARGUMENT; + } + + if (!(fp_write = fopen(fileName, mode_of_writing))) { + SLOGE("Failed to open the file for writing, [%s].", fileName); + return CERTSVC_FAIL; + } + + /* if mode of writing is to append, then goto end of file */ + if (strcmp(mode_of_writing,"ab") == 0) + fseek(fp_write, 0L, SEEK_END); + + if (fwrite(certBuffer, sizeof(char), certLength, fp_write) != certLength) { + SLOGE("Fail to write into file."); + result = CERTSVC_FAIL; + goto error; + } + + /* adding empty line at the end */ + fwrite("\n",sizeof(char), 1, fp_write); + +error: + if (fp_write) + fclose(fp_write); + + return result; +} + +int write_to_ca_cert_crt_file(const char *mode_of_writing, const char *certBuffer, size_t certLength) +{ + return write_to_file(CERTSVC_CRT_FILE_PATH, mode_of_writing, certBuffer, certLength); +} + +int saveCertificateToStore( + const char *pGname, + const char *pData, + size_t dataLen) +{ + if (!pGname || !pData || dataLen < 1) { + SLOGE("Invalid input parameter passed."); + return CERTSVC_WRONG_ARGUMENT; + } + + ckmc_policy_s cert_policy; + cert_policy.password = NULL; + cert_policy.extractable = true; + + ckmc_raw_buffer_s cert_data; + cert_data.data = (unsigned char *)pData; + cert_data.size = dataLen; + + char *ckm_alias = add_shared_owner_prefix(pGname); + if (!ckm_alias) { + SLOGE("Failed to make alias. memory allocation error."); + return CERTSVC_BAD_ALLOC; + } + + int result = ckmc_save_data(ckm_alias, cert_data, cert_policy); + free(ckm_alias); + + if (result != CKMC_ERROR_NONE) { + SLOGE("Failed to save trusted data. ckm errcode[%d]", result); + return CERTSVC_FAIL; + } + + return CERTSVC_SUCCESS; +} + +int saveCertificateToSystemStore( + const char *pGname, + const char *pData, + size_t dataLen) +{ + if (!pGname || !pData || dataLen < 1) { + SLOGE("Invalid input parameter passed."); + return CERTSVC_WRONG_ARGUMENT; + } + + int result = add_file_to_system_cert_dir(pGname, pData, dataLen); + if (result != CERTSVC_SUCCESS) + SLOGE("Failed to store the certificate in store."); + + return result; +} + +int get_certificate_buffer_from_store( + sqlite3 *db_handle, + CertStoreType storeType, + const char *pGname, + char **certBuffer, + size_t *certSize) +{ + int result = CERTSVC_SUCCESS; + int records = 0; + char *tempBuffer = NULL; + char *query = NULL; + sqlite3_stmt *stmt = NULL; + + if (!pGname) { + SLOGE("Invalid input parameter passed."); + return CERTSVC_WRONG_ARGUMENT; + } + + if (storeType != SYSTEM_STORE) + query = sqlite3_mprintf("select * from %Q where gname=%Q and enabled=%d and is_root_app_enabled=%d", \ + ((storeType == WIFI_STORE)? "wifi" : (storeType == VPN_STORE)? "vpn" : \ + (storeType == EMAIL_STORE)? "email" : "ssl"), pGname, ENABLED, ENABLED); + else + query = sqlite3_mprintf("select certificate from ssl where gname=%Q and enabled=%d and is_root_app_enabled=%d", \ + pGname, ENABLED, ENABLED); + + result = execute_select_query(db_handle, query, &stmt); + if (result != CERTSVC_SUCCESS) { + SLOGE("Querying database failed."); + result = CERTSVC_FAIL; + goto error; + } + + records = sqlite3_step(stmt); + if (records != SQLITE_ROW || records == SQLITE_DONE) { + SLOGE("No valid records found for given gname [%s].",pGname); + result = CERTSVC_FAIL; + goto error; + } + + tempBuffer = (char *)malloc(sizeof(char) * VCORE_MAX_RECV_DATA_SIZE); + if (!tempBuffer) { + SLOGE("Fail to allocate memory"); + result = CERTSVC_FAIL; + goto error; + } + + memset(tempBuffer, 0x00, VCORE_MAX_RECV_DATA_SIZE); + + if (storeType == SYSTEM_STORE) + result = getCertificateDetailFromSystemStore(db_handle, pGname, tempBuffer, certSize); + else + result = getCertificateDetailFromStore(db_handle, storeType, PEM_CRT, pGname, tempBuffer, certSize); + + if (result != CERTSVC_SUCCESS) { + SLOGE("Failed to set request data."); + result = CERTSVC_WRONG_ARGUMENT; + goto error; + } + + *certBuffer = tempBuffer; + +error: + if (result != CERTSVC_SUCCESS) + free(tempBuffer); + + if (query) + sqlite3_free(query); + + if (stmt) + sqlite3_finalize(stmt); + + return result; +} + +int update_ca_certificate_file(sqlite3 *db_handle, char *certBuffer, size_t certLength) +{ + int result = CERTSVC_SUCCESS; + int records = 0; + int count = 0; + int counter = 0; + char *pValue = NULL; + char *query = NULL; + const char *text; + sqlite3_stmt *stmt = NULL; + + int storeType[4] = {SYSTEM_STORE, WIFI_STORE, VPN_STORE, EMAIL_STORE}; + + /* During install of a root certificate, the root certificate gets appended at + * the end to optimise the write operation onto ca-certificate.crt file. */ + if (certBuffer && certLength > 0) { + result = write_to_ca_cert_crt_file("ab", certBuffer, certLength); + if (result != CERTSVC_SUCCESS) { + SLOGE("Failed to write to file."); + result = CERTSVC_FAIL; + } + goto error_and_exit; + } + + while (count < 4) { + /* get the ssl certificate from database */ + if (count == 0) + query = sqlite3_mprintf("select certificate from ssl where enabled=%d and is_root_app_enabled=%d", ENABLED, ENABLED); + else if (count > 0 && count < 4) + /* gets all the gname which is marked as root certificate and enabled = TRUE */ + query = sqlite3_mprintf("select gname from %Q where is_root_cert=%d and enabled=%d and is_root_app_enabled=%d", \ + ((count == 1)?"wifi":(count == 2)?"vpn":"email"), ENABLED, ENABLED, ENABLED); + + result = execute_select_query(db_handle, query, &stmt); + if (result != CERTSVC_SUCCESS) { + SLOGE("Querying database failed."); + goto next; + } + + /* update the ca-certificate.crt file */ + while (1) { + records = sqlite3_step(stmt); + if (records != SQLITE_ROW || records == SQLITE_DONE) { + result = CERTSVC_SUCCESS; + break; + } + + if (records == SQLITE_ROW) { + certLength = 0; + certBuffer = NULL; + pValue = NULL; + + if (count == 0) { + /* gets the certificate from database for system store */ + text = (const char *)sqlite3_column_text(stmt, 0); + if (text) { + certLength = strlen(text); + certBuffer = strndup(text, certLength); + } + } else { + /* gets the certificate from key-manager for other stores */ + text = (const char *)sqlite3_column_text(stmt, 0); + if (text) + pValue = strndup(text, strlen(text)); + + result = get_certificate_buffer_from_store(db_handle, storeType[count], pValue, &certBuffer, &certLength); + if (result != CERTSVC_SUCCESS) { + SLOGE("Failed to get certificate buffer from key-manager."); + goto error_and_exit; + } + } + + if (certBuffer) { + if (counter++ == 0) + result = write_to_ca_cert_crt_file("wb", certBuffer, certLength); + else + result = write_to_ca_cert_crt_file("ab", certBuffer, certLength); + + if (result != CERTSVC_SUCCESS) { + SLOGE("Failed to write to file."); + result = CERTSVC_FAIL; + goto error_and_exit; + } + } + } + } +next: + count++; + if (query) { + sqlite3_free(query); + query = NULL; + } + } + SLOGD("Successfully updated ca-certificate.crt file."); + +error_and_exit: + if (query) + sqlite3_free(query); + + if (stmt) + sqlite3_finalize(stmt); + + return result; +} + +int enable_disable_cert_status( + sqlite3 *db_handle, + CertStoreType storeType, + int is_root_app, + const char *pGname, + CertStatus status) +{ + int ckmc_result = CKMC_ERROR_UNKNOWN; + int result = CERTSVC_SUCCESS; + int records = 0; + size_t certSize = 0; + size_t certLength = 0; + char *certBuffer = NULL; + char *query = NULL; + const char *text = NULL; + sqlite3_stmt *stmt = NULL; + + if (status != DISABLED && status != ENABLED) { + SLOGE("Invalid cert status"); + return CERTSVC_INVALID_STATUS; + } + + query = sqlite3_mprintf("select * from %Q where gname=%Q", ((storeType == WIFI_STORE)? "wifi" : \ + (storeType == VPN_STORE)? "vpn" : (storeType == EMAIL_STORE)? "email" : "ssl"), pGname); + if (!query) { + SLOGE("Failed to generate query"); + return CERTSVC_BAD_ALLOC; + } + + result = execute_select_query(db_handle, query, &stmt); + sqlite3_free(query); + + if (result != CERTSVC_SUCCESS || !stmt) { + SLOGE("Querying database failed."); + return CERTSVC_FAIL; + } + + records = sqlite3_step(stmt); + sqlite3_finalize(stmt); + stmt = NULL; + + if (records != SQLITE_ROW) { + SLOGE("No valid records found."); + return CERTSVC_FAIL; + } + + if (status == DISABLED) { + /* check certificate presence in disabled_certs table before inserting */ + query = sqlite3_mprintf("select * from disabled_certs where gname=%Q", pGname); + if (!query) { + SLOGE("Failed to generate query"); + return CERTSVC_BAD_ALLOC; + } + + result = execute_select_query(db_handle, query, &stmt); + sqlite3_free(query); + query = NULL; + + if (result != CERTSVC_SUCCESS) { + SLOGE("Querying database failed."); + return CERTSVC_FAIL; + } + + records = sqlite3_step(stmt); + sqlite3_finalize(stmt); + stmt = NULL; + + if (records == SQLITE_ROW) { + SLOGE("Selected certificate identifier is already disabled.", pGname); + return CERTSVC_FAIL; + } + + /* get certificate from keymanager*/ + result = get_certificate_buffer_from_store(db_handle, storeType, pGname, &certBuffer, &certSize); + if (result != CERTSVC_SUCCESS) { + SLOGE("Failed to get certificate buffer. result[%d]", result); + return result; + } + + /* inserting the disabled certificate to disabled_certs table */ + query = sqlite3_mprintf("insert into disabled_certs (gname, certificate) values (%Q, %Q)", pGname, certBuffer); + free(certBuffer); + + if (!query) { + SLOGE("Failed to generate query"); + return CERTSVC_BAD_ALLOC; + } + + result = execute_insert_update_query(db_handle, query); + sqlite3_free(query); + + if (result != CERTSVC_SUCCESS) { + SLOGE("Insert to database failed."); + return result; + } + + if (storeType != SYSTEM_STORE) { + result = ckmc_remove_alias_with_shared_owner_prefix(pGname, &ckmc_result); + + if (result != CERTSVC_SUCCESS || ckmc_result != CKMC_ERROR_NONE) { + SLOGE("Failed to delete certificate from key-manager. ckmc_result[%d]", ckmc_result); + return CERTSVC_FAIL; + } + + } else { + result = del_file_from_system_cert_dir(pGname); + if (result != CERTSVC_SUCCESS) { + SLOGE("Error in del_file_from_system_cert_dir. ret[%d]", result); + return result; + } + } + } else { /* moving the certificate to enabled state */ + query = sqlite3_mprintf("select certificate from disabled_certs where gname=%Q", pGname); + if (!query) { + SLOGE("Failed to generate query"); + return CERTSVC_BAD_ALLOC; + } + + result = execute_select_query(db_handle, query, &stmt); + sqlite3_free(query); + + if (result != CERTSVC_SUCCESS) { + SLOGE("Querying database failed."); + return CERTSVC_FAIL; + } + + records = sqlite3_step(stmt); + if (records == SQLITE_ROW) { + text = (const char *)sqlite3_column_text(stmt, 0); + + if (!text) { + SLOGE("Invalid column text"); + sqlite3_finalize(stmt); + return CERTSVC_FAIL; + } + + certBuffer = strndup(text, strlen(text)); + + sqlite3_finalize(stmt); + + if (!certBuffer) { + SLOGE("Failed to allocate memory"); + return CERTSVC_BAD_ALLOC; + } + + certLength = strlen(certBuffer); + + if (storeType == SYSTEM_STORE) + result = saveCertificateToSystemStore(pGname, certBuffer, certLength); + else + result = saveCertificateToStore(pGname, certBuffer, certLength); + + free(certBuffer); + + if (result != CERTSVC_SUCCESS) { + SLOGE("Failed to save certificate to key-manager. ret[%d]", result); + return result; + } + + query = sqlite3_mprintf("delete from disabled_certs where gname=%Q", pGname); + if (!query) { + SLOGE("Failed to generate query"); + return CERTSVC_BAD_ALLOC; + } + + result = execute_insert_update_query(db_handle, query); + sqlite3_free(query); + + if (result != CERTSVC_SUCCESS) { + SLOGE("Unable to delete certificate entry from database. ret[%d]", result); + return result; + } + } + } + + if (is_root_app == ENABLED) + query = sqlite3_mprintf("update %Q set is_root_app_enabled=%d , enabled=%d where gname=%Q", ((storeType == WIFI_STORE)? "wifi" : \ + (storeType == VPN_STORE)? "vpn" : (storeType == EMAIL_STORE)? "email" : "ssl"), status, status, pGname); + else + query = sqlite3_mprintf("update %Q set enabled=%d where gname=%Q", ((storeType == WIFI_STORE)? "wifi" : \ + (storeType == VPN_STORE)? "vpn" : (storeType == EMAIL_STORE)? "email" : "ssl"), status, pGname); + + if (!query) { + SLOGE("Failed to generate query"); + return CERTSVC_BAD_ALLOC; + } + + result = execute_insert_update_query(db_handle, query); + sqlite3_free(query); + + if (result != CERTSVC_SUCCESS) { + SLOGE("Update failed. ret[%d]", result); + return result; + } + + return result; +} + +int setCertificateStatusToStore( + sqlite3 *db_handle, + int storeType, + int is_root_app, + const char *pGname, + int status) +{ + if (!pGname) { + SLOGE("Invalid input parameter passed."); + return CERTSVC_WRONG_ARGUMENT; + } + + int result = enable_disable_cert_status(db_handle, storeType, is_root_app, pGname, status); + if (result != CERTSVC_SUCCESS) { + SLOGE("Failed to disable certificate."); + return result; + } + + SLOGD("Successfully updated the certificate status from %s to %s.", + (status == DISABLED) ? "ENABLED" : "DISABLED", (status == DISABLED) ? "DISABLED" : "ENABLED"); + return CERTSVC_SUCCESS; +} + +int getCertificateStatusFromStore( + sqlite3 *db_handle, + int storeType, + const char* pGname, + int *status) +{ + if (!pGname) { + SLOGE("Invalid input parameter passed."); + return CERTSVC_WRONG_ARGUMENT; + } + + char *query = sqlite3_mprintf("select gname, common_name, enabled from %Q where gname=%Q",\ + ((storeType == WIFI_STORE)? "wifi" : (storeType == VPN_STORE)? "vpn" : \ + (storeType == EMAIL_STORE)? "email" : "ssl"), pGname); + if (!query) { + SLOGE("Failed to generate query"); + return CERTSVC_BAD_ALLOC; + } + + sqlite3_stmt *stmt = NULL; + int result = execute_select_query(db_handle, query, &stmt); + sqlite3_free(query); + + if (result != CERTSVC_SUCCESS || !stmt) { + SLOGE("Querying database failed."); + *status = DISABLED; + return CERTSVC_FAIL; + } + + result = sqlite3_step(stmt); + if (result != SQLITE_ROW || result == SQLITE_DONE) { + SLOGE("No valid records found."); + *status = DISABLED; + sqlite3_finalize(stmt); + return CERTSVC_FAIL; + } + + *status = sqlite3_column_int(stmt, 2); + + sqlite3_finalize(stmt); + + return CERTSVC_SUCCESS; +} + +int check_alias_exist_in_database( + sqlite3 *db_handle, + CertStoreType storeType, + const char *alias, + int *status) +{ + sqlite3_stmt *stmt = NULL; + + if (!alias || !status) { + SLOGE("Invalid input parameter passed."); + return CERTSVC_WRONG_ARGUMENT; + } + + char *query = sqlite3_mprintf("select * from %Q where common_name=%Q", ((storeType == WIFI_STORE)? "wifi" : \ + (storeType == VPN_STORE)? "vpn" : "email"),alias); + + if (!query) { + SLOGE("Failed to generate query"); + return CERTSVC_BAD_ALLOC; + } + + int result = execute_select_query(db_handle, query, &stmt); + sqlite3_free(query); + + if (result != CERTSVC_SUCCESS || !stmt) { + SLOGE("Querying database failed."); + return CERTSVC_FAIL; + } + + result = sqlite3_step(stmt); + sqlite3_finalize(stmt); + + if (result != SQLITE_ROW) { + SLOGD("No records found with the alias passed (%s).", alias); + *status = CERTSVC_TRUE; + } else { + SLOGD("Records found with the alias passed (%s).", alias); + *status = CERTSVC_FALSE; + } + + return CERTSVC_SUCCESS; +} + +int installCertificateToStore( + sqlite3 *db_handle, + int storeType, + const char *pGname, + const char *common_name, + const char *private_key_gname, + const char *associated_gname, + const char *dataBlock, + size_t dataBlockLen, + int certType) +{ + if ((!pGname) + || (certType == P12_END_USER && !common_name && !private_key_gname) + || (certType != P12_END_USER && !common_name && !associated_gname)) { + SLOGE("Invalid input parameter passed."); + return CERTSVC_WRONG_ARGUMENT; + } + + if (storeType != SYSTEM_STORE + && saveCertificateToStore( + pGname, + dataBlock, + dataBlockLen) != CERTSVC_SUCCESS) { + SLOGE("FAIL to save certificate to key-manager."); + return CERTSVC_FAIL; + } + + if (certType == P12_PKEY) { + SLOGD("Don't save private key in store"); + return CERTSVC_SUCCESS; + } + + char *query = NULL; + if (certType == P12_END_USER && private_key_gname) { + query = sqlite3_mprintf("insert into %Q (gname, common_name, private_key_gname, associated_gname, enabled, is_root_app_enabled) "\ + "values (%Q, %Q, %Q, %Q, %d, %d)",((storeType == WIFI_STORE)? "wifi" : \ + (storeType == VPN_STORE)? "vpn" : "email"), pGname, common_name, private_key_gname, pGname, ENABLED, ENABLED); + } else if (certType == PEM_CRT || certType == P12_TRUSTED) { + query = sqlite3_mprintf("insert into %Q (gname, common_name, is_root_cert, associated_gname, enabled, is_root_app_enabled) values "\ + "(%Q, %Q, %d, %Q, %d, %d)", ((storeType == WIFI_STORE)? "wifi" : \ + (storeType == VPN_STORE)? "vpn" : "email"), pGname, common_name, ENABLED, associated_gname, ENABLED, ENABLED); + } else if (certType == P12_INTERMEDIATE) { + query = sqlite3_mprintf("insert into %Q (gname, common_name, associated_gname, enabled, is_root_app_enabled) values (%Q, %Q, %Q, %d, %d)", \ + ((storeType == WIFI_STORE)? "wifi" : (storeType == VPN_STORE)? "vpn" : "email"), + pGname, common_name, associated_gname, ENABLED, ENABLED); + } + + if (!query) { + SLOGE("Failed to generate query"); + return CERTSVC_BAD_ALLOC; + } + + int result = execute_insert_update_query(db_handle, query); + sqlite3_free(query); + + if (result != CERTSVC_SUCCESS) { + SLOGE("Insert to database failed."); + return CERTSVC_FAIL; + } + + return CERTSVC_SUCCESS; +} + +int checkAliasExistsInStore( + sqlite3 *db_handle, + int storeType, + const char* alias, + int *status) +{ + if (!alias) { + SLOGE("Invalid input parameter passed."); + return CERTSVC_WRONG_ARGUMENT; + } + + *status = CERTSVC_FAIL; + int result = check_alias_exist_in_database(db_handle, storeType, alias, status); + if (result != CERTSVC_SUCCESS) { + SLOGE("Failed to check_alias_exist_in_database. err[%d]", result); + return CERTSVC_FAIL; + } + + if (*status == CERTSVC_TRUE) { + SLOGD("Alias (%s) does not exist in %s store.", + alias, + (storeType == VPN_STORE) ? "VPN" : + (storeType == WIFI_STORE) ? "WIFI" : "EMAIL"); + } else { + SLOGD("Alias (%s) exist in %s store.", + alias, + (storeType == VPN_STORE) ? "VPN" : + (storeType == WIFI_STORE) ? "WIFI" : "EMAIL"); + } + + return CERTSVC_SUCCESS; +} + +int getCertificateDetailFromStore( + sqlite3 *db_handle, + int storeType, + int certType, + const char *pGname, + char *pOutData, + size_t *size) +{ + int result = CERTSVC_SUCCESS; + int records = 0; + char *query = NULL; + const char *text = NULL; + sqlite3_stmt *stmt = NULL; + ckmc_raw_buffer_s *cert_data = NULL; + + if (!pGname || !pOutData) { + SLOGE("Invalid input parameter passed."); + return CERTSVC_WRONG_ARGUMENT; + } + + /* start constructing query */ + if (certType == P12_PKEY) { + /* From the given certificate identifier, get the associated_gname for the certificate. + * Then query the database for records matching the associated_gname to get the private key */ + query = sqlite3_mprintf("select associated_gname from %Q where gname=%Q", \ + ((storeType == WIFI_STORE)? "wifi" : (storeType == VPN_STORE)? "vpn" : "email"), pGname); + if (!query) { + SLOGE("Failed to generate query"); + return CERTSVC_BAD_ALLOC; + } + + result = execute_select_query(db_handle, query, &stmt); + sqlite3_free(query); + + if (result != CERTSVC_SUCCESS) { + SLOGE("Querying database failed."); + return result; + } + + records = sqlite3_step(stmt); + if (records != SQLITE_ROW) { + SLOGE("No valid records found."); + sqlite3_finalize(stmt); + return CERTSVC_FAIL; + } + + text = (const char *)sqlite3_column_text(stmt, 0); + + if (!text) { + SLOGE("No valid column text"); + sqlite3_finalize(stmt); + return CERTSVC_FAIL; + } + + query = sqlite3_mprintf("select private_key_gname from %Q where gname=%Q and enabled=%d and is_root_app_enabled=%d", \ + ((storeType == WIFI_STORE)? "wifi" : (storeType == VPN_STORE)? "vpn" : "email"), text, ENABLED, ENABLED); + + sqlite3_finalize(stmt); + } else if (storeType != SYSTEM_STORE) { + query = sqlite3_mprintf("select * from %Q where gname=%Q and enabled=%d and is_root_app_enabled=%d", \ + ((storeType == WIFI_STORE)? "wifi" : (storeType == VPN_STORE)? "vpn" : \ + (storeType == EMAIL_STORE)? "email" : "ssl"), pGname, ENABLED, ENABLED); + } + + if (!query) { + SLOGE("Failed to generate query"); + return CERTSVC_BAD_ALLOC; + } + + result = execute_select_query(db_handle, query, &stmt); + sqlite3_free(query); + + if (result != CERTSVC_SUCCESS) { + SLOGE("Querying database failed."); + return result; + } + + records = sqlite3_step(stmt); + if (records != SQLITE_ROW) { + SLOGE("No valid records found."); + sqlite3_finalize(stmt); + return CERTSVC_FAIL; + } + + if (certType == P12_PKEY) { + if (!(text = (const char *)sqlite3_column_text(stmt, 0))) { + SLOGE("No valid column text"); + sqlite3_finalize(stmt); + return CERTSVC_FAIL; + } + + pGname = text; + } + + char *ckm_alias = add_shared_owner_prefix(pGname); + if (!ckm_alias) { + SLOGE("Failed to make alias. memory allocation error."); + return CERTSVC_BAD_ALLOC; + } + + result = ckmc_get_data(ckm_alias, NULL, &cert_data); + free(ckm_alias); + + sqlite3_finalize(stmt); + + if (result != CKMC_ERROR_NONE) { + SLOGE("Failed to get certificate from key-manager. ckm ret[%d]", result); + *size = CERTSVC_FAIL; + return CERTSVC_FAIL; + } + + memcpy(pOutData, cert_data->data, cert_data->size); + pOutData[cert_data->size] = 0; + *size = cert_data->size; + + ckmc_buffer_free(cert_data); + + return CERTSVC_SUCCESS; +} + +int getCertificateDetailFromSystemStore( + sqlite3 *db_handle, + const char *pGname, + char *pOutData, + size_t *size) +{ + int result = CERTSVC_SUCCESS; + int records = 0; + size_t certLength = 0; + char *query = NULL; + const char *text = NULL; + sqlite3_stmt *stmt = NULL; + + if (!pGname) { + SLOGE("Invalid input parameter passed."); + return CERTSVC_WRONG_ARGUMENT; + } + + query = sqlite3_mprintf("select certificate from ssl where gname=%Q and is_root_app_enabled=%d", \ + pGname, ENABLED, ENABLED); + if (!query) { + SLOGE("Query is NULL."); + return CERTSVC_FAIL; + } + + result = execute_select_query(db_handle, query, &stmt); + sqlite3_free(query); + + if (result != CERTSVC_SUCCESS) { + SLOGE("Querying database failed."); + return result; + } + + records = sqlite3_step(stmt); + if (records != SQLITE_ROW) { + SLOGE("No valid records found for passed gname [%s].", pGname); + sqlite3_finalize(stmt); + return CERTSVC_FAIL; + } + + text = (const char *)sqlite3_column_text(stmt, 0); + + if (!text) { + SLOGE("Fail to sqlite3_column_text"); + sqlite3_finalize(stmt); + return CERTSVC_FAIL; + } + + certLength = strlen(text); + if (certLength >= 4096) { + sqlite3_finalize(stmt); + SLOGE("certificate is too long"); + return CERTSVC_FAIL; + } + + memcpy(pOutData, text, certLength); + pOutData[certLength] = 0; + *size = certLength; + + sqlite3_finalize(stmt); + return CERTSVC_SUCCESS; +} + +int deleteCertificateFromStore(sqlite3 *db_handle, int storeType, const char* pGname) { + + int result = CERTSVC_SUCCESS; + int ckmc_result = CKMC_ERROR_UNKNOWN; + int records = 0; + char *query = NULL; + char *private_key_name = NULL; + sqlite3_stmt *stmt = NULL; + + if (!pGname) { + SLOGE("Invalid input parameter passed."); + return CERTSVC_WRONG_ARGUMENT; + } + + if (storeType != SYSTEM_STORE) { + /* start constructing query */ + query = sqlite3_mprintf("select private_key_gname from %Q where gname=%Q", ((storeType == WIFI_STORE)? "wifi" :\ + (storeType == VPN_STORE)? "vpn" : "email"), pGname); + + result = execute_select_query(db_handle, query, &stmt); + if (result != CERTSVC_SUCCESS) { + SLOGE("Querying database failed."); + result = CERTSVC_FAIL; + goto error; + } + + records = sqlite3_step(stmt); + if ((records != SQLITE_ROW) || (records == SQLITE_DONE)) { + SLOGE("No valid records found for passed gname [%s].",pGname); + result = CERTSVC_FAIL; + goto error; + } + + /* if a cert is having private-key in it, the private key should + * be deleted first from key-manager, then the actual cert */ + if (sqlite3_column_text(stmt, 0) != NULL) { + private_key_name = strdup((const char *)sqlite3_column_text(stmt, 0)); + result = ckmc_remove_alias_with_shared_owner_prefix(private_key_name, &ckmc_result); + if (result != CERTSVC_SUCCESS || ckmc_result != CKMC_ERROR_NONE) { + SLOGE("Failed to delete certificate from key-manager. ckmc_result[%d]", ckmc_result); + result = CERTSVC_FAIL; + goto error; + } + } + + /* removing the actual cert */ + result = ckmc_remove_alias_with_shared_owner_prefix(pGname, &ckmc_result); + if (result != CERTSVC_SUCCESS || ckmc_result != CKMC_ERROR_NONE) { + query = sqlite3_mprintf("delete from disabled_certs where gname=%Q", pGname); + result = execute_insert_update_query(db_handle, query); + if (result != CERTSVC_SUCCESS) { + SLOGE("Unable to delete certificate entry from database."); + result = CERTSVC_FAIL; + goto error; + } + } + + if (query) { + sqlite3_free(query); + query = NULL; + } + + if (stmt) { + sqlite3_finalize(stmt); + stmt = NULL; + } + + query = sqlite3_mprintf("delete from %Q where gname=%Q", ((storeType == WIFI_STORE)? "wifi" : \ + (storeType == VPN_STORE)? "vpn" : "email"), pGname); + + result = execute_insert_update_query(db_handle, query); + if (result != CERTSVC_SUCCESS) { + SLOGE("Unable to delete certificate entry from database."); + result = CERTSVC_FAIL; + goto error; + } + } else { + SLOGE("Invalid store type passed."); + result = CERTSVC_INVALID_STORE_TYPE; + } + SLOGD("Success in deleting the certificate from store."); + +error: + if (query) + sqlite3_free(query); + + if (stmt) + sqlite3_finalize(stmt); + + free(private_key_name); + return result; +} + + +int getCertificateListFromStore( + sqlite3 *db_handle, + int reqType, + int storeType, + int is_root_app, + char **certListBuffer, + size_t *bufferLen, + int *certCount) +{ + int result = CERTSVC_SUCCESS; + CertSvcStoreCertList *rootCertHead = NULL; + CertSvcStoreCertList *tmpNode = NULL; + CertSvcStoreCertList *currentNode = NULL; + sqlite3_stmt *stmt = NULL; + char *query = NULL; + int loopCount = 0; + int records = 0; + int count = 0; + int i = 0; + + + while (1) { + /* Iteration only possible from VPN_STORE till SYSTEM_STORE */ + if (loopCount == (MAX_STORE_ENUMS - 1)) + break; + + /* Check if the passed store type matches with any of the in-built store type */ + if ((1 << loopCount) & storeType) { + /* if a store type matches, put that value as storetype argument in the below function */ + CertStoreType tempStore = (CertStoreType) (1 << loopCount); + SLOGD("Processing storetype [%s]", (tempStore == WIFI_STORE)? "WIFI" : (tempStore == VPN_STORE)? "VPN" : \ + (tempStore == EMAIL_STORE)? "EMAIL" : "SYSTEM"); + + if (reqType == CERTSVC_GET_ROOT_CERTIFICATE_LIST) { + // For get_root_certificate_list_from_store + if (storeType == SYSTEM_STORE) { + query = sqlite3_mprintf("select gname, common_name, enabled from %Q where enabled=%d "\ + "and is_root_app_enabled=%d and order by common_name asc", "ssl", ENABLED, ENABLED); + } else { + query = sqlite3_mprintf("select gname, common_name, enabled from %Q where "\ + "is_root_cert IS NOT NULL and is_root_app_enabled=%d and enabled=%d", \ + (storeType== WIFI_STORE)? "wifi" : (storeType == VPN_STORE)? "vpn" : \ + (storeType == EMAIL_STORE)? "email" : "ssl", ENABLED, ENABLED); + } + } else if (reqType == CERTSVC_GET_USER_CERTIFICATE_LIST) { + // For get_end_user_certificate_list_from_store + if (storeType == SYSTEM_STORE) { + SLOGE("Invalid store type passed."); + return CERTSVC_WRONG_ARGUMENT; + } else { + query = sqlite3_mprintf("select gname, common_name, enabled from %Q where "\ + "private_key_gname IS NOT NULL and is_root_app_enabled=%d and enabled=%d", \ + (storeType== WIFI_STORE)? "wifi" : (storeType == VPN_STORE)? "vpn" : \ + (storeType == EMAIL_STORE)? "email" : "ssl", ENABLED, ENABLED); + } + } else { + // For get_certificate_list_from_store + if (is_root_app != ENABLED) { + /* Gets only the list of certificates where is_root_app = 1 (which are enabled by the master application) */ + if (tempStore == SYSTEM_STORE) { + query = sqlite3_mprintf("select gname, common_name, enabled from %Q where "\ + "is_root_app_enabled=%d order by common_name asc", \ + (tempStore== WIFI_STORE)? "wifi" : (tempStore == VPN_STORE)? "vpn" : \ + (tempStore == EMAIL_STORE)? "email" : "ssl", ENABLED, ENABLED); + } else { + query = sqlite3_mprintf("select gname, common_name, enabled from %Q where is_root_app_enabled=%d", \ + (tempStore== WIFI_STORE)? "wifi" : (tempStore == VPN_STORE)? "vpn" : \ + (tempStore == EMAIL_STORE)? "email" : "ssl", ENABLED, ENABLED); + } + } else { + /* Gets all the certificates from store without any restrictions */ + if (tempStore == SYSTEM_STORE) { + query = sqlite3_mprintf("select gname, common_name, enabled from %Q order by common_name asc", \ + (tempStore== WIFI_STORE)? "wifi" : (tempStore == VPN_STORE)? "vpn" : \ + (tempStore == EMAIL_STORE)? "email" : "ssl", ENABLED); + } else { + query = sqlite3_mprintf("select gname, common_name, enabled from %Q", \ + (tempStore== WIFI_STORE)? "wifi" : (tempStore == VPN_STORE)? "vpn" : \ + (tempStore == EMAIL_STORE)? "email" : "ssl", ENABLED); + } + } + } + + result = execute_select_query(db_handle, query, &stmt); + if (result != CERTSVC_SUCCESS) { + SLOGE("Querying database failed."); + result = CERTSVC_FAIL; + goto error; + } + + while (1) { + records = sqlite3_step(stmt); + if (records != SQLITE_ROW || records == SQLITE_DONE) { + if (count < 0) { + SLOGE("No records found"); + result = CERTSVC_SUCCESS; + goto error; + } else { + break; + } + } + + if (records == SQLITE_ROW) { + tmpNode = (CertSvcStoreCertList *)malloc(sizeof(CertSvcStoreCertList)); + if (!tmpNode) { + SLOGE("Failed to allocate memory."); + result = CERTSVC_BAD_ALLOC; + goto error; + } else { + tmpNode->next = NULL; + const char *textGname = (const char *)sqlite3_column_text(stmt, 0); + const char *textAlias = (const char *)sqlite3_column_text(stmt, 1); + if (!textGname || !textAlias) { + SLOGE("Failed to read texts from records"); + free(tmpNode); + result = CERTSVC_FAIL; + goto error; + } + + int gnameLen = strlen(textGname); + int aliasLen = strlen(textAlias); + + tmpNode->gname = (char *)malloc(sizeof(char) * (gnameLen + 1)); + tmpNode->title = (char *)malloc(sizeof(char) * (aliasLen + 1)); + if (!tmpNode->title || !tmpNode->gname) { + free(tmpNode->gname); + free(tmpNode->title); + free(tmpNode); + SLOGE("Failed to allocate memory"); + result = CERTSVC_BAD_ALLOC; + goto error; + } + + memset(tmpNode->gname, 0x00, gnameLen + 1); + memset(tmpNode->title, 0x00, aliasLen + 1); + + memcpy(tmpNode->gname, textGname, gnameLen); + memcpy(tmpNode->title, textAlias, aliasLen); + + tmpNode->status = (int)sqlite3_column_int(stmt, 2); /* for status */ + tmpNode->storeType = tempStore; + } + + /* When multiple stores are passed, we need to ensure that the rootcerthead is + assigned to currentNode once, else previous store data gets overwritten */ + if (count == 0) { + rootCertHead = tmpNode; + currentNode = rootCertHead; + tmpNode = NULL; + } else { + currentNode->next = tmpNode; + currentNode = tmpNode; + tmpNode = NULL; + } + count++; + } + } + + if (count <=0 ) { + SLOGD("No entries found in database."); + result = CERTSVC_SUCCESS; + } + + if (query) { + sqlite3_free(query); + query = NULL; + } + + if (stmt) { + sqlite3_finalize(stmt); + stmt = NULL; + } + } + loopCount++; + } + + *certCount = count; + VcoreCertResponseData *respCertData = (VcoreCertResponseData *)malloc(count * sizeof(VcoreCertResponseData)); + if (!respCertData) { + SLOGE("Failed to allocate memory"); + result = CERTSVC_BAD_ALLOC; + goto error; + } + if (count > 0) + memset(respCertData, 0x00, count * sizeof(VcoreCertResponseData)); + VcoreCertResponseData* currRespCertData = NULL; + + currentNode = rootCertHead; + for (i = 0; i < count; i++) { + tmpNode = currentNode->next; + + currRespCertData = respCertData + i; + if (strlen(currentNode->gname) > sizeof(currRespCertData->gname) + || strlen(currentNode->title) > sizeof(currRespCertData->title)) { + SLOGE("String is too long. [%s], [%s]", currentNode->gname, currentNode->title); + result = CERTSVC_FAIL; + *certListBuffer = NULL; + free(respCertData); + goto error; + } + strncpy(currRespCertData->gname, currentNode->gname, strlen(currentNode->gname)); + strncpy(currRespCertData->title, currentNode->title, strlen(currentNode->title)); + currRespCertData->status = currentNode->status; + currRespCertData->storeType = currentNode->storeType; + //SLOGD("get cert list: %d th cert: gname=%s, title=%s, status=%d, storeType=%d", i, currRespCertData->gname, currRespCertData->title, currRespCertData->status, currRespCertData->storeType); + + currentNode = tmpNode; + } + + *certListBuffer = (char *) respCertData; + *bufferLen = count * sizeof(VcoreCertResponseData); + + SLOGD("Success to create certificate list. cert_count=%d", count); + result= CERTSVC_SUCCESS; +error: + if (query) + sqlite3_free(query); + + if (stmt) + sqlite3_finalize(stmt); + + if (rootCertHead) { + currentNode = rootCertHead; + while (currentNode) { + tmpNode = currentNode->next; + free(currentNode->title); + free(currentNode->gname); + free(currentNode); + currentNode=tmpNode; + } + rootCertHead = NULL; + } + + return result; +} + +int getCertificateAliasFromStore(sqlite3 *db_handle, int storeType, const char* gname, char* alias) +{ + int result = CERTSVC_SUCCESS; + int records = 0; + sqlite3_stmt *stmt = NULL; + char *query = NULL; + const char *text = NULL; + + query = sqlite3_mprintf("select common_name from %Q where gname=%Q", ((storeType==WIFI_STORE)? "wifi" : \ + (storeType==VPN_STORE)? "vpn" : "email"), gname); + + result = execute_select_query(db_handle, query, &stmt); + if (result != CERTSVC_SUCCESS) { + SLOGE("Querying database failed."); + result = CERTSVC_FAIL; + goto error; + } + + records = sqlite3_step(stmt); + if (records != SQLITE_ROW || records == SQLITE_DONE) { + SLOGE("No valid records found for gname passed [%s].",gname); + result = CERTSVC_FAIL; + goto error; + } + + if (!(text = (const char *)sqlite3_column_text(stmt, 0))) { + SLOGE("No column text in returned records"); + result = CERTSVC_FAIL; + goto error; + } + + strncpy(alias, text, strlen(text)); + + if (strlen(alias) == 0) { + SLOGE("Unable to get the alias name for the gname passed."); + result = CERTSVC_FAIL; + goto error; + } + + result = CERTSVC_SUCCESS; + + SLOGD("success : getCertificateAliasFromStore"); +error: + if (query) + sqlite3_free(query); + + if (stmt) + sqlite3_finalize(stmt); + + return result; +} + +int loadCertificatesFromStore( + sqlite3 *db_handle, + int storeType, + const char* gname, + char **ppCertBlockBuffer, + size_t *bufferLen, + int *certBlockCount) +{ + int result = CERTSVC_SUCCESS; + int count = 0; + int records = 0; + sqlite3_stmt *stmt = NULL; + char *query = NULL; + char **certs = NULL; + const char *tmpText = NULL; + int i = 0; + + query = sqlite3_mprintf("select associated_gname from %Q where gname=%Q", ((storeType==WIFI_STORE)? "wifi" : \ + (storeType==VPN_STORE)? "vpn" : "email"), gname); + + result = execute_select_query(db_handle, query, &stmt); + if (result != CERTSVC_SUCCESS) { + SLOGE("Querying database failed."); + result = CERTSVC_FAIL; + goto error; + } + + records = sqlite3_step(stmt); + if (records != SQLITE_ROW || records == SQLITE_DONE) { + SLOGE("No valid records found for gname passed [%s].",gname); + result = CERTSVC_FAIL; + goto error; + } + + + if (records == SQLITE_ROW) { + if (query) + sqlite3_free(query); + + const char *columnText = (const char *)sqlite3_column_text(stmt, 0); + if (!columnText) { + SLOGE("Failed to sqlite3_column_text"); + result = CERTSVC_FAIL; + goto error; + } + + query = sqlite3_mprintf("select gname from %Q where associated_gname=%Q and enabled=%d and is_root_app_enabled=%d", \ + ((storeType==WIFI_STORE)? "wifi" : (storeType==VPN_STORE)? "vpn" : "email"), \ + columnText, ENABLED, ENABLED); + + if (stmt) + sqlite3_finalize(stmt); + + result = execute_select_query(db_handle, query, &stmt); + if (result != CERTSVC_SUCCESS) { + SLOGE("Querying database failed."); + result = CERTSVC_FAIL; + goto error; + } + + while (1) { + records = sqlite3_step(stmt); + if (records != SQLITE_ROW || records == SQLITE_DONE) + break; + + if (count == 0) { + certs = (char**) malloc(4 * sizeof(char *)); + if (!certs) { + SLOGE("Failed to allocate memory"); + result = CERTSVC_BAD_ALLOC; + goto error; + } + memset(certs, 0x00, 4 * sizeof(char *)); + } + + if (records == SQLITE_ROW) { + tmpText = (const char *)sqlite3_column_text(stmt, 0); + if (!tmpText) { + SLOGE("Failed to sqlite3_column_text."); + result = CERTSVC_FAIL; + goto error; + } + + if (!((certs)[count] = strdup(tmpText))) { + SLOGE("Failed to allocate memory"); + result = CERTSVC_BAD_ALLOC; + goto error; + } + } + + count++; + } + + if (count == 0) { + SLOGE("No valid records found for the gname passed [%s].",gname); + return CERTSVC_FAIL; + } + } + + *certBlockCount = count; + *bufferLen = count * sizeof(ResponseCertBlock); + ResponseCertBlock *certBlockList = (ResponseCertBlock *) malloc(*bufferLen); + if (!certBlockList) { + SLOGE("Failed to allocate memory for ResponseCertBlock"); + result = CERTSVC_BAD_ALLOC; + goto error; + } + + if (count > 0) + memset(certBlockList, 0x00, *bufferLen); + + ResponseCertBlock *currentBlock = NULL; + for (i = 0; i < count; i++) { + currentBlock = certBlockList + i; + if (sizeof(currentBlock->dataBlock) < strlen(certs[i])) { + SLOGE("src is longer than dst. src[%s] dst size[%d]", certs[i], sizeof(currentBlock->dataBlock)); + free(certBlockList); + result = CERTSVC_FAIL; + goto error; + } + strncpy(currentBlock->dataBlock, certs[i], strlen(certs[i])); + currentBlock->dataBlockLen = strlen(certs[i]); + } + *ppCertBlockBuffer = (char *)certBlockList; + + result = CERTSVC_SUCCESS; + + SLOGD("success: loadCertificatesFromStore. CERT_COUNT=%d", count); + +error: + if (query) + sqlite3_free(query); + + if (stmt) + sqlite3_finalize(stmt); + + if (certs) { + for(i = 0; i < count; i++) + free(certs[i]); + + free(certs); + } + + return result; +} diff --git a/vcore/src/server/src/cert-server-main.c b/vcore/src/server/src/cert-server-main.c new file mode 100644 index 0000000..7624a50 --- /dev/null +++ b/vcore/src/server/src/cert-server-main.c @@ -0,0 +1,479 @@ +/** + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file cert-server-main.c + * @author Madhan A K (madhan.ak@samsung.com) + * Kyungwook Tak (k.tak@samsung.com) + * @version 1.0 + * @brief cert-svc server. + */ + +#include <signal.h> +#include <unistd.h> +#include <errno.h> +#include <sys/un.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <sys/select.h> +#include <systemd/sd-daemon.h> + +#include <cert-service-debug.h> +#include <cert-svc/cerror.h> +#include <cert-svc/ccert.h> +#include <cert-svc-client.h> + +#include <cert-server-logic.h> + +sqlite3 *cert_store_db = NULL; + +int open_db(sqlite3 **db_handle, const char *db_path) { + + int result = CERTSVC_FAIL; + sqlite3 *handle; + + if (access(db_path, F_OK) == 0) { + result = db_util_open(db_path, &handle, 0); + if (result != SQLITE_OK) { + SLOGE("connect db [%s] failed!", db_path); + return CERTSVC_FAIL; + } + *db_handle = handle; + return CERTSVC_SUCCESS; + } + SLOGD("%s DB does not exists. Creating one!!", db_path); + + result = db_util_open(db_path, &handle, 0); + if (result != SQLITE_OK) { + SLOGE("connect to db [%s] failed!.", db_path); + return CERTSVC_FAIL; + } + *db_handle = handle; + return CERTSVC_SUCCESS; +} + +int evaluate_query(sqlite3 *db_handle, char *query) { + + int result = CERTSVC_SUCCESS; + sqlite3_stmt* p_statement; + + if (!db_handle) { + SLOGE("Database not initialised."); + return CERTSVC_WRONG_ARGUMENT; + } + + if (!query) { + SLOGE("Query is NULL."); + return CERTSVC_WRONG_ARGUMENT; + } + + result = sqlite3_prepare_v2(db_handle, query, strlen(query), &p_statement, NULL); + if (result != SQLITE_OK) { + SLOGE("Sqlite3 error [%d] : <%s> preparing <%s> query.", result, sqlite3_errmsg(db_handle), query); + return CERTSVC_FAIL; + } + + result = sqlite3_step(p_statement); + if (result != SQLITE_DONE) { + SLOGE("Sqlite3 error [%d] : <%s> executing <%s> statement.", result, sqlite3_errmsg(db_handle), query); + return CERTSVC_FAIL; + } + + result = sqlite3_finalize(p_statement); + if (result != SQLITE_OK) { + SLOGE("Sqlite3 error [%d] : <%s> finalising <%s> statement.", result, sqlite3_errmsg(db_handle), query); + return CERTSVC_FAIL; + } + return CERTSVC_SUCCESS; +} + +int initialize_db(void) { + + int result = CERTSVC_SUCCESS; +// int i=0; +// static int reentry = 1; +// char *query = NULL; +// char db_list[][6]={"wifi","vpn","email"}; + + if (cert_store_db == NULL) { + result = open_db(&cert_store_db, CERTSVC_SYSTEM_STORE_DB); + if (result != CERTSVC_SUCCESS) { + SLOGE("Certsvc store DB creation failed. result[%d]", result); + return result; + } + } + +/* + if (reentry == 1) { + for (i=0; i<3; i++) { + query = sqlite3_mprintf("create table if not exists %Q (gname text primary key not null, " \ + "common_name text key not null, private_key_gname text, " \ + "associated_gname text, is_root_cert integer, " \ + "enabled integer key not null," + "is_root_app_enabled integer key not null)", db_list[i]); + + result = evaluate_query(cert_store_db, query); + if (result != CERTSVC_SUCCESS) { + SLOGE("Certificate store database initialisation Failed."); + result = CERTSVC_FAIL; + } + sqlite3_free(query); query=NULL; + } + + query = sqlite3_mprintf("create table if not exists disabled_certs "\ + "(gname text primary key not null, certificate text key not null)"); + + result = evaluate_query(cert_store_db, query); + if (result != CERTSVC_SUCCESS) { + SLOGE("wifi store DB initialisation Failed."); + result = CERTSVC_FAIL; + } + + sqlite3_free(query); query=NULL; + result = CERTSVC_SUCCESS; + reentry++; + goto err; + } + +err: +*/ + + return CERTSVC_SUCCESS; +} + +void CertSigHandler(int signo) +{ + SLOGD("Got Signal %d, exiting now.", signo); + if (cert_store_db != NULL) { + sqlite3_close(cert_store_db); + cert_store_db = NULL; + } + exit(1); +} + +int CertSvcGetSocketFromSystemd(int* pSockfd) +{ + int n = sd_listen_fds(0); + int fd; + + for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START+n; ++fd) { + if (0 < sd_is_socket_unix(fd, SOCK_STREAM, 1, VCORE_SOCK_PATH, 0)) { + LOGD("Get socket from systemd. fd[%d]", fd); + *pSockfd = fd; + return CERTSVC_SUCCESS; + } + } + return CERTSVC_FAIL; +} + +void CertSvcServerComm() +{ + int server_sockfd = 0; + int client_sockfd = 0; + int read_len = 0; + int client_len = 0; + struct sockaddr_un clientaddr; + int result = CERTSVC_SUCCESS; + char *certListBuffer = NULL; + char *certBlockBuffer = NULL; + size_t bufferLen = 0; + size_t blockBufferLen = 0; + + struct timeval timeout; + timeout.tv_sec = 10; + timeout.tv_usec = 0; + + SLOGI("cert-server is starting..."); + + VcoreRequestData recv_data; + VcoreResponseData send_data; + + if (!CertSvcGetSocketFromSystemd(&server_sockfd)) { + SLOGE("Failed to get sockfd from systemd."); + return; + } + + client_len = sizeof(clientaddr); + signal(SIGINT, (void*)CertSigHandler); + +/* + if (!cert_store_db) { + result = initialize_db(); + if (result != CERTSVC_SUCCESS) { + SLOGE("Failed to initialize database."); + result = CERTSVC_IO_ERROR; + goto Error_close_exit; + } + + if (cert_store_db) { + sqlite3_close(cert_store_db); + cert_store_db = NULL; + } + } +*/ + + fd_set fd; + struct timeval tv; + while (1) { + errno = 0; + + FD_ZERO(&fd); + FD_SET(server_sockfd, &fd); + + tv.tv_sec = 1; + tv.tv_usec = 0; + + memset(&recv_data, 0x00, sizeof(VcoreRequestData)); + memset(&send_data, 0x00, sizeof(VcoreResponseData)); + + int ret = select(server_sockfd + 1, &fd, NULL, NULL, &tv); + if (ret == 0) { // timeout + SLOGD("cert-server timeout. exit."); + break; + } + + if (ret == -1) { + SLOGE("select() error."); + break; + } + + if ((client_sockfd = accept(server_sockfd, (struct sockaddr*)&clientaddr, (socklen_t*)&client_len)) < 0) { + SLOGE("Error in function accept().[socket desc :%d, error no :%d].", client_sockfd, errno); + continue; + } + + SLOGD("cert-server Accept! client sock[%d]", client_sockfd); + + if (setsockopt (client_sockfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout)) < 0) { + SLOGE("Error in Set SO_RCVTIMEO Socket Option"); + send_data.result = CERTSVC_FAIL; + goto Error_close_exit; + } + + if (setsockopt (client_sockfd, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, sizeof(timeout)) < 0) { + SLOGE("Error in Set SO_SNDTIMEO Socket Option"); + send_data.result = CERTSVC_FAIL; + goto Error_close_exit; + } + + SLOGD("Connected to a client..."); + + read_len = recv(client_sockfd, (char*)&recv_data, sizeof(recv_data), 0); + if (read_len < 0) { + SLOGE("Error in function recv()."); + send_data.result = CERTSVC_FAIL; + goto Error_close_exit; + } + + if (!cert_store_db) { + result = initialize_db(); + if (result != CERTSVC_SUCCESS) { + SLOGE("Failed to initialize database."); + result = CERTSVC_IO_ERROR; + goto Error_close_exit; + } + } + + SLOGD("revc request: reqType=%d", recv_data.reqType); + + switch (recv_data.reqType) { + case CERTSVC_EXTRACT_CERT: + { + send_data.result = getCertificateDetailFromStore( + cert_store_db, + recv_data.storeType, + recv_data.certType, + recv_data.gname, + send_data.dataBlock, + &send_data.dataBlockLen); + result = send(client_sockfd, (char*)&send_data, sizeof(send_data), 0); + break; + } + + case CERTSVC_EXTRACT_SYSTEM_CERT: + { + send_data.result = getCertificateDetailFromSystemStore( + cert_store_db, + recv_data.gname, + send_data.dataBlock, + &send_data.dataBlockLen); + result = send(client_sockfd, (char*)&send_data, sizeof(send_data), 0); + break; + } + + case CERTSVC_DELETE_CERT: + { + send_data.result = deleteCertificateFromStore( + cert_store_db, + recv_data.storeType, + recv_data.gname); + if (send_data.result == CERTSVC_SUCCESS) + send_data.result = update_ca_certificate_file(cert_store_db, NULL, 0); + result = send(client_sockfd, (char*)&send_data, sizeof(send_data), 0); + break; + } + + case CERTSVC_GET_CERTIFICATE_STATUS: + { + send_data.result = getCertificateStatusFromStore( + cert_store_db, + recv_data.storeType, + recv_data.gname, + &send_data.certStatus); + result = send(client_sockfd, (char*)&send_data, sizeof(send_data), 0); + break; + } + + case CERTSVC_SET_CERTIFICATE_STATUS: + { + send_data.result = setCertificateStatusToStore( + cert_store_db, + recv_data.storeType, + recv_data.is_root_app, + recv_data.gname, + recv_data.certStatus); + if (send_data.result == CERTSVC_SUCCESS) + send_data.result = update_ca_certificate_file(cert_store_db, NULL, 0); + result = send(client_sockfd, (char*)&send_data, sizeof(send_data), 0); + break; + } + + case CERTSVC_CHECK_ALIAS_EXISTS: + { + send_data.result = checkAliasExistsInStore( + cert_store_db, + recv_data.storeType, + recv_data.gname, + &send_data.certStatus); + result = send(client_sockfd, (char*)&send_data, sizeof(send_data), 0); + break; + } + + case CERTSVC_INSTALL_CERTIFICATE: + { + send_data.result = installCertificateToStore( + cert_store_db, + recv_data.storeType, + recv_data.gname, + recv_data.common_name, + recv_data.private_key_gname, + recv_data.associated_gname, + recv_data.dataBlock, + recv_data.dataBlockLen, + recv_data.certType); + + if ((send_data.result == CERTSVC_SUCCESS) && ((recv_data.certType == PEM_CRT) || (recv_data.certType == P12_TRUSTED))) + send_data.result = update_ca_certificate_file(cert_store_db, recv_data.dataBlock, recv_data.dataBlockLen); + result = send(client_sockfd, (char*)&send_data, sizeof(send_data), 0); + break; + } + + case CERTSVC_GET_CERTIFICATE_LIST: + case CERTSVC_GET_USER_CERTIFICATE_LIST: + case CERTSVC_GET_ROOT_CERTIFICATE_LIST: + { + send_data.result = getCertificateListFromStore( + cert_store_db, + recv_data.reqType, + recv_data.storeType, + recv_data.is_root_app, + &certListBuffer, + &bufferLen, + &send_data.certCount); + result = send(client_sockfd, (char*)&send_data, sizeof(send_data), 0); + if (bufferLen > 0) + result = send(client_sockfd, certListBuffer, bufferLen, 0); + + break; + } + + case CERTSVC_GET_CERTIFICATE_ALIAS: + { + send_data.result = getCertificateAliasFromStore( + cert_store_db, + recv_data.storeType, + recv_data.gname, + send_data.common_name); + result = send(client_sockfd, (char*)&send_data, sizeof(send_data), 0); + break; + } + + case CERTSVC_LOAD_CERTIFICATES: + { + send_data.result = loadCertificatesFromStore( + cert_store_db, + recv_data.storeType, + recv_data.gname, + &certBlockBuffer, + &blockBufferLen, + &send_data.certBlockCount); + result = send(client_sockfd, (char*)&send_data, sizeof(send_data), 0); + if (blockBufferLen > 0) + result = send(client_sockfd, certBlockBuffer, blockBufferLen, 0); + break; + } + + default: + SLOGE("Input error. Please check request type"); + break; + } + + if (result <= 0) { + SLOGE("send failed :%d, errno %d try once", result, errno); + //result = send(client_sockfd, (char*)&send_data, sizeof(send_data), 0); + //SLOGE("retry result :%d, errno %d", result, errno); + } + + close(client_sockfd); + if (cert_store_db) { + sqlite3_close(cert_store_db); + cert_store_db = NULL; + SLOGI("cert_store db was closed"); + } + } + +Error_close_exit: + close(server_sockfd); + if (cert_store_db) { + sqlite3_close(cert_store_db); + cert_store_db = NULL; + } + + if (certListBuffer) + free(certListBuffer); + + if (certBlockBuffer) + free(certBlockBuffer); + + if (client_sockfd >= 0) { + result = send(client_sockfd, (char*)&send_data, sizeof(send_data), 0); + close(client_sockfd); + } + else + SLOGE("cannot connect to client socket."); + + SLOGI("CertSvcServerComm done."); +} + +int main(void) +{ + SLOGI("cert-server start"); + CertSvcServerComm(); + SLOGI("cert-server end"); + + return 0; +} diff --git a/vcore/src/vcore/Base64.cpp b/vcore/src/vcore/Base64.cpp index 82398aa..e3a1abe 100644 --- a/vcore/src/vcore/Base64.cpp +++ b/vcore/src/vcore/Base64.cpp @@ -20,7 +20,8 @@ #include <openssl/evp.h> #include <openssl/buffer.h> -#include <dpl/log/log.h> +#include <dpl/log/wrt_log.h> + #include <dpl/scoped_free.h> #include <vcore/Base64.h> @@ -36,8 +37,8 @@ Base64Encoder::Base64Encoder() : void Base64Encoder::append(const std::string &data) { if (m_finalized) { - LogWarning("Already finalized."); - ThrowMsg(Exception::AlreadyFinalized, "Already finalized"); + WrtLogW("Already finalized."); + VcoreThrowMsg(Exception::AlreadyFinalized, "Already finalized"); } if (!m_b64) { @@ -49,24 +50,26 @@ void Base64Encoder::append(const std::string &data) void Base64Encoder::finalize() { if (m_finalized) { - LogWarning("Already finalized."); - ThrowMsg(Exception::AlreadyFinalized, "Already finalized."); + WrtLogW("Already finalized."); + VcoreThrowMsg(Exception::AlreadyFinalized, "Already finalized."); } m_finalized = true; - BIO_flush(m_b64); + + if (BIO_flush(m_b64) != 1) + VcoreThrowMsg(Exception::InternalError, "Bio internal error"); } std::string Base64Encoder::get() { if (!m_finalized) { - LogWarning("Not finalized"); - ThrowMsg(Exception::NotFinalized, "Not finalized"); + WrtLogW("Not finalized"); + VcoreThrowMsg(Exception::NotFinalized, "Not finalized"); } BUF_MEM *bptr = 0; BIO_get_mem_ptr(m_b64, &bptr); if (bptr == 0) { - LogError("Bio internal error"); - ThrowMsg(Exception::InternalError, "Bio internal error"); + WrtLogE("Bio internal error"); + VcoreThrowMsg(Exception::InternalError, "Bio internal error"); } if (bptr->length > 0) { @@ -82,8 +85,8 @@ void Base64Encoder::reset() m_b64 = BIO_new(BIO_f_base64()); m_bmem = BIO_new(BIO_s_mem()); if (!m_b64 || !m_bmem) { - LogError("Error during allocation memory in BIO"); - ThrowMsg(Exception::InternalError, + WrtLogE("Error during allocation memory in BIO"); + VcoreThrowMsg(Exception::InternalError, "Error during allocation memory in BIO"); } BIO_set_flags(m_b64, BIO_FLAGS_BASE64_NO_NL); @@ -103,8 +106,8 @@ Base64Decoder::Base64Decoder() : void Base64Decoder::append(const std::string &data) { if (m_finalized) { - LogWarning("Already finalized."); - ThrowMsg(Exception::AlreadyFinalized, "Already finalized."); + WrtLogW("Already finalized."); + VcoreThrowMsg(Exception::AlreadyFinalized, "Already finalized."); } m_input.append(data); } @@ -118,8 +121,8 @@ static bool whiteCharacter(char a) bool Base64Decoder::finalize() { if (m_finalized) { - LogWarning("Already finalized."); - ThrowMsg(Exception::AlreadyFinalized, "Already finalized."); + WrtLogW("Already finalized."); + VcoreThrowMsg(Exception::AlreadyFinalized, "Already finalized."); } m_finalized = true; @@ -137,44 +140,44 @@ bool Base64Decoder::finalize() { continue; } - LogError("Base64 input contains illegal chars: " << m_input[i]); + WrtLogE("Base64 input contains illegal chars: %c", m_input[i]); return false; } BIO *b64, *bmem; size_t len = m_input.size(); - DPL::ScopedFree<char> buffer(static_cast<char*>(malloc(len))); + VcoreDPL::ScopedFree<char> buffer(static_cast<char*>(malloc(len))); if (!buffer) { - LogError("Error in malloc."); - ThrowMsg(Exception::InternalError, "Error in malloc."); + WrtLogE("Error in malloc."); + VcoreThrowMsg(Exception::InternalError, "Error in malloc."); } memset(buffer.Get(), 0, len); b64 = BIO_new(BIO_f_base64()); if (!b64) { - LogError("Couldn't create BIO object."); - ThrowMsg(Exception::InternalError, "Couldn't create BIO object."); + WrtLogE("Couldn't create BIO object."); + VcoreThrowMsg(Exception::InternalError, "Couldn't create BIO object."); } BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); - DPL::ScopedFree<char> tmp(strdup(m_input.c_str())); + VcoreDPL::ScopedFree<char> tmp(strdup(m_input.c_str())); m_input.clear(); bmem = BIO_new_mem_buf(tmp.Get(), len); if (!bmem) { BIO_free(b64); - LogError("Internal error in BIO"); - ThrowMsg(Exception::InternalError, "Internal error in BIO"); + WrtLogE("Internal error in BIO"); + VcoreThrowMsg(Exception::InternalError, "Internal error in BIO"); } bmem = BIO_push(b64, bmem); if (!bmem) { BIO_free(b64); - LogError("Internal error in BIO"); - ThrowMsg(Exception::InternalError, "Internal error in BIO"); + WrtLogE("Internal error in BIO"); + VcoreThrowMsg(Exception::InternalError, "Internal error in BIO"); } int readlen = BIO_read(bmem, buffer.Get(), len); @@ -195,8 +198,8 @@ bool Base64Decoder::finalize() std::string Base64Decoder::get() const { if (!m_finalized) { - LogWarning("Not finalized."); - ThrowMsg(Exception::NotFinalized, "Not finalized"); + WrtLogW("Not finalized."); + VcoreThrowMsg(Exception::NotFinalized, "Not finalized"); } return m_output; } diff --git a/vcore/src/vcore/Base64.h b/vcore/src/vcore/Base64.h index 520662e..b961d98 100644 --- a/vcore/src/vcore/Base64.h +++ b/vcore/src/vcore/Base64.h @@ -17,23 +17,20 @@ #define _BASE64_H_ #include <string> -#include <dpl/noncopyable.h> -#include <dpl/exception.h> +#include <vcore/exception.h> struct bio_st; typedef bio_st BIO; namespace ValidationCore { -class Base64Encoder : public DPL::Noncopyable -{ - public: - class Exception - { - public: - DECLARE_EXCEPTION_TYPE(DPL::Exception, Base) - DECLARE_EXCEPTION_TYPE(Base, InternalError) - DECLARE_EXCEPTION_TYPE(Base, NotFinalized) - DECLARE_EXCEPTION_TYPE(Base, AlreadyFinalized) +class Base64Encoder { +public: + class Exception { + public: + VCORE_DECLARE_EXCEPTION_TYPE(ValidationCore::Exception, Base) + VCORE_DECLARE_EXCEPTION_TYPE(Base, InternalError) + VCORE_DECLARE_EXCEPTION_TYPE(Base, NotFinalized) + VCORE_DECLARE_EXCEPTION_TYPE(Base, AlreadyFinalized) }; Base64Encoder(); void append(const std::string &data); @@ -42,22 +39,23 @@ class Base64Encoder : public DPL::Noncopyable void reset(); ~Base64Encoder(); - private: +private: + Base64Encoder(const Base64Encoder &); + const Base64Encoder &operator=(const Base64Encoder &); + BIO *m_b64; BIO *m_bmem; bool m_finalized; }; -class Base64Decoder : public DPL::Noncopyable -{ - public: - class Exception - { - public: - DECLARE_EXCEPTION_TYPE(DPL::Exception, Base) - DECLARE_EXCEPTION_TYPE(Base, InternalError) - DECLARE_EXCEPTION_TYPE(Base, NotFinalized) - DECLARE_EXCEPTION_TYPE(Base, AlreadyFinalized) +class Base64Decoder { +public: + class Exception { + public: + VCORE_DECLARE_EXCEPTION_TYPE(ValidationCore::Exception, Base) + VCORE_DECLARE_EXCEPTION_TYPE(Base, InternalError) + VCORE_DECLARE_EXCEPTION_TYPE(Base, NotFinalized) + VCORE_DECLARE_EXCEPTION_TYPE(Base, AlreadyFinalized) }; Base64Decoder(); void append(const std::string &data); @@ -69,11 +67,12 @@ class Base64Decoder : public DPL::Noncopyable bool finalize(); std::string get() const; void reset(); - ~Base64Decoder() - { - } + ~Base64Decoder() {} + +private: + Base64Decoder(const Base64Decoder &); + const Base64Decoder &operator=(const Base64Decoder &); - private: std::string m_input; std::string m_output; bool m_finalized; diff --git a/vcore/src/vcore/CRL.h b/vcore/src/vcore/CRL.h index 51915ee..7a52569 100644 --- a/vcore/src/vcore/CRL.h +++ b/vcore/src/vcore/CRL.h @@ -26,29 +26,24 @@ #include <list> #include <string> -#include <dpl/exception.h> -#include <dpl/noncopyable.h> -#include <dpl/log/log.h> - #include <vcore/Certificate.h> #include <vcore/CertificateCollection.h> #include <vcore/VerificationStatus.h> #include <vcore/CRLCacheInterface.h> +#include <vcore/exception.h> namespace ValidationCore { - namespace CRLException { -DECLARE_EXCEPTION_TYPE(DPL::Exception, CRLException) -DECLARE_EXCEPTION_TYPE(CRLException, StorageError) -DECLARE_EXCEPTION_TYPE(CRLException, DownloadFailed) -DECLARE_EXCEPTION_TYPE(CRLException, InternalError) -DECLARE_EXCEPTION_TYPE(CRLException, InvalidParameter) +VCORE_DECLARE_EXCEPTION_TYPE(ValidationCore::Exception, Base) +VCORE_DECLARE_EXCEPTION_TYPE(Base, StorageError) +VCORE_DECLARE_EXCEPTION_TYPE(Base, InternalError) +VCORE_DECLARE_EXCEPTION_TYPE(Base, InvalidParameter) + } // namespace CRLException class CRLImpl; -class CRL : DPL::Noncopyable -{ +class CRL { public: typedef std::list<std::string> StringList; @@ -67,6 +62,7 @@ public: bool isRevoked; /**< True when certificate is revoked */ }; + CRL() = delete; CRL(CRLCacheInterface *ptr); virtual ~CRL(); @@ -152,6 +148,9 @@ public: private: friend class CachedCRL; CRLImpl *m_impl; + + CRL(const CRL &); + const CRL &operator=(const CRL &); }; } // namespace ValidationCore diff --git a/vcore/src/vcore/CRLImpl.cpp b/vcore/src/vcore/CRLImpl.cpp index b2e18f9..6602e17 100644 --- a/vcore/src/vcore/CRLImpl.cpp +++ b/vcore/src/vcore/CRLImpl.cpp @@ -16,7 +16,7 @@ /*! * @author Piotr Marcinkiewicz(p.marcinkiew@samsung.com) * @version 0.2 - * @file CRLImpl.h + * @file CRLImpl.cpp * @brief Routines for certificate validation over CRL */ @@ -32,9 +32,8 @@ #include <openssl/pem.h> #include <openssl/x509v3.h> -#include <dpl/log/log.h> +#include <dpl/log/wrt_log.h> #include <dpl/assert.h> -#include <dpl/exception.h> #include <dpl/db/orm.h> #include <dpl/foreach.h> @@ -42,11 +41,9 @@ #include <vcore/Certificate.h> #include <vcore/SoupMessageSendSync.h> #include <vcore/CRLCacheInterface.h> -#include <tzplatform_config.h> namespace { -const char *CRL_LOOKUP_DIR_1 = tzplatform_mkpath(TZ_SYS_SHARE, "cert-svc/ca-certs/code-signing/wac"); -const char *CRL_LOOKUP_DIR_2 = tzplatform_mkpath(TZ_SYS_SHARE, "cert-svc/certs/code-signing/wac"); +const char *CRL_LOOKUP_DIR = "/usr/share/ca-certificates/wac"; } //anonymous namespace namespace ValidationCore { @@ -58,7 +55,7 @@ CRL::StringList CRLImpl::getCrlUris(const CertificatePtr &argCert) if (!result.empty()) { return result; } - LogInfo("No distribution points found. Getting from CA cert."); + WrtLogI("No distribution points found. Getting from CA cert."); X509_STORE_CTX *ctx = createContext(argCert); X509_OBJECT obj; @@ -69,7 +66,7 @@ CRL::StringList CRLImpl::getCrlUris(const CertificatePtr &argCert) &obj); X509_STORE_CTX_free(ctx); if (0 >= retVal) { - LogError("No dedicated CA certificate available"); + WrtLogE("No dedicated CA certificate available"); return result; } CertificatePtr caCert(new Certificate(obj.data.x509)); @@ -82,36 +79,27 @@ CRLImpl::CRLImpl(CRLCacheInterface *ptr) { Assert(m_crlCache != NULL); - LogInfo("CRL storage initialization."); + WrtLogI("CRL storage initialization."); m_store = X509_STORE_new(); - if (!m_store) { - LogError("Failed to create new store."); - ThrowMsg(CRLException::StorageError, - "Not possible to create new store."); - } + if (!m_store) + VcoreThrowMsg(CRLException::StorageError, + "impossible to create new store"); + m_lookup = X509_STORE_add_lookup(m_store, X509_LOOKUP_hash_dir()); if (!m_lookup) { cleanup(); - LogError("Failed to add hash dir lookup"); - ThrowMsg(CRLException::StorageError, - "Not possible to add hash dir lookup."); + VcoreThrowMsg(CRLException::StorageError, + "impossible to add hash dir lookup"); } // Add hash dir pathname for CRL checks - bool retVal = X509_LOOKUP_add_dir(m_lookup, - CRL_LOOKUP_DIR_1, X509_FILETYPE_PEM) == 1; - retVal &= retVal && (X509_LOOKUP_add_dir(m_lookup, CRL_LOOKUP_DIR_1, - X509_FILETYPE_ASN1) == 1); - retVal &= retVal && (X509_LOOKUP_add_dir(m_lookup, CRL_LOOKUP_DIR_2, - X509_FILETYPE_PEM) == 1); - retVal &= retVal && (X509_LOOKUP_add_dir(m_lookup, CRL_LOOKUP_DIR_2, - X509_FILETYPE_ASN1) == 1); + bool retVal = X509_LOOKUP_add_dir(m_lookup, CRL_LOOKUP_DIR, X509_FILETYPE_PEM) == 1; + retVal &= X509_LOOKUP_add_dir(m_lookup, CRL_LOOKUP_DIR, X509_FILETYPE_ASN1) == 1; if (!retVal) { - LogError("Failed to add lookup dir for PEM files."); cleanup(); - ThrowMsg(CRLException::StorageError, - "Failed to add lookup dir for PEM files."); + VcoreThrowMsg(CRLException::StorageError, + "Failed to add lookup dir for PEM files"); } - LogInfo("CRL storage initialization complete."); + WrtLogI("CRL storage initialization complete."); } CRLImpl::~CRLImpl() @@ -122,7 +110,7 @@ CRLImpl::~CRLImpl() void CRLImpl::cleanup() { - LogInfo("Free CRL storage"); + WrtLogI("Free CRL storage"); // STORE is responsible for LOOKUP release // X509_LOOKUP_free(m_lookup); X509_STORE_free(m_store); @@ -136,7 +124,7 @@ CRL::RevocationStatus CRLImpl::checkCertificate(const CertificatePtr &argCert) FOREACH(it, crlUris) { CRLDataPtr crl = getCRL(*it); if (!crl) { - LogDebug("CRL not found for URI: " << *it); + WrtLogD("CRL not found for URI: %s", (*it).c_str()); continue; } X509_CRL *crlInternal = convertToInternal(crl); @@ -150,17 +138,17 @@ CRL::RevocationStatus CRLImpl::checkCertificate(const CertificatePtr &argCert) // If nextUpdate is not set assume it is actual. retStatus.isCRLValid = true; } - LogInfo("CRL valid: " << retStatus.isCRLValid); + WrtLogI("CRL valid: %d", retStatus.isCRLValid); X509_REVOKED rev; rev.serialNumber = X509_get_serialNumber(argCert->getX509()); // sk_X509_REVOKED_find returns index if serial number is found on list retVal = sk_X509_REVOKED_find(crlInternal->crl->revoked, &rev); X509_CRL_free(crlInternal); retStatus.isRevoked = retVal != -1; - LogInfo("CRL revoked: " << retStatus.isRevoked); + WrtLogI("CRL revoked: %d", retStatus.isRevoked); if (!retStatus.isRevoked && isOutOfDate(crl)) { - LogDebug("Certificate is not Revoked, but CRL is outOfDate."); + WrtLogD("Certificate is not Revoked, but CRL is outOfDate."); continue; } @@ -171,14 +159,11 @@ CRL::RevocationStatus CRLImpl::checkCertificate(const CertificatePtr &argCert) return retStatus; } -CRL::RevocationStatus CRLImpl::checkCertificateChain(CertificateCollection - certChain) +CRL::RevocationStatus CRLImpl::checkCertificateChain(CertificateCollection certChain) { - if (!certChain.sort()) { - LogError("Certificate list doesn't create chain."); - ThrowMsg(CRLException::InvalidParameter, - "Certificate list doesn't create chain."); - } + if (!certChain.sort()) + VcoreThrowMsg(CRLException::InvalidParameter, + "Certificate list doesn't create chain."); CRL::RevocationStatus ret; ret.isCRLValid = true; @@ -186,25 +171,27 @@ CRL::RevocationStatus CRLImpl::checkCertificateChain(CertificateCollection const CertificateList &certList = certChain.getChain(); FOREACH(it, certList) { if (!(*it)->isRootCert()) { - LogInfo("Certificate common name: " << *((*it)->getCommonName())); + WrtLogI("Certificate common name: %s", (*it)->getCommonName().c_str()); CRL::RevocationStatus certResult = checkCertificate(*it); ret.isCRLValid &= certResult.isCRLValid; ret.isRevoked |= certResult.isRevoked; if (ret.isCRLValid && !ret.isRevoked) { addToStore(*it); } + if (ret.isRevoked) { return ret; } } } + return ret; } VerificationStatus CRLImpl::checkEndEntity(CertificateCollection &chain) { if (!chain.sort() && !chain.empty()) { - LogInfo("Could not find End Entity certificate. " + WrtLogI("Could not find End Entity certificate. " "Collection does not form chain."); return VERIFICATION_STATUS_ERROR; } @@ -244,13 +231,13 @@ bool CRLImpl::isOutOfDate(const CRLDataPtr &crl) const { bool CRLImpl::updateList(const CertificatePtr &argCert, const CRL::UpdatePolicy updatePolicy) { - LogInfo("Update CRL for certificate"); + WrtLogI("Update CRL for certificate"); // Retrieve distribution points CRL::StringList crlUris = getCrlUris(argCert); FOREACH(it, crlUris) { // Try to get CRL from database - LogInfo("Getting CRL for URI: " << *it); + WrtLogI("Getting CRL for URI: %s", (*it).c_str()); bool downloaded = false; @@ -263,24 +250,24 @@ bool CRLImpl::updateList(const CertificatePtr &argCert, } if (!!crl && isOutOfDate(crl)) { - LogDebug("Crl out of date - downloading."); + WrtLogD("Crl out of date - downloading."); crl = downloadCRL(*it); downloaded = true; } if (!crl) { - LogDebug("Crl not found in cache - downloading."); + WrtLogD("Crl not found in cache - downloading."); crl = downloadCRL(*it); downloaded = true; } if (!crl) { - LogDebug("Failed to obtain CRL. URL: " << *it); + WrtLogD("Failed to obtain CRL. URL: %s", (*it).c_str()); continue; } if (!!crl && isOutOfDate(crl)) { - LogError("CRL out of date. Broken URL: " << *it); + WrtLogE("CRL out of date. Broken URL: %s", (*it).c_str()); } // Make X509 internal structure @@ -288,7 +275,7 @@ bool CRLImpl::updateList(const CertificatePtr &argCert, //Check if CRL is signed if (!verifyCRL(crlInternal, argCert)) { - LogError("Failed to verify CRL. URI: " << crl->uri); + WrtLogE("Failed to verify CRL. URI: %s", (crl->uri).c_str()); X509_CRL_free(crlInternal); return false; } @@ -333,7 +320,7 @@ bool CRLImpl::verifyCRL(X509_CRL *crl, X509_CRL_get_issuer(crl), &obj); X509_STORE_CTX_free(ctx); if (0 >= retVal) { - LogError("Unknown CRL issuer certificate!"); + WrtLogE("Unknown CRL issuer certificate!"); return false; } @@ -341,19 +328,19 @@ bool CRLImpl::verifyCRL(X509_CRL *crl, EVP_PKEY *pkey = X509_get_pubkey(obj.data.x509); X509_OBJECT_free_contents(&obj); if (!pkey) { - LogError("Failed to get issuer's public key."); + WrtLogE("Failed to get issuer's public key."); return false; } retVal = X509_CRL_verify(crl, pkey); EVP_PKEY_free(pkey); if (0 > retVal) { - LogError("Failed to verify CRL."); + WrtLogE("Failed to verify CRL."); return false; } else if (0 == retVal) { - LogError("CRL is invalid"); + WrtLogE("CRL is invalid"); return false; } - LogInfo("CRL is valid."); + WrtLogI("CRL is valid."); return true; } @@ -362,10 +349,10 @@ bool CRLImpl::isPEMFormat(const CRLDataPtr &crl) const const char *pattern = "-----BEGIN X509 CRL-----"; std::string content(crl->buffer, crl->length); if (content.find(pattern) != std::string::npos) { - LogInfo("CRL is in PEM format."); + WrtLogI("CRL is in PEM format."); return true; } - LogInfo("CRL is in DER format."); + WrtLogI("CRL is in DER format."); return false; } @@ -375,11 +362,10 @@ X509_CRL *CRLImpl::convertToInternal(const CRLDataPtr &crl) const X509_CRL *ret = NULL; if (isPEMFormat(crl)) { BIO *bmem = BIO_new_mem_buf(crl->buffer, crl->length); - if (!bmem) { - LogError("Failed to allocate memory in BIO"); - ThrowMsg(CRLException::InternalError, - "Failed to allocate memory in BIO"); - } + if (!bmem) + VcoreThrowMsg(CRLException::InternalError, + "Failed to allocate memory in BIO"); + ret = PEM_read_bio_X509_CRL(bmem, NULL, NULL, NULL); BIO_free_all(bmem); } else { @@ -389,11 +375,10 @@ X509_CRL *CRLImpl::convertToInternal(const CRLDataPtr &crl) const reinterpret_cast<unsigned char*>(crl->buffer); ret = d2i_X509_CRL(NULL, &buffer, crl->length); } - if (!ret) { - LogError("Failed to convert to internal structure"); - ThrowMsg(CRLException::InternalError, - "Failed to convert to internal structure"); - } + + if (!ret) + VcoreThrowMsg(CRLException::InternalError, + "Failed to convert to internal structure"); return ret; } @@ -401,9 +386,9 @@ X509_STORE_CTX *CRLImpl::createContext(const CertificatePtr &argCert) { X509_STORE_CTX *ctx; ctx = X509_STORE_CTX_new(); - if (!ctx) { - ThrowMsg(CRLException::StorageError, "Failed to create new context."); - } + if (!ctx) + VcoreThrowMsg(CRLException::StorageError, "Failed to create new ctx"); + X509_STORE_CTX_init(ctx, m_store, argCert->getX509(), NULL); return ctx; } @@ -421,7 +406,7 @@ CRLImpl::CRLDataPtr CRLImpl::downloadCRL(const std::string &uri) &cpath, &use_ssl)) { - LogWarning("Error in OCSP_parse_url"); + WrtLogW("Error in OCSP_parse_url"); return CRLDataPtr(); } @@ -440,7 +425,7 @@ CRLImpl::CRLDataPtr CRLImpl::downloadCRL(const std::string &uri) message.setHeader("Host", host); if (SoupMessageSendSync::REQUEST_STATUS_OK != message.sendSync()) { - LogWarning("Error in sending network request."); + WrtLogW("Error in sending network request."); return CRLDataPtr(); } @@ -453,22 +438,21 @@ CRLImpl::CRLDataPtr CRLImpl::getCRL(const std::string &uri) const CRLCachedData cachedCrl; cachedCrl.distribution_point = uri; if (!(m_crlCache->getCRLResponse(&cachedCrl))) { - LogInfo("CRL not present in database. URI: " << uri); + WrtLogI("CRL not present in database. URI: %s", uri.c_str()); return CRLDataPtr(); } std::string body = cachedCrl.crl_body; - LogInfo("CRL found in database."); + WrtLogI("CRL found in database."); //TODO: remove when ORM::blob available //Encode buffer to base64 format to store in database Base64Decoder decoder; decoder.append(body); - if (!decoder.finalize()) { - LogError("Failed to decode base64 format."); - ThrowMsg(CRLException::StorageError, "Failed to decode base64 format."); - } + if (!decoder.finalize()) + VcoreThrowMsg(CRLException::StorageError, + "Failed to decode base64 format."); std::string crlBody = decoder.get(); std::unique_ptr<char[]> bodyBuffer(new char[crlBody.length()]); @@ -482,9 +466,9 @@ void CRLImpl::updateCRL(const CRLDataPtr &crl) //TODO: remove when ORM::blob available //Encode buffer to base64 format to store in database Base64Encoder encoder; - if (!crl || !crl->buffer) { - ThrowMsg(CRLException::InternalError, "CRL buffer is empty"); - } + if (!crl || !crl->buffer) + VcoreThrowMsg(CRLException::InternalError, "CRL buffer is empty"); + encoder.append(std::string(crl->buffer, crl->length)); encoder.finalize(); std::string b64CRLBody = encoder.get(); diff --git a/vcore/src/vcore/CRLImpl.h b/vcore/src/vcore/CRLImpl.h index 72d8d43..68475d5 100644 --- a/vcore/src/vcore/CRLImpl.h +++ b/vcore/src/vcore/CRLImpl.h @@ -23,14 +23,12 @@ #ifndef _VALIDATION_CORE_ENGINE_CRLIMPL_H_ #define _VALIDATION_CORE_ENGINE_CRLIMPL_H_ -#include <dpl/exception.h> +#include <string.h> #include <memory> -#include <dpl/noncopyable.h> -#include <dpl/log/log.h> - #include <openssl/x509.h> -#include <vcore/CRL.h> +#include <dpl/noncopyable.h> + #include <vcore/Certificate.h> #include <vcore/CertificateCollection.h> #include <vcore/SoupMessageSendBase.h> @@ -38,18 +36,18 @@ #include <vcore/CRLCacheInterface.h> #include <vcore/TimeConversion.h> +#include <vcore/CRL.h> + namespace ValidationCore { -class CRLImpl : DPL::Noncopyable -{ - protected: +class CRLImpl : VcoreDPL::Noncopyable { +protected: X509_STORE *m_store; X509_LOOKUP *m_lookup; CRLCacheInterface *m_crlCache; - class CRLData : DPL::Noncopyable - { - public: + class CRLData : VcoreDPL::Noncopyable { + public: //TODO: change to SharedArray when available char *buffer; size_t length; @@ -75,7 +73,6 @@ class CRLImpl : DPL::Noncopyable ~CRLData() { - LogInfo("Delete buffer"); delete[] buffer; } }; @@ -94,7 +91,8 @@ class CRLImpl : DPL::Noncopyable bool isOutOfDate(const CRLDataPtr &crl) const; friend class CachedCRL; - public: + +public: CRLImpl(CRLCacheInterface *ptr); ~CRLImpl(); diff --git a/vcore/src/vcore/CachedCRL.cpp b/vcore/src/vcore/CachedCRL.cpp index dfcd04b..bdc5123 100644 --- a/vcore/src/vcore/CachedCRL.cpp +++ b/vcore/src/vcore/CachedCRL.cpp @@ -23,7 +23,7 @@ #include <vcore/CachedCRL.h> #include <dpl/foreach.h> -#include <dpl/log/log.h> +#include <dpl/log/wrt_log.h> #include <dpl/foreach.h> #include <vcore/CRLImpl.h> @@ -86,7 +86,7 @@ VerificationStatus CachedCRL::check(const CertificateCollection &certs) } if (!allValid) { // problems with CRL validity - LogDebug("Some CRLs not valid"); + WrtLogD("Some CRLs not valid"); } CRL::RevocationStatus stat; Try { @@ -96,24 +96,24 @@ VerificationStatus CachedCRL::check(const CertificateCollection &certs) return VERIFICATION_STATUS_ERROR; } if (stat.isRevoked) { - LogDebug("Status REVOKED"); + WrtLogD("Status REVOKED"); return VERIFICATION_STATUS_REVOKED; } - LogDebug("Status GOOD"); + WrtLogD("Status GOOD"); return VERIFICATION_STATUS_GOOD; } VerificationStatus CachedCRL::checkEndEntity(CertificateCollection &certs) { if (certs.empty()) { - LogError("Collection empty. This should never happen."); - LogDebug("Status ERROR"); + WrtLogE("Collection empty. This should never happen."); + WrtLogD("Status ERROR"); return VERIFICATION_STATUS_ERROR; } if (!certs.sort()) { - LogError("Could not find End Entity certificate. " + WrtLogE("Could not find End Entity certificate. " "Collection does not form chain."); - LogDebug("Status ERROR"); + WrtLogD("Status ERROR"); return VERIFICATION_STATUS_ERROR; } CRLImpl crl(new CRLCacheDAO); @@ -131,15 +131,15 @@ VerificationStatus CachedCRL::checkEndEntity(CertificateCollection &certs) } if (!allValid) { // problems with CRL validity - LogDebug("Some CRLs not valid"); + WrtLogD("Some CRLs not valid"); } CertificateList::const_iterator iter = certs.begin(); CRL::RevocationStatus stat = crl.checkCertificate(*iter); if (stat.isRevoked) { - LogDebug("Status REVOKED"); + WrtLogD("Status REVOKED"); return VERIFICATION_STATUS_REVOKED; } - LogDebug("Status GOOD"); + WrtLogD("Status GOOD"); return VERIFICATION_STATUS_GOOD; } @@ -164,7 +164,7 @@ bool CachedCRL::updateCRLForUri(const std::string &uri, bool useExpiredShift) } if (CertificateCacheDAO::getCRLResponse(&cachedCRL)) { if (now < cachedCRL.next_update_time) { - LogDebug("Cached CRL still valid for: " << uri); + WrtLogD("Cached CRL still valid for: %s", uri.c_str()); return true; } } @@ -172,7 +172,7 @@ bool CachedCRL::updateCRLForUri(const std::string &uri, bool useExpiredShift) CRLImpl crl(new CRLCacheDAO); CRLImpl::CRLDataPtr list = crl.downloadCRL(uri); if (!list) { - LogWarning("Could not retreive CRL from " << uri); + WrtLogW("Could not retreive CRL from %s", uri.c_str()); return false; } crl.updateCRL(list); diff --git a/vcore/src/vcore/CachedOCSP.cpp b/vcore/src/vcore/CachedOCSP.cpp index c0e3695..48c613f 100644 --- a/vcore/src/vcore/CachedOCSP.cpp +++ b/vcore/src/vcore/CachedOCSP.cpp @@ -25,7 +25,7 @@ #include <time.h> #include <dpl/foreach.h> -#include <dpl/log/log.h> +#include <dpl/log/wrt_log.h> #include <dpl/foreach.h> #include <vcore/OCSP.h> @@ -75,9 +75,9 @@ VerificationStatus CachedOCSP::check(const CertificateCollection &certs) db_status.end_entity_check = false; if (CertificateCacheDAO::getOCSPStatus(&db_status)) { - LogDebug("Found cache entry for OCSP"); + WrtLogD("Found cache entry for OCSP"); if (now < db_status.next_update_time) { - LogDebug("Cache response valid"); + WrtLogD("Cache response valid"); return db_status.ocsp_status; } } @@ -109,9 +109,9 @@ VerificationStatus CachedOCSP::checkEndEntity(CertificateCollection &certs) db_status.end_entity_check = true; if (CertificateCacheDAO::getOCSPStatus(&db_status)) { - LogDebug("Found cache entry for OCSP"); + WrtLogD("Found cache entry for OCSP"); if (now < db_status.next_update_time) { - LogDebug("Cache response valid"); + WrtLogD("Cache response valid"); return db_status.ocsp_status; } } @@ -150,7 +150,7 @@ void CachedOCSP::updateCache() CertificateCollection col; col.load(db_status->cert_chain); if (!col.sort()) { - LogError("Certificate collection does not create chain."); + WrtLogE("Certificate collection does not create chain."); continue; } @@ -183,7 +183,7 @@ void CachedOCSP::getCertsForEndEntity( const CertificateCollection &certs, CertificateList* clst) { if (NULL == clst) { - LogError("NULL pointer"); + WrtLogE("NULL pointer"); return; } diff --git a/vcore/src/vcore/CertStoreType.cpp b/vcore/src/vcore/CertStoreType.cpp index 4a994b7..d435fb6 100644 --- a/vcore/src/vcore/CertStoreType.cpp +++ b/vcore/src/vcore/CertStoreType.cpp @@ -23,46 +23,57 @@ */ #include <vcore/CertStoreType.h> +#include <string.h> + namespace ValidationCore { namespace CertStoreId { Set::Set() : m_certificateStorage(0) - #ifdef TIZEN_FEATURE_CERT_SVC_OCSP_CRL +#ifdef TIZEN_FEATURE_CERT_SVC_OCSP_CRL , m_ocspUrl(NULL) - #endif +#endif {} -void Set::add(Type second) { +Set::~Set() +{ +#ifdef TIZEN_FEATURE_CERT_SVC_OCSP_CRL + delete[] m_ocspUrl; +#endif +} + +void Set::add(Type second) +{ m_certificateStorage |= second; } #ifdef TIZEN_FEATURE_CERT_SVC_OCSP_CRL -void Set::add(std::string ocspUrl) { +void Set::add(std::string ocspUrl) +{ - if (strlen(ocspUrl.c_str()) == 0) - { - return; - } + if (ocspUrl.length() == 0) + return; - m_ocspUrl = new char[ocspUrl.size() + 1]; - if (m_ocspUrl != NULL) { - strncpy(m_ocspUrl, ocspUrl.c_str(), ocspUrl.size() + 1); - } + m_ocspUrl = new char[ocspUrl.length() + 1]; + if (m_ocspUrl) + strncpy(m_ocspUrl, ocspUrl.c_str(), ocspUrl.length() + 1); } #endif -bool Set::contains(Type second) const { +bool Set::contains(Type second) const +{ return static_cast<bool>(m_certificateStorage & second); } -bool Set::isEmpty() const { +bool Set::isEmpty() const +{ return m_certificateStorage == 0; } #ifdef TIZEN_FEATURE_CERT_SVC_OCSP_CRL -char* Set::getOcspUrl() { - return m_ocspUrl; +char* Set::getOcspUrl() +{ + return m_ocspUrl; } #endif diff --git a/vcore/src/vcore/CertStoreType.h b/vcore/src/vcore/CertStoreType.h index 409d9b7..c07e0ce 100644 --- a/vcore/src/vcore/CertStoreType.h +++ b/vcore/src/vcore/CertStoreType.h @@ -24,7 +24,7 @@ #ifndef _VALIDATION_CORE_CERTSTORETYPE_H_ #define _VALIDATION_CORE_CERTSTORETYPE_H_ -#include <string.h> +#include <string> namespace ValidationCore { namespace CertStoreId { @@ -35,6 +35,7 @@ const Type TIZEN_DEVELOPER = 1; // RootCA certificates for author signatures. const Type TIZEN_TEST = 1 << 1; const Type TIZEN_VERIFY = 1 << 2; +const Type TIZEN_STORE = 1 << 3; // RootCA's visibility level : public const Type VIS_PUBLIC = 1 << 6; // RootCA's visibility level : partner @@ -46,26 +47,26 @@ const Type VIS_PARTNER_MANUFACTURER = 1 << 9; // RootCA's visibility level : platform const Type VIS_PLATFORM = 1 << 10; -class Set -{ - public: +class Set { +public: Set(); + virtual ~Set(); void add(Type second); - #ifdef TIZEN_FEATURE_CERT_SVC_OCSP_CRL +#ifdef TIZEN_FEATURE_CERT_SVC_OCSP_CRL void add(std::string ocspUrl); char* getOcspUrl(); - #endif +#endif - bool contains(Type second) const; + bool contains(Type second) const; bool isEmpty() const; private: Type m_certificateStorage; - #ifdef TIZEN_FEATURE_CERT_SVC_OCSP_CRL +#ifdef TIZEN_FEATURE_CERT_SVC_OCSP_CRL char* m_ocspUrl; - #endif +#endif }; } // namespace CertStoreId diff --git a/vcore/src/vcore/Certificate.cpp b/vcore/src/vcore/Certificate.cpp index 45bfba6..55bcd3a 100644 --- a/vcore/src/vcore/Certificate.cpp +++ b/vcore/src/vcore/Certificate.cpp @@ -29,7 +29,7 @@ #include <openssl/bn.h> #include <dpl/assert.h> -#include <dpl/log/log.h> +#include <dpl/log/wrt_log.h> #include <vcore/Base64.h> #include <vcore/TimeConversion.h> @@ -40,11 +40,9 @@ Certificate::Certificate(X509 *cert) { Assert(cert); m_x509 = X509_dup(cert); - if (!m_x509) { - LogWarning("Internal Openssl error in d2i_X509 function."); - ThrowMsg(Exception::OpensslInternalError, - "Internal Openssl error in d2i_X509 function."); - } + if (!m_x509) + VcoreThrowMsg(Certificate::Exception::OpensslInternalError, + "Internal Openssl error in d2i_X509 function."); } Certificate::Certificate(cert_svc_mem_buff &buffer) @@ -52,11 +50,9 @@ Certificate::Certificate(cert_svc_mem_buff &buffer) Assert(buffer.data); const unsigned char *ptr = buffer.data; m_x509 = d2i_X509(NULL, &ptr, buffer.size); - if (!m_x509) { - LogWarning("Internal Openssl error in d2i_X509 function."); - ThrowMsg(Exception::OpensslInternalError, - "Internal Openssl error in d2i_X509 function."); - } + if (!m_x509) + VcoreThrowMsg(Certificate::Exception::OpensslInternalError, + "Internal Openssl error in d2i_X509 function."); } Certificate::Certificate(const std::string &der, @@ -73,7 +69,7 @@ Certificate::Certificate(const std::string &der, base64.reset(); base64.append(der); if (!base64.finalize()) { - LogWarning("Error during decoding"); + WrtLogW("Error during decoding"); } tmp = base64.get(); ptr = reinterpret_cast<const unsigned char*>(tmp.c_str()); @@ -84,11 +80,9 @@ Certificate::Certificate(const std::string &der, } m_x509 = d2i_X509(NULL, &ptr, size); - if (!m_x509) { - LogError("Internal Openssl error in d2i_X509 function."); - ThrowMsg(Exception::OpensslInternalError, - "Internal Openssl error in d2i_X509 function."); - } + if (!m_x509) + VcoreThrowMsg(Certificate::Exception::OpensslInternalError, + "Internal Openssl error in d2i_X509 function."); } Certificate::~Certificate() @@ -105,11 +99,9 @@ std::string Certificate::getDER(void) const { unsigned char *rawDer = NULL; int size = i2d_X509(m_x509, &rawDer); - if (!rawDer || size <= 0) { - LogError("i2d_X509 failed"); - ThrowMsg(Exception::OpensslInternalError, - "i2d_X509 failed"); - } + if (!rawDer || size <= 0) + VcoreThrowMsg(Certificate::Exception::OpensslInternalError, + "i2d_X509 failed"); std::string output(reinterpret_cast<char*>(rawDer), size); OPENSSL_free(rawDer); @@ -128,7 +120,7 @@ std::string Certificate::getBase64(void) const bool Certificate::isSignedBy(const CertificatePtr &parent) const { if (!parent) { - LogDebug("Invalid certificate parameter."); + WrtLogD("Invalid certificate parameter."); return false; } return 0 == X509_NAME_cmp(X509_get_subject_name(parent->m_x509), @@ -143,21 +135,15 @@ Certificate::Fingerprint Certificate::getFingerprint( Fingerprint raw; if (type == FINGERPRINT_MD5) { - if (!X509_digest(m_x509, EVP_md5(), fingerprint, &fingerprintlength)) { - LogError("MD5 digest counting failed!"); - ThrowMsg(Exception::OpensslInternalError, - "MD5 digest counting failed!"); - } + if (!X509_digest(m_x509, EVP_md5(), fingerprint, &fingerprintlength)) + VcoreThrowMsg(Certificate::Exception::OpensslInternalError, + "MD5 digest counting failed!"); } if (type == FINGERPRINT_SHA1) { - if (!X509_digest(m_x509, EVP_sha1(), fingerprint, - &fingerprintlength)) - { - LogError("SHA1 digest counting failed"); - ThrowMsg(Exception::OpensslInternalError, - "SHA1 digest counting failed!"); - } + if (!X509_digest(m_x509, EVP_sha1(), fingerprint, &fingerprintlength)) + VcoreThrowMsg(Certificate::Exception::OpensslInternalError, + "SHA1 digest counting failed"); } raw.resize(fingerprintlength); // improve performance @@ -181,30 +167,28 @@ X509_NAME *Certificate::getX509Name(FieldType type) const Assert("Invalid field type."); } - if (!name) { - LogError("Error during x509 name extraction."); - ThrowMsg(Exception::OpensslInternalError, - "Error during x509 name extraction."); - } + if (!name) + VcoreThrowMsg(Certificate::Exception::OpensslInternalError, + "Error during x509 name extraction."); return name; } -DPL::String Certificate::getOneLine(FieldType type) const +std::string Certificate::getOneLine(FieldType type) const { X509_NAME *name = getX509Name(type); static const int MAXB = 1024; - char buffer[MAXB]; + char buffer[MAXB] = {0, }; X509_NAME_oneline(name, buffer, MAXB); - return DPL::FromUTF8String(buffer); + + return std::string(buffer); } -DPL::String Certificate::getField(FieldType type, - int fieldNid) const +std::string Certificate::getField(FieldType type, int fieldNid) const { X509_NAME *subjectName = getX509Name(type); X509_NAME_ENTRY *subjectEntry = NULL; - DPL::String output; + std::string output; int entryCount = X509_NAME_entry_count(subjectName); for (int i = 0; i < entryCount; ++i) { @@ -229,59 +213,61 @@ DPL::String Certificate::getField(FieldType type, int nLength = ASN1_STRING_to_UTF8(&pData, pASN1Str); - if (nLength < 0) { - LogError("Reading field error."); - ThrowMsg(Exception::OpensslInternalError, - "Reading field error."); - } + if (nLength < 0) + VcoreThrowMsg(Certificate::Exception::OpensslInternalError, + "Reading field error."); - std::string strEntry(reinterpret_cast<char*>(pData), - nLength); - output = DPL::FromUTF8String(strEntry); - OPENSSL_free(pData); + if (!pData) { + output = std::string(); + } + else { + output = std::string(reinterpret_cast<char*>(pData), nLength); + OPENSSL_free(pData); + } } + return output; } -DPL::String Certificate::getCommonName(FieldType type) const +std::string Certificate::getCommonName(FieldType type) const { return getField(type, NID_commonName); } -DPL::String Certificate::getCountryName(FieldType type) const +std::string Certificate::getCountryName(FieldType type) const { return getField(type, NID_countryName); } -DPL::String Certificate::getStateOrProvinceName(FieldType type) const +std::string Certificate::getStateOrProvinceName(FieldType type) const { return getField(type, NID_stateOrProvinceName); } -DPL::String Certificate::getLocalityName(FieldType type) const +std::string Certificate::getLocalityName(FieldType type) const { return getField(type, NID_localityName); } -DPL::String Certificate::getOrganizationName(FieldType type) const +std::string Certificate::getOrganizationName(FieldType type) const { return getField(type, NID_organizationName); } -DPL::String Certificate::getOrganizationalUnitName(FieldType type) const +std::string Certificate::getOrganizationalUnitName(FieldType type) const { return getField(type, NID_organizationalUnitName); } -DPL::String Certificate::getEmailAddres(FieldType type) const +std::string Certificate::getEmailAddres(FieldType type) const { return getField(type, NID_pkcs9_emailAddress); } -DPL::String Certificate::getOCSPURL() const +std::string Certificate::getOCSPURL() const { // TODO verify this code - DPL::String retValue; + std::string retValue; AUTHORITY_INFO_ACCESS *aia = static_cast<AUTHORITY_INFO_ACCESS*>( X509_get_ext_d2i(m_x509, NID_info_access, @@ -301,10 +287,11 @@ DPL::String Certificate::getOCSPURL() const if (OBJ_obj2nid(ad->method) == NID_ad_OCSP && ad->location->type == GEN_URI) { - void* data = ASN1_STRING_data(ad->location->d.ia5); - retValue = DPL::String(DPL::FromUTF8String( - static_cast<char*>(data))); - + void *data = ASN1_STRING_data(ad->location->d.ia5); + if (!data) + retValue = std::string(); + else + retValue = std::string(static_cast<char *>(data)); break; } } @@ -312,8 +299,6 @@ DPL::String Certificate::getOCSPURL() const return retValue; } - - Certificate::AltNameSet Certificate::getAlternativeNameDNS() const { AltNameSet set; @@ -327,13 +312,16 @@ Certificate::AltNameSet Certificate::getAlternativeNameDNS() const while (sk_GENERAL_NAME_num(san) > 0) { namePart = sk_GENERAL_NAME_pop(san); if (GEN_DNS == namePart->type) { - std::string temp = - reinterpret_cast<char*>(ASN1_STRING_data(namePart->d.dNSName)); - DPL::String altDNSName = DPL::FromASCIIString(temp); - set.insert(altDNSName); - LogDebug("FOUND GEN_DNS: " << temp); + char *temp = reinterpret_cast<char *>(ASN1_STRING_data(namePart->d.dNSName)); + if (!temp) { + set.insert(std::string()); + } + else { + set.insert(std::string(temp)); + WrtLogD("FOUND GEN_DNS: %s", temp); + } } else { - LogDebug("FOUND GEN TYPE ID: " << namePart->type); + WrtLogD("FOUND GEN TYPE ID: %d", namePart->type); } } return set; @@ -342,54 +330,51 @@ Certificate::AltNameSet Certificate::getAlternativeNameDNS() const time_t Certificate::getNotAfter() const { ASN1_TIME *time = X509_get_notAfter(m_x509); - if (!time) { - LogError("Reading Not After error."); - ThrowMsg(Exception::OpensslInternalError, "Reading Not After error."); - } + if (!time) + VcoreThrowMsg(Certificate::Exception::OpensslInternalError, + "Reading Not After error."); + time_t output; - if (asn1TimeToTimeT(time, &output)) { - LogError("Converting ASN1_time to time_t error."); - ThrowMsg(Exception::OpensslInternalError, - "Converting ASN1_time to time_t error."); - } + if (asn1TimeToTimeT(time, &output)) + VcoreThrowMsg(Certificate::Exception::OpensslInternalError, + "Converting ASN1_time to time_t error."); + return output; } time_t Certificate::getNotBefore() const { ASN1_TIME *time = X509_get_notBefore(m_x509); - if (!time) { - LogError("Reading Not Before error."); - ThrowMsg(Exception::OpensslInternalError, "Reading Not Before error."); - } + if (!time) + VcoreThrowMsg(Certificate::Exception::OpensslInternalError, + "Reading Not Before error."); + time_t output; - if (asn1TimeToTimeT(time, &output)) { - LogError("Converting ASN1_time to time_t error."); - ThrowMsg(Exception::OpensslInternalError, - "Converting ASN1_time to time_t error."); - } + if (asn1TimeToTimeT(time, &output)) + VcoreThrowMsg(Certificate::Exception::OpensslInternalError, + "Converting ASN1_time to time_t error."); + return output; } ASN1_TIME* Certificate::getNotAfterTime() const { - ASN1_TIME *timeafter = X509_get_notAfter(m_x509); - if (!timeafter) { - LogError("Reading Not After error."); - ThrowMsg(Exception::OpensslInternalError, "Reading Not After error."); - } + ASN1_TIME *timeafter = X509_get_notAfter(m_x509); + if (!timeafter) + VcoreThrowMsg(Certificate::Exception::OpensslInternalError, + "Reading Not After error."); - return timeafter; + return timeafter; } ASN1_TIME* Certificate::getNotBeforeTime() const { - ASN1_TIME *timebefore = X509_get_notBefore(m_x509); - if (!timebefore) { - LogError("Reading Not Before error."); - ThrowMsg(Exception::OpensslInternalError, "Reading Not Before error."); - } - return timebefore; + ASN1_TIME *timebefore = X509_get_notBefore(m_x509); + if (!timebefore) + VcoreThrowMsg(Certificate::Exception::OpensslInternalError, + "Reading Not Before error."); + + return timebefore; } bool Certificate::isRootCert() @@ -412,7 +397,7 @@ Certificate::getCrlUris() const NULL, NULL)); if (!distPoints) { - LogDebug("No distribution points in certificate."); + WrtLogD("No distribution points in certificate."); return result; } @@ -420,7 +405,7 @@ Certificate::getCrlUris() const for (int i = 0; i < count; ++i) { DIST_POINT* point = sk_DIST_POINT_value(distPoints, i); if (!point) { - LogError("Failed to get distribution point."); + WrtLogE("Failed to get distribution point."); continue; } if (point->distpoint != NULL && @@ -435,7 +420,7 @@ Certificate::getCrlUris() const char *crlUri = reinterpret_cast<char*>(name->d.ia5->data); if (!crlUri) { - LogError("Failed to get URI."); + WrtLogE("Failed to get URI."); continue; } result.push_back(crlUri); @@ -453,14 +438,13 @@ long Certificate::getVersion() const return X509_get_version(m_x509); } -DPL::String Certificate::getSerialNumberString() const +std::string Certificate::getSerialNumberString() const { ASN1_INTEGER *ai = X509_get_serialNumber(m_x509); - if (NULL == ai) { - LogError("Error in X509_get_serialNumber"); - ThrowMsg(Exception::OpensslInternalError, - "Error in X509_get_serialNumber"); - } + if (!ai) + VcoreThrowMsg(Certificate::Exception::OpensslInternalError, + "Error in X509_get_serialNumber"); + std::stringstream stream; stream << std::hex << std::setfill('0'); if (ai->type == V_ASN1_NEG_INTEGER) { @@ -473,10 +457,11 @@ DPL::String Certificate::getSerialNumberString() const if (!data.empty()) { data.erase(--data.end()); } - return DPL::FromUTF8String(data); + + return data; } -DPL::String Certificate::getKeyUsageString() const +std::string Certificate::getKeyUsageString() const { // Extensions were defined in RFC 3280 const char *usage[] = { @@ -505,66 +490,64 @@ DPL::String Certificate::getKeyUsageString() const if (!result.empty()) { result.erase(--result.end()); } - return DPL::FromUTF8String(result); + + return result; } -DPL::String Certificate::getSignatureAlgorithmString() const +std::string Certificate::getSignatureAlgorithmString() const { std::unique_ptr<BIO, std::function<int(BIO*)>> b(BIO_new(BIO_s_mem()),BIO_free); - if (b.get() == NULL) { - LogError("Error in BIO_new"); - ThrowMsg(Exception::OpensslInternalError, - "Error in BIO_new"); - } - if (i2a_ASN1_OBJECT(b.get(), m_x509->cert_info->signature->algorithm) < 0) { - LogError("Error in i2a_ASN1_OBJECT"); - ThrowMsg(Exception::OpensslInternalError, - "Error in i2a_ASN1_OBJECT"); - } + if (!b.get()) + VcoreThrowMsg(Certificate::Exception::OpensslInternalError, + "Error in BIO_new"); + + if (i2a_ASN1_OBJECT(b.get(), m_x509->cert_info->signature->algorithm) < 0) + VcoreThrowMsg(Certificate::Exception::OpensslInternalError, + "Error in i2a_ASN1_OBJECT"); + BUF_MEM *bptr = 0; BIO_get_mem_ptr(b.get(), &bptr); - if (bptr == 0) { - LogError("Error in BIO_get_mem_ptr"); - ThrowMsg(Exception::OpensslInternalError, - "Error in BIO_get_mem_ptr"); - } + if (bptr == 0) + VcoreThrowMsg(Certificate::Exception::OpensslInternalError, + "Error in BIO_get_mem_ptr"); + std::string result(bptr->data, bptr->length); - return DPL::FromUTF8String(result); + + return result; } -DPL::String Certificate::getPublicKeyString() const +std::string Certificate::getPublicKeyString() const { std::unique_ptr<BIO, std::function<int(BIO*)>> b(BIO_new(BIO_s_mem()),BIO_free); - if (b.get() == NULL) { - LogError("Error in BIO_new"); - ThrowMsg(Exception::OpensslInternalError, - "Error in BIO_new"); - } + if (!b.get()) + VcoreThrowMsg(Certificate::Exception::OpensslInternalError, + "Error in BIO_new"); + EVP_PKEY *pkey = X509_get_pubkey(m_x509); - if (pkey == NULL) { - LogError("Error in X509_get_pubkey"); - ThrowMsg(Exception::OpensslInternalError, - "Error in X509_get_pubkey"); - } + if (!pkey) + VcoreThrowMsg(Certificate::Exception::OpensslInternalError, + "Error in X509_get_pubkey"); + EVP_PKEY_print_public(b.get(), pkey, 16, NULL); EVP_PKEY_free(pkey); BUF_MEM *bptr = 0; BIO_get_mem_ptr(b.get(), &bptr); - if (bptr == 0) { - LogError("Error in BIO_get_mem_ptr"); - ThrowMsg(Exception::OpensslInternalError, - "Error in BIO_get_mem_ptr"); - } + if (bptr == 0) + VcoreThrowMsg(Certificate::Exception::OpensslInternalError, + "Error in BIO_get_mem_ptr"); + std::string result(bptr->data, bptr->length); - return DPL::FromUTF8String(result); + + return result; } -int Certificate::isCA() const { +int Certificate::isCA() const +{ return X509_check_ca(m_x509); } diff --git a/vcore/src/vcore/Certificate.h b/vcore/src/vcore/Certificate.h index 2687468..e8d2364 100644 --- a/vcore/src/vcore/Certificate.h +++ b/vcore/src/vcore/Certificate.h @@ -27,14 +27,12 @@ #include <string> #include <vector> #include <ctime> - -#include <dpl/exception.h> -#include <dpl/noncopyable.h> #include <memory> -#include <dpl/string.h> #include <openssl/x509.h> +#include <vcore/exception.h> + #include <cert-service.h> extern "C" { @@ -51,11 +49,18 @@ class Certificate; typedef std::shared_ptr<Certificate> CertificatePtr; typedef std::list<CertificatePtr> CertificateList; -class Certificate : public std::enable_shared_from_this<Certificate> -{ - public: +class Certificate : public std::enable_shared_from_this<Certificate> { +public: + class Exception { + public: + VCORE_DECLARE_EXCEPTION_TYPE(ValidationCore::Exception, Base); + VCORE_DECLARE_EXCEPTION_TYPE(Base, OpensslInternalError); + }; + typedef std::vector<unsigned char> Fingerprint; - typedef DPL::String AltName; + + // ascii string + typedef std::string AltName; typedef std::set<AltName> AltNameSet; enum FingerprintType @@ -75,13 +80,6 @@ class Certificate : public std::enable_shared_from_this<Certificate> FORM_BASE64 }; - class Exception - { - public: - DECLARE_EXCEPTION_TYPE(DPL::Exception, Base) - DECLARE_EXCEPTION_TYPE(Base, OpensslInternalError) - }; - explicit Certificate(X509 *cert); explicit Certificate(cert_svc_mem_buff &buffer); @@ -107,19 +105,16 @@ class Certificate : public std::enable_shared_from_this<Certificate> Fingerprint getFingerprint(FingerprintType type) const; // getName uses deprecated functions. Usage is strongly discouraged. - DPL::String getOneLine(FieldType type = FIELD_SUBJECT) const; - - DPL::String getCommonName(FieldType type = FIELD_SUBJECT) const; - DPL::String getCountryName(FieldType type = FIELD_SUBJECT) const; - DPL::String getStateOrProvinceName( - FieldType type = FIELD_SUBJECT) const; - DPL::String getLocalityName(FieldType type = FIELD_SUBJECT) const; - DPL::String getOrganizationName( - FieldType type = FIELD_SUBJECT) const; - DPL::String getOrganizationalUnitName( - FieldType type = FIELD_SUBJECT) const; - DPL::String getEmailAddres(FieldType type = FIELD_SUBJECT) const; - DPL::String getOCSPURL() const; + // utf8 string + std::string getOneLine(FieldType type = FIELD_SUBJECT) const; + std::string getCommonName(FieldType type = FIELD_SUBJECT) const; + std::string getCountryName(FieldType type = FIELD_SUBJECT) const; + std::string getStateOrProvinceName(FieldType type = FIELD_SUBJECT) const; + std::string getLocalityName(FieldType type = FIELD_SUBJECT) const; + std::string getOrganizationName(FieldType type = FIELD_SUBJECT) const; + std::string getOrganizationalUnitName(FieldType type = FIELD_SUBJECT) const; + std::string getEmailAddres(FieldType type = FIELD_SUBJECT) const; + std::string getOCSPURL() const; // Openssl supports 9 types of alternative name filed. @@ -150,13 +145,11 @@ class Certificate : public std::enable_shared_from_this<Certificate> long getVersion() const; - DPL::String getSerialNumberString() const; - - DPL::String getKeyUsageString() const; - - DPL::String getSignatureAlgorithmString() const; - - DPL::String getPublicKeyString() const; + // utf8 string + std::string getSerialNumberString() const; + std::string getKeyUsageString() const; + std::string getSignatureAlgorithmString() const; + std::string getPublicKeyString() const; /* * 0 - not CA @@ -171,11 +164,11 @@ class Certificate : public std::enable_shared_from_this<Certificate> static std::string FingerprintToColonHex( const Fingerprint &fingerprint); - protected: +protected: X509_NAME *getX509Name(FieldType type) const; - DPL::String getField(FieldType type, - int fieldNid) const; + // utf8 string + std::string getField(FieldType type, int fieldNid) const; X509 *m_x509; }; diff --git a/vcore/src/vcore/CertificateCacheDAO.cpp b/vcore/src/vcore/CertificateCacheDAO.cpp index 483702c..c01fa7a 100644 --- a/vcore/src/vcore/CertificateCacheDAO.cpp +++ b/vcore/src/vcore/CertificateCacheDAO.cpp @@ -26,13 +26,13 @@ #include <vcore/VCorePrivate.h> #include <dpl/foreach.h> -#include <dpl/log/log.h> +#include <dpl/log/wrt_log.h> #include <dpl/db/orm.h> #include <orm_generator_vcore.h> #include <vcore/Database.h> -using namespace DPL::DB::ORM; -using namespace DPL::DB::ORM::vcore; +using namespace VcoreDPL::DB::ORM; +using namespace VcoreDPL::DB::ORM::vcore; namespace ValidationCore { @@ -49,7 +49,7 @@ void CertificateCacheDAO::setOCSPStatus(const std::string& cert_chain, if (getOCSPStatus(&status)) { // only need to update data in DB Equals<OCSPResponseStorage::cert_chain> e1( - DPL::FromUTF8String(cert_chain)); + VcoreDPL::FromUTF8String(cert_chain)); Equals<OCSPResponseStorage::end_entity_check> e2( end_entity_check ? 1 : 0); @@ -66,7 +66,7 @@ void CertificateCacheDAO::setOCSPStatus(const std::string& cert_chain, // need to insert data OCSPResponseStorage::Row row; - row.Set_cert_chain(DPL::FromUTF8String(cert_chain)); + row.Set_cert_chain(VcoreDPL::FromUTF8String(cert_chain)); row.Set_ocsp_status(ocsp_status); row.Set_next_update_time(next_update_time); row.Set_end_entity_check(end_entity_check ? 1 : 0); @@ -76,7 +76,7 @@ void CertificateCacheDAO::setOCSPStatus(const std::string& cert_chain, insert->Execute(); } transaction.Commit(); - } Catch(DPL::DB::SqlConnection::Exception::Base) { + } Catch(VcoreDPL::DB::SqlConnection::Exception::Base) { ReThrowMsg(Exception::DatabaseError, "Failed to setOCSPStatus"); } } @@ -84,12 +84,12 @@ void CertificateCacheDAO::setOCSPStatus(const std::string& cert_chain, bool CertificateCacheDAO::getOCSPStatus(OCSPCachedStatus* cached_status) { if (NULL == cached_status) { - LogError("NULL pointer"); + WrtLogE("NULL pointer"); return false; } Try { Equals<OCSPResponseStorage::cert_chain> e1( - DPL::FromUTF8String(cached_status->cert_chain)); + VcoreDPL::FromUTF8String(cached_status->cert_chain)); Equals<OCSPResponseStorage::end_entity_check> e2( cached_status->end_entity_check ? 1 : 0); @@ -105,10 +105,10 @@ bool CertificateCacheDAO::getOCSPStatus(OCSPCachedStatus* cached_status) return true; } - LogDebug("Cached OCSP status not found"); + WrtLogD("Cached OCSP status not found"); return false; } - Catch(DPL::DB::SqlConnection::Exception::Base) { + Catch(VcoreDPL::DB::SqlConnection::Exception::Base) { ReThrowMsg(Exception::DatabaseError, "Failed to getOCSPStatus"); } } @@ -117,7 +117,7 @@ void CertificateCacheDAO::getOCSPStatusList( OCSPCachedStatusList* cached_status_list) { if (NULL == cached_status_list) { - LogError("NULL pointer"); + WrtLogE("NULL pointer"); return; } Try { @@ -127,7 +127,7 @@ void CertificateCacheDAO::getOCSPStatusList( FOREACH(i, list) { OCSPCachedStatus status; - status.cert_chain = DPL::ToUTF8String(i->Get_cert_chain()); + status.cert_chain = VcoreDPL::ToUTF8String(i->Get_cert_chain()); status.ocsp_status = intToVerificationStatus( *(i->Get_ocsp_status())); status.end_entity_check = @@ -137,7 +137,7 @@ void CertificateCacheDAO::getOCSPStatusList( } } - Catch(DPL::DB::SqlConnection::Exception::Base) { + Catch(VcoreDPL::DB::SqlConnection::Exception::Base) { ReThrowMsg(Exception::DatabaseError, "Failed to getOCSPStatusList"); } } @@ -155,11 +155,11 @@ void CertificateCacheDAO::setCRLResponse(const std::string& distribution_point, // only need to update data in DB VCORE_DB_UPDATE(update, CRLResponseStorage, &ThreadInterface()) Equals<CRLResponseStorage::distribution_point> e1( - DPL::FromUTF8String(distribution_point)); + VcoreDPL::FromUTF8String(distribution_point)); CRLResponseStorage::Row row; update->Where(e1); - row.Set_crl_body(DPL::FromUTF8String(crl_body)); + row.Set_crl_body(VcoreDPL::FromUTF8String(crl_body)); row.Set_next_update_time(next_update_time); update->Values(row); update->Execute(); @@ -168,14 +168,14 @@ void CertificateCacheDAO::setCRLResponse(const std::string& distribution_point, VCORE_DB_INSERT(insert, CRLResponseStorage, &ThreadInterface()) CRLResponseStorage::Row row; - row.Set_distribution_point(DPL::FromUTF8String(distribution_point)); - row.Set_crl_body(DPL::FromUTF8String(crl_body)); + row.Set_distribution_point(VcoreDPL::FromUTF8String(distribution_point)); + row.Set_crl_body(VcoreDPL::FromUTF8String(crl_body)); row.Set_next_update_time(next_update_time); insert->Values(row); insert->Execute(); } transaction.Commit(); - } Catch(DPL::DB::SqlConnection::Exception::Base) { + } Catch(VcoreDPL::DB::SqlConnection::Exception::Base) { ReThrowMsg(Exception::DatabaseError, "Failed to setOCSPStatus"); } } @@ -183,27 +183,27 @@ void CertificateCacheDAO::setCRLResponse(const std::string& distribution_point, bool CertificateCacheDAO::getCRLResponse(CRLCachedData* cached_data) { if (NULL == cached_data) { - LogError("NULL pointer"); + WrtLogE("NULL pointer"); return false; } Try { VCORE_DB_SELECT(select, CRLResponseStorage, &ThreadInterface()) Equals<CRLResponseStorage::distribution_point> e1( - DPL::FromUTF8String(cached_data->distribution_point)); + VcoreDPL::FromUTF8String(cached_data->distribution_point)); select->Where(e1); std::list<CRLResponseStorage::Row> rows = select->GetRowList(); if (1 == rows.size()) { CRLResponseStorage::Row row = rows.front(); - cached_data->crl_body = DPL::ToUTF8String(row.Get_crl_body()); + cached_data->crl_body = VcoreDPL::ToUTF8String(row.Get_crl_body()); cached_data->next_update_time = *(row.Get_next_update_time()); return true; } - LogDebug("Cached CRL not found"); + WrtLogD("Cached CRL not found"); return false; } - Catch(DPL::DB::SqlConnection::Exception::Base) { + Catch(VcoreDPL::DB::SqlConnection::Exception::Base) { ReThrowMsg(Exception::DatabaseError, "Failed to getCRLResponse"); } } @@ -212,7 +212,7 @@ void CertificateCacheDAO::getCRLResponseList( CRLCachedDataList* cached_data_list) { if (NULL == cached_data_list) { - LogError("NULL pointer"); + WrtLogE("NULL pointer"); return; } Try { @@ -222,15 +222,15 @@ void CertificateCacheDAO::getCRLResponseList( FOREACH(i, list) { CRLCachedData response; - response.distribution_point = DPL::ToUTF8String( + response.distribution_point = VcoreDPL::ToUTF8String( i->Get_distribution_point()); - response.crl_body = DPL::ToUTF8String(i->Get_crl_body()); + response.crl_body = VcoreDPL::ToUTF8String(i->Get_crl_body()); response.next_update_time = *(i->Get_next_update_time()); cached_data_list->push_back(response); } } - Catch(DPL::DB::SqlConnection::Exception::Base) { + Catch(VcoreDPL::DB::SqlConnection::Exception::Base) { ReThrowMsg(Exception::DatabaseError, "Failed to getCRLResponses"); } } @@ -245,7 +245,7 @@ void CertificateCacheDAO::clearCertificateCache() del2->Execute(); transaction.Commit(); } - Catch(DPL::DB::SqlConnection::Exception::Base) { + Catch(VcoreDPL::DB::SqlConnection::Exception::Base) { ReThrowMsg(Exception::DatabaseError, "Failed to clearUserSettings"); } } diff --git a/vcore/src/vcore/CertificateCacheDAO.h b/vcore/src/vcore/CertificateCacheDAO.h index 59102da..f10ec07 100644 --- a/vcore/src/vcore/CertificateCacheDAO.h +++ b/vcore/src/vcore/CertificateCacheDAO.h @@ -52,7 +52,7 @@ class CertificateCacheDAO { class Exception { public: - DECLARE_EXCEPTION_TYPE(DPL::Exception, Base) + DECLARE_EXCEPTION_TYPE(VcoreDPL::Exception, Base) DECLARE_EXCEPTION_TYPE(Base, DatabaseError) }; diff --git a/vcore/src/vcore/CertificateCollection.cpp b/vcore/src/vcore/CertificateCollection.cpp index 90d1d4e..2f20146 100644 --- a/vcore/src/vcore/CertificateCollection.cpp +++ b/vcore/src/vcore/CertificateCollection.cpp @@ -21,13 +21,12 @@ */ #include <vcore/CertificateCollection.h> -#include <algorithm> - +#include <vcore/Base64.h> #include <dpl/binary_queue.h> #include <dpl/foreach.h> -#include <dpl/log/log.h> +#include <dpl/log/wrt_log.h> -#include <vcore/Base64.h> +#include <algorithm> namespace { @@ -68,18 +67,19 @@ bool CertificateCollection::load(const std::string &buffer) base64.reset(); base64.append(buffer); if (!base64.finalize()) { - LogWarning("Error during chain decoding"); + WrtLogW("Error during chain decoding"); return false; } std::string binaryData = base64.get(); - DPL::BinaryQueue queue; + VcoreDPL::BinaryQueue queue; queue.AppendCopy(binaryData.c_str(), binaryData.size()); int certNum; queue.FlattenConsume(&certNum, sizeof(int)); CertificateList list; + CertificatePtr certPtr; for (int i = 0; i < certNum; ++i) { int certSize; @@ -87,16 +87,16 @@ bool CertificateCollection::load(const std::string &buffer) std::vector<char> rawDERCert; rawDERCert.resize(certSize); queue.FlattenConsume(&rawDERCert[0], certSize); - Try { - list.push_back(CertificatePtr( - new Certificate(std::string(rawDERCert.begin(), - rawDERCert.end())))); - } Catch(Certificate::Exception::Base) { - LogWarning("Error during certificate creation."); + VcoreTry { + list.push_back(CertificatePtr(new Certificate(std::string( + rawDERCert.begin(), + rawDERCert.end())))); + } VcoreCatch (Certificate::Exception::Base) { + WrtLogW("Error during certificate creation."); return false; } - LogDebug("Loading certificate. Certificate common name: " << - list.back()->getCommonName()); + + WrtLogD("Loading certificate. Certificate common name: %s", list.back()->getCommonName().c_str()); } load(list); return true; @@ -126,11 +126,10 @@ CertificateList CertificateCollection::getCertificateList() const bool CertificateCollection::isChain() const { - if (COLLECTION_SORTED != m_collectionStatus) { - LogError("You must sort certificates first"); - ThrowMsg(Exception::WrongUsage, - "You must sort certificates first"); - } + if (COLLECTION_SORTED != m_collectionStatus) + VcoreThrowMsg(CertificateCollection::Exception::WrongUsage, + "You must sort certificate first"); + return (COLLECTION_SORTED == m_collectionStatus) ? true : false; } @@ -144,11 +143,9 @@ bool CertificateCollection::sort() CertificateList CertificateCollection::getChain() const { - if (COLLECTION_SORTED != m_collectionStatus) { - LogError("You must sort certificates first"); - ThrowMsg(Exception::WrongUsage, - "You must sort certificates first"); - } + if (COLLECTION_SORTED != m_collectionStatus) + VcoreThrowMsg(CertificateCollection::Exception::WrongUsage, + "You must sort certificates first"); return m_certList; } @@ -166,7 +163,7 @@ void CertificateCollection::sortCollection() // Sort all certificate by subject for (auto it = m_certList.begin(); it != m_certList.end(); ++it) { - subTransl.insert(std::make_pair(DPL::ToUTF8String((*it)->getOneLine()),(*it))); + subTransl.insert(std::make_pair((*it)->getOneLine(), (*it))); } // We need one start certificate sorted.push_back(subTransl.begin()->second); @@ -175,7 +172,7 @@ void CertificateCollection::sortCollection() // Get the issuer from front certificate and find certificate with this subject in subTransl. // Add this certificate to the front. while (!subTransl.empty()) { - std::string issuer = DPL::ToUTF8String(sorted.back()->getOneLine(Certificate::FIELD_ISSUER)); + std::string issuer = sorted.back()->getOneLine(Certificate::FIELD_ISSUER); auto it = subTransl.find(issuer); if (it == subTransl.end()) { break; @@ -186,13 +183,13 @@ void CertificateCollection::sortCollection() // Sort all certificates by issuer for (auto it = subTransl.begin(); it != subTransl.end(); ++it) { - issTransl.insert(std::make_pair(DPL::ToUTF8String((it->second->getOneLine(Certificate::FIELD_ISSUER))),it->second)); + issTransl.insert(std::make_pair(it->second->getOneLine(Certificate::FIELD_ISSUER), it->second)); } // Get the subject from last certificate and find certificate with such issuer in issTransl. // Add this certificate at end. while (!issTransl.empty()) { - std::string sub = DPL::ToUTF8String(sorted.front()->getOneLine()); + std::string sub = sorted.front()->getOneLine(); auto it = issTransl.find(sub); if (it == issTransl.end()) { break; @@ -202,7 +199,7 @@ void CertificateCollection::sortCollection() } if (!issTransl.empty()) { - LogWarning("Certificates don't form a valid chain."); + WrtLogW("Certificates don't form a valid chain."); m_collectionStatus = COLLECTION_CHAIN_BROKEN; return; } diff --git a/vcore/src/vcore/CertificateCollection.h b/vcore/src/vcore/CertificateCollection.h index 953bbfb..9b9a6c4 100644 --- a/vcore/src/vcore/CertificateCollection.h +++ b/vcore/src/vcore/CertificateCollection.h @@ -24,8 +24,9 @@ #include <list> #include <string> +#include <map> -#include <dpl/exception.h> +#include <vcore/exception.h> #include <vcore/Certificate.h> @@ -37,14 +38,12 @@ namespace ValidationCore { * It could check if collection creates certificate chain. */ -class CertificateCollection -{ - public: - class Exception - { - public: - DECLARE_EXCEPTION_TYPE(DPL::Exception, Base) - DECLARE_EXCEPTION_TYPE(Base, WrongUsage) +class CertificateCollection { +public: + class Exception { + public: + VCORE_DECLARE_EXCEPTION_TYPE(ValidationCore::Exception, Base); + VCORE_DECLARE_EXCEPTION_TYPE(Base, WrongUsage); }; CertificateCollection(); @@ -152,7 +151,7 @@ class CertificateCollection */ CertificatePtr back() const; - protected: +protected: void sortCollection(void); enum CollectionStatus diff --git a/vcore/src/vcore/CertificateConfigReader.cpp b/vcore/src/vcore/CertificateConfigReader.cpp index e98e747..3d67e35 100644 --- a/vcore/src/vcore/CertificateConfigReader.cpp +++ b/vcore/src/vcore/CertificateConfigReader.cpp @@ -19,12 +19,13 @@ * @version 1.0 * @brief */ -#include "CertificateConfigReader.h" -#include <cstdlib> +#include <vcore/CertificateConfigReader.h> #include <dpl/assert.h> +#include <cstdlib> + namespace { const std::string XML_EMPTY_NAMESPACE = ""; @@ -39,6 +40,7 @@ const std::string TOKEN_ATTR_URL_NAME = "ocspUrl"; const std::string TOKEN_VALUE_TIZEN_DEVELOPER = "tizen-developer"; const std::string TOKEN_VALUE_TIZEN_TEST = "tizen-test"; const std::string TOKEN_VALUE_TIZEN_VERIFY = "tizen-verify"; +const std::string TOKEN_VALUE_TIZEN_STORE = "tizen-store"; const std::string TOKEN_VALUE_VISIBILITY_PUBLIC = "tizen-public"; const std::string TOKEN_VALUE_VISIBILITY_PARTNER = "tizen-partner"; const std::string TOKEN_VALUE_VISIBILITY_PARTNER_OPERATOR = "tizen-partner-operator"; @@ -61,9 +63,9 @@ int hexCharToInt(char c) } // anonymous namespace namespace ValidationCore { -CertificateConfigReader::CertificateConfigReader() : - m_certificateDomain(0), - m_parserSchema(this) +CertificateConfigReader::CertificateConfigReader() + : m_certificateDomain(0) + , m_parserSchema(this) { m_parserSchema.addBeginTagCallback( TOKEN_CERTIFICATE_SET, @@ -96,21 +98,37 @@ CertificateConfigReader::CertificateConfigReader() : &CertificateConfigReader::tokenEndFingerprintSHA1); } +void CertificateConfigReader::initialize( + const std::string &file, + const std::string &scheme) +{ + m_parserSchema.initialize(file, true, SaxReader::VALIDATION_XMLSCHEME, scheme); +} + +void CertificateConfigReader::read(CertificateIdentifier &identificator) +{ + m_parserSchema.read(identificator); +} + +void CertificateConfigReader::blankFunction(CertificateIdentifier &) +{ +} + void CertificateConfigReader::tokenCertificateDomain(CertificateIdentifier &) { - std::string name = m_parserSchema.getReader(). - attribute(TOKEN_ATTR_NAME, SaxReader::THROW_DISABLE); + std::string name = m_parserSchema.getReader().attribute(TOKEN_ATTR_NAME); if (name.empty()) { - LogWarning("Invalid fingerprint file. Domain name is mandatory"); - ThrowMsg(Exception::InvalidFile, - "Invalid fingerprint file. Domain name is mandatory"); + VcoreThrowMsg(CertificateConfigReader::Exception::InvalidFile, + "Invalid fingerprint file. Domain name is mandatory"); } else if (name == TOKEN_VALUE_TIZEN_DEVELOPER) { m_certificateDomain = CertStoreId::TIZEN_DEVELOPER; } else if (name == TOKEN_VALUE_TIZEN_TEST) { m_certificateDomain = CertStoreId::TIZEN_TEST; } else if (name == TOKEN_VALUE_TIZEN_VERIFY) { m_certificateDomain = CertStoreId::TIZEN_VERIFY; + } else if (name == TOKEN_VALUE_TIZEN_STORE) { + m_certificateDomain = CertStoreId::TIZEN_STORE; } else if (name == TOKEN_VALUE_VISIBILITY_PUBLIC) { m_certificateDomain = CertStoreId::VIS_PUBLIC; } else if (name == TOKEN_VALUE_VISIBILITY_PARTNER) { @@ -121,8 +139,7 @@ void CertificateConfigReader::tokenCertificateDomain(CertificateIdentifier &) m_certificateDomain = CertStoreId::VIS_PARTNER_MANUFACTURER; } else if (name == TOKEN_VALUE_VISIBILITY_PLATFORM) { m_certificateDomain = CertStoreId::VIS_PLATFORM; - } else { - LogWarning("This domain will be ignored : " << name); + } else { m_certificateDomain = 0; } } @@ -130,9 +147,9 @@ void CertificateConfigReader::tokenCertificateDomain(CertificateIdentifier &) void CertificateConfigReader::tokenEndFingerprintSHA1( CertificateIdentifier &identificator) { - #ifdef TIZEN_FEATURE_CERT_SVC_OCSP_CRL - std::string url = m_parserSchema.getReader().attribute(TOKEN_ATTR_URL_NAME, SaxReader::THROW_DISABLE); - #endif +#ifdef TIZEN_FEATURE_CERT_SVC_OCSP_CRL + std::string url = m_parserSchema.getReader().attribute(TOKEN_ATTR_URL_NAME); +#endif std::string text = m_parserSchema.getText(); text += ":"; // add guard at the end of fingerprint @@ -157,8 +174,8 @@ void CertificateConfigReader::tokenEndFingerprintSHA1( } identificator.add(fingerprint, m_certificateDomain); - #ifdef TIZEN_FEATURE_CERT_SVC_OCSP_CRL +#ifdef TIZEN_FEATURE_CERT_SVC_OCSP_CRL identificator.add(fingerprint, url); - #endif +#endif } } // namespace ValidationCore diff --git a/vcore/src/vcore/CertificateConfigReader.h b/vcore/src/vcore/CertificateConfigReader.h index 4ca7d8e..d61cc86 100644 --- a/vcore/src/vcore/CertificateConfigReader.h +++ b/vcore/src/vcore/CertificateConfigReader.h @@ -23,46 +23,33 @@ #define _VALIDATION_CORE_CERTIFICATE_CONFIG_READER_H_ #include <string> -#include <dpl/exception.h> #include <vcore/CertificateIdentifier.h> #include <vcore/CertStoreType.h> #include <vcore/ParserSchema.h> +#include <vcore/exception.h> namespace ValidationCore { -class CertificateConfigReader -{ - public: - class Exception - { - public: - DECLARE_EXCEPTION_TYPE(DPL::Exception, Base) - DECLARE_EXCEPTION_TYPE(Base, InvalidFile) +class CertificateConfigReader { +public: + class Exception { + public: + VCORE_DECLARE_EXCEPTION_TYPE(ValidationCore::Exception, Base); + VCORE_DECLARE_EXCEPTION_TYPE(Base, InvalidFile); }; - CertificateConfigReader(); - void initialize(const std::string &file, - const std::string &scheme) - { - m_parserSchema.initialize(file, true, SaxReader::VALIDATION_XMLSCHEME, - scheme); - } + CertificateConfigReader(); - void read(CertificateIdentifier &identificator) - { - m_parserSchema.read(identificator); - } + void initialize(const std::string &file, const std::string &scheme); + void read(CertificateIdentifier &identificator); - private: - void blankFunction(CertificateIdentifier &) - { - } +private: + void blankFunction(CertificateIdentifier &); void tokenCertificateDomain(CertificateIdentifier &identificator); void tokenEndFingerprintSHA1(CertificateIdentifier &identificator); CertStoreId::Type m_certificateDomain; - ParserSchema<CertificateConfigReader, CertificateIdentifier> - m_parserSchema; + ParserSchema<CertificateConfigReader, CertificateIdentifier> m_parserSchema; }; } // namespace ValidationCore diff --git a/vcore/src/vcore/CertificateIdentifier.h b/vcore/src/vcore/CertificateIdentifier.h index 0090d2c..bbdab2d 100644 --- a/vcore/src/vcore/CertificateIdentifier.h +++ b/vcore/src/vcore/CertificateIdentifier.h @@ -27,14 +27,13 @@ #include <map> #include <dpl/noncopyable.h> -#include "Certificate.h" -#include "CertStoreType.h" +#include <vcore/Certificate.h> +#include <vcore/CertStoreType.h> namespace ValidationCore { -class CertificateIdentifier : public DPL::Noncopyable -{ +class CertificateIdentifier : public VcoreDPL::Noncopyable { public: - typedef std::map<Certificate::Fingerprint, CertStoreId::Set> FingerPrintMap; + typedef std::map<Certificate::Fingerprint, CertStoreId::Set> FingerPrintMap; CertificateIdentifier() { @@ -49,13 +48,13 @@ public: fingerPrintMap[fingerprint].add(domain); } - #ifdef TIZEN_FEATURE_CERT_SVC_OCSP_CRL + #ifdef TIZEN_FEATURE_CERT_SVC_OCSP_CRL void add(const Certificate::Fingerprint &fingerprint, - std::string ocspUrl) + std::string ocspUrl) { - fingerPrintMap[fingerprint].add(ocspUrl); + fingerPrintMap[fingerprint].add(ocspUrl); } - #endif + #endif CertStoreId::Set find(const Certificate::Fingerprint &fingerprint) const { @@ -72,7 +71,7 @@ public: find(certificate->getFingerprint(Certificate::FINGERPRINT_SHA1)); } - private: +private: FingerPrintMap fingerPrintMap; }; } // namespace ValidationCore diff --git a/vcore/src/vcore/CertificateLoader.cpp b/vcore/src/vcore/CertificateLoader.cpp index 038e0fc..a934f67 100644 --- a/vcore/src/vcore/CertificateLoader.cpp +++ b/vcore/src/vcore/CertificateLoader.cpp @@ -15,7 +15,7 @@ */ #include <dpl/assert.h> #include <openssl/x509v3.h> -#include <dpl/log/log.h> +#include <dpl/log/wrt_log.h> #include <dpl/noncopyable.h> #include <openssl/ecdsa.h> #include <openssl/evp.h> @@ -34,7 +34,7 @@ const int MIN_RSA_KEY_LENGTH = 1024; namespace ValidationCore { //// COMPARATOR CLASS START //// -//class CertificateLoaderECDSA : public CertificateLoader::CertificateLoaderComparator, DPL::Noncopyable { +//class CertificateLoaderECDSA : public CertificateLoader::CertificateLoaderComparator, VcoreDPL::Noncopyable { //public: // CertificateLoaderECDSA(const std::string &publicKey) // : m_ecPublicKey(NULL) @@ -45,7 +45,7 @@ namespace ValidationCore { // m_initialized = CertificateLoader::convertBase64NodeToBigNum(publicKey, &m_searchKey); // // if(!m_initialized) -// LogError("Init failed!"); +// WrtLogE("Init failed!"); // } // // virtual bool compare(X509 *x509cert){ @@ -60,7 +60,7 @@ namespace ValidationCore { // return false; // // if(m_ecPublicKey->type != EVP_PKEY_EC){ -// LogError("ecPublicKey has wrong type!"); +// WrtLogE("ecPublicKey has wrong type!"); // return false; // } // @@ -97,7 +97,7 @@ namespace ValidationCore { //// COMPARATOR RSA CLASS START //// -//class CertificateLoaderRSA : public CertificateLoader::CertificateLoaderComparator, DPL::Noncopyable { +//class CertificateLoaderRSA : public CertificateLoader::CertificateLoaderComparator, VcoreDPL::Noncopyable { //public: // CertificateLoaderRSA(const std::string &m_modulus,const std::string &m_exponent ) // : m_rsaPublicKey(NULL) @@ -109,7 +109,7 @@ namespace ValidationCore { // m_initialized_exponent = CertificateLoader::convertBase64NodeToBigNum(m_exponent, &m_exponent_bn); // // if(!m_initialized_modulus || !m_initialized_exponent) -// LogError("Init failed!"); +// WrtLogE("Init failed!"); // } // // virtual bool compare(X509 *x509cert){ @@ -124,7 +124,7 @@ namespace ValidationCore { // return false; // // if(m_rsaPublicKey->type != EVP_PKEY_RSA){ -// LogInfo("rsaPublicKey has wrong type!"); +// WrtLogI("rsaPublicKey has wrong type!"); // return false; // } // @@ -133,7 +133,7 @@ namespace ValidationCore { // // if (BN_cmp(m_modulus_bn, rsa->n) == 0 && // BN_cmp(m_exponent_bn, rsa->e) == 0 ){ -// LogError ("Compare TRUE"); +// WrtLogE ("Compare TRUE"); // return true; // } // return false; @@ -162,7 +162,7 @@ CertificateLoader::CertificateLoaderResult CertificateLoader:: { (void) m_modulus; (void) m_exponent; - LogError("Not implemented."); + WrtLogE("Not implemented."); return UNKNOWN_ERROR; // if (m_exponent.empty() || m_modulus.empty()) // return WRONG_ARGUMENTS; @@ -188,7 +188,7 @@ CertificateLoader::CertificateLoaderResult CertificateLoader::loadCertificate( { (void) storageName; (void) cmp; - LogError("Not Implemented"); + WrtLogE("Not Implemented"); return UNKNOWN_ERROR; // long int result = OPERATION_SUCCESS; // @@ -217,7 +217,7 @@ CertificateLoader::CertificateLoaderResult CertificateLoader::loadCertificate( // { // // if(OPERATION_SUCCESS!=certmgr_extract_certificate_data(&certRetrieved, &descriptor)){ - // LogError("Extracting Certificate Data failed \n"); + // WrtLogE("Extracting Certificate Data failed "); // continue; // } // @@ -226,35 +226,35 @@ CertificateLoader::CertificateLoaderResult CertificateLoader::loadCertificate( // X509 *x509cert = d2i_X509(NULL, &ptr, certRetrieved.size); // if(x509cert == NULL){ // certmgr_release_certificate_data(&descriptor); - // LogError("Error extracting certificate (d2i_X509)."); + // WrtLogE("Error extracting certificate (d2i_X509)."); // return UNKNOWN_ERROR; // } // - // LogDebug("The subject of this certificate is " << descriptor.mandatory.subject); + // WrtLogD("The subject of this certificate is %s", (descriptor.mandatory.subject)); // if(cmp->compare(x509cert)){ - // LogDebug("Found match. Coping bytes: " << certRetrieved.size); + // WrtLogD("Found match. Coping bytes: %d", certRetrieved.size); // m_certificatePtr = CertificatePtr(new Certificate(certRetrieved)); // certmgr_release_certificate_data(&descriptor); // X509_free(x509cert); // break; // } // - // LogDebug("Release"); + // WrtLogD("Release"); // X509_free(x509cert); // certmgr_release_certificate_data(&descriptor); // } // // if(ERR_NO_MORE_CERTIFICATES == result){ - // LogError("Certificates for given DN not found\n"); + // WrtLogE("Certificates for given DN not found"); // return CERTIFICATE_NOT_FOUND; // } // // if(result!= OPERATION_SUCCESS){ - // LogError("Certificate Manager Error\n"); + // WrtLogE("Certificate Manager Error"); // return UNKNOWN_ERROR; // } // - // LogDebug("Exit"); + // WrtLogD("Exit"); // return NO_ERROR; } @@ -263,7 +263,7 @@ CertificateLoader::CertificateLoaderResult CertificateLoader:: loadCertificateBasedOnSubjectName(const std::string &subjectName) { (void) subjectName; - LogError("Not implemented."); + WrtLogE("Not implemented."); return UNKNOWN_ERROR; // if(subjectName.empty()) // { @@ -295,29 +295,29 @@ CertificateLoader::CertificateLoaderResult CertificateLoader:: // { // // if(OPERATION_SUCCESS!=certmgr_extract_certificate_data(&certRetrieved, &descriptor)){ - // LogError("Extracting Certificate Data failed \n"); + // WrtLogE("Extracting Certificate Data failed "); // continue; // } // // if(!strcmp(subjectName.c_str(), descriptor.mandatory.subject)){ - // LogDebug("The subject of this certificate is " << descriptor.mandatory.subject); + // WrtLogD("The subject of this certificate is %s", descriptor.mandatory.subject); // m_certificatePtr = CertificatePtr(new Certificate(certRetrieved)); // certmgr_release_certificate_data(&descriptor); // break; // } - // LogDebug("Release"); + // WrtLogD("Release"); // certmgr_release_certificate_data(&descriptor); // } // // if(ERR_NO_MORE_CERTIFICATES == result) { - // LogError("Certificates for given DN not found\n"); + // WrtLogE("Certificates for given DN not found"); // return CERTIFICATE_NOT_FOUND; // } // if(result!= OPERATION_SUCCESS){ - // LogError("Certificate Manager Error\n"); + // WrtLogE("Certificate Manager Error"); // return UNKNOWN_ERROR; // } - // LogDebug("Exit"); + // WrtLogD("Exit"); // return NO_ERROR; } @@ -333,7 +333,7 @@ CertificateLoader::CertificateLoaderResult CertificateLoader:: // KW memset(&m_cmBuff, 0, sizeof(certmgr_mem_buff)); // KW } // KW -// KW LogDebug("IssuerName: " << issuerName << " serialNumber: " << serialNumber); +// KW WrtLogD("IssuerName: %s , serialNumber: %s", issuerName.c_str(), serialNumber.c_str()); // KW // KW //used to check status of retrieved certificate // KW long int result = OPERATION_SUCCESS; @@ -359,14 +359,14 @@ CertificateLoader::CertificateLoaderResult CertificateLoader:: // KW certRetrieved.firstFree = 0) // KW { // KW -// KW LogDebug("Extracting certificate from CertMgr"); +// KW WrtLogD("Extracting certificate from CertMgr"); // KW // KW if( OPERATION_SUCCESS != certmgr_extract_certificate_data(&certRetrieved, &descriptor) ){ -// KW LogError("Extracting Certificate Data failed \n"); +// KW WrtLogE("Extracting Certificate Data failed "); // KW continue; // KW } // KW -// KW LogDebug("Issuer: " << descriptor.mandatory.issuer); +// KW WrtLogD("Issuer: %s", (descriptor.mandatory.issuer).c_str()); // KW // KW const unsigned char *ptr = certRetrieved.data; // KW char *tmp; @@ -376,13 +376,13 @@ CertificateLoader::CertificateLoaderResult CertificateLoader:: // KW OPENSSL_free(tmp); // KW X509_free(x509cert); // KW -// KW LogInfo("Certificate number found: " << serialNO); -// KW LogInfo("Certificate number looking for: " << serialNumber); +// KW WrtLogI("Certificate number found: %d", serialNO); +// KW WrtLogI("Certificate number looking for: %d", serialNumber); // KW // KW if(!strcmp(issuerName.c_str(), descriptor.mandatory.issuer) // KW && serialNumber == serialNO) // KW { -// KW LogError("The issuer of this certificate is " << descriptor.mandatory.issuer); +// KW WrtLogE("The issuer of this certificate is %s", (descriptor.mandatory.issuer).c_str()); // KW // KW m_cmBuff.data = new unsigned char[certRetrieved.size]; // KW m_cmBuff.firstFree = m_cmBuff.size = certRetrieved.size; @@ -394,11 +394,11 @@ CertificateLoader::CertificateLoaderResult CertificateLoader:: // KW } // KW // KW if(ERR_NO_MORE_CERTIFICATES == result) { -// KW LogError("Certificates not found"); +// KW WrtLogE("Certificates not found"); // KW return CERTIFICATE_NOT_FOUND; // KW } // KW if(result != OPERATION_SUCCESS){ -// KW LogError("Certificate Manager Error"); +// KW WrtLogE("Certificate Manager Error"); // KW return UNKNOWN_ERROR; // KW } // KW return NO_ERROR; @@ -410,10 +410,10 @@ CertificateLoader::CertificateLoaderResult CertificateLoader:: { (void) curveName; (void) publicKey; - LogError("Not implemented."); + WrtLogE("Not implemented."); return UNKNOWN_ERROR; // if(curveName != OID_CURVE_SECP256R1){ - // LogError("Found field id: " << curveName << " Expected: " << OID_CURVE_SECP256R1); + // WrtLogE("Found field id: %s Expected:", curveName.c_str(), OID_CURVE_SECP256R1.c_str()); // return UNSUPPORTED_CERTIFICATE_FIELD; // } // @@ -432,34 +432,34 @@ CertificateLoader::CertificateLoaderResult CertificateLoader:: // return result; } -CertificateLoader::CertificateLoaderResult CertificateLoader:: - loadCertificateFromRawData(const std::string &rawData) +CertificateLoader::CertificateLoaderResult CertificateLoader::loadCertificateFromRawData(const std::string &rawData) { - Try { - m_certificatePtr = - CertificatePtr(new Certificate(rawData, Certificate::FORM_BASE64)); - } Catch(Certificate::Exception::Base) { - LogWarning("Error reading certificate by openssl."); + VcoreTry { + m_certificatePtr = CertificatePtr(new Certificate(rawData, Certificate::FORM_BASE64)); + } VcoreCatch(Certificate::Exception::Base) { + WrtLogW("Error reading certificate by openssl."); return UNKNOWN_ERROR; } // Check the key length if sig algorithm is RSA EVP_PKEY *pKey = X509_get_pubkey(m_certificatePtr->getX509()); - if (pKey->type == EVP_PKEY_RSA) { - RSA* pRSA = pKey->pkey.rsa; + if (pKey != NULL) { + if (pKey->type == EVP_PKEY_RSA) { + RSA* pRSA = pKey->pkey.rsa; - if (pRSA) { - int keyLength = RSA_size(pRSA); + if (pRSA) { + int keyLength = RSA_size(pRSA); - // key Length (modulus) is in bytes - keyLength <<= 3; - LogDebug("RSA key length: " << keyLength << " bits"); + // key Length (modulus) is in bytes + keyLength <<= 3; + WrtLogD("RSA key length: %d bits", keyLength); - if (keyLength < MIN_RSA_KEY_LENGTH) { - LogError( - "RSA key too short!" << "Has only " << keyLength << " bits"); - return CERTIFICATE_SECURITY_ERROR; + if (keyLength < MIN_RSA_KEY_LENGTH) { + WrtLogE( + "RSA key too short! Has only %d bits", keyLength); + return CERTIFICATE_SECURITY_ERROR; + } } } } @@ -483,7 +483,7 @@ CertificateLoader::CertificateLoaderResult CertificateLoader:: // // if (result != OPERATION_SUCCESS) // { -// LogError("Unable to load certificate"); +// WrtLogE("Unable to load certificate"); // return UNKNOWN_ERROR; // } // @@ -512,11 +512,11 @@ CertificateLoader::CertificateLoaderResult CertificateLoader:: // // // key Length (modulus) is in bytes // keyLength <<= 3; -// LogDebug("RSA key length: " << keyLength << " bits"); +// WrtLogD("RSA key length: %d bits", keyLength); // // if (keyLength < MIN_RSA_KEY_LENGTH) // { -// LogError("RSA key too short!" << "Has only " << keyLength << " bits"); +// WrtLogE("RSA key too short! Has only %d bits.", keyLength); // return CERTIFICATE_SECURITY_ERROR; // } // } @@ -542,7 +542,7 @@ CertificateLoader::CertificateLoaderResult CertificateLoader:: (void) strJ; (void) strSeed; (void) strPGenCounter; - LogError("Not implemented."); + WrtLogE("Not implemented."); return UNKNOWN_ERROR; // (void)strY; // (void)strJ; @@ -578,7 +578,7 @@ CertificateLoader::CertificateLoaderResult CertificateLoader:: // // if (OPERATION_SUCCESS != certmgr_extract_certificate_data(&certRetrieved, &descriptor)) // { - // LogDebug("unable to retrieve cert from storage"); + // WrtLogD("unable to retrieve cert from storage"); // continue; // } // @@ -605,9 +605,9 @@ CertificateLoader::CertificateLoaderResult CertificateLoader:: // BN_cmp(pDSAqBigNum, pDSA->q) == 0 && // BN_cmp(pDSAgBigNum, pDSA->g) == 0) // { - // LogInfo("DSA Certificate found"); + // WrtLogI("DSA Certificate found"); // /* TODO load this certificate to m_cmBuff value */ - // LogError("Not implemented!"); + // WrtLogE("Not implemented!"); // // EVP_PKEY_free(pKey); // X509_free(pCertificate); @@ -639,12 +639,12 @@ CertificateLoader::CertificateLoaderResult CertificateLoader:: // X509_free(pCertificate); // } // else - // LogError("Unable to load certificate"); + // WrtLogE("Unable to load certificate"); // // certmgr_release_certificate_data(&descriptor); // } // - // LogError("No DSA certificate with given parameters"); + // WrtLogE("No DSA certificate with given parameters"); // // return CERTIFICATE_NOT_FOUND; } @@ -654,11 +654,11 @@ bool CertificateLoader::convertBase64NodeToBigNum(const std::string& strNode, { (void) strNode; (void) ppBigNum; - LogError("Not implemented."); + WrtLogE("Not implemented."); return false; // if (!ppBigNum || *ppBigNum != NULL) // { - // LogError("Ptr variable not initialized properly!"); + // WrtLogE("Ptr variable not initialized properly!"); // return false; // } // @@ -670,7 +670,7 @@ bool CertificateLoader::convertBase64NodeToBigNum(const std::string& strNode, // // if (!binBuff) // { - // LogError("base64 decode failed"); + // WrtLogE("base64 decode failed"); // return false; // } // @@ -681,7 +681,7 @@ bool CertificateLoader::convertBase64NodeToBigNum(const std::string& strNode, // // if (!(*ppBigNum)) // { - // LogError("Conversion from node to bignum failed"); + // WrtLogE("Conversion from node to bignum failed"); // return false; // } // @@ -692,7 +692,7 @@ bool CertificateLoader::convertBase64NodeToBigNum(const std::string& strNode, // KW { // KW if (!pBigNum) // KW { -// KW LogError("null ptr"); +// KW WrtLogE("null ptr"); // KW return false; // KW } // KW @@ -702,7 +702,7 @@ bool CertificateLoader::convertBase64NodeToBigNum(const std::string& strNode, // KW // convert bignum to binary format // KW if (BN_bn2bin(pBigNum, buffer) < 0) // KW { -// KW LogError("Conversion from bignum to binary failed"); +// KW WrtLogE("Conversion from bignum to binary failed"); // KW delete []buffer; // KW return false; // KW } diff --git a/vcore/src/vcore/CertificateLoader.h b/vcore/src/vcore/CertificateLoader.h index de92764..0d4fe04 100644 --- a/vcore/src/vcore/CertificateLoader.h +++ b/vcore/src/vcore/CertificateLoader.h @@ -27,7 +27,7 @@ #include <vcore/Certificate.h> namespace ValidationCore { -class CertificateLoader : public DPL::Noncopyable +class CertificateLoader : public VcoreDPL::Noncopyable { public: class CertificateLoaderComparator diff --git a/vcore/src/vcore/CertificateVerifier.cpp b/vcore/src/vcore/CertificateVerifier.cpp index ffc0dcc..d683883 100644 --- a/vcore/src/vcore/CertificateVerifier.cpp +++ b/vcore/src/vcore/CertificateVerifier.cpp @@ -23,7 +23,7 @@ #include <dpl/assert.h> #include <dpl/foreach.h> -#include <dpl/log/log.h> +#include <dpl/log/wrt_log.h> namespace ValidationCore { @@ -35,7 +35,7 @@ CertificateVerifier::CertificateVerifier(bool enableOcsp, bool enableCrl) VerificationStatus CertificateVerifier::check( CertificateCollection &certCollection) const { - LogDebug("== Certificate collection validation start =="); + WrtLogD("== Certificate collection validation start =="); Assert(certCollection.isChain() && "Collection must form chain."); VerificationStatus statusOcsp; @@ -52,14 +52,14 @@ VerificationStatus CertificateVerifier::check( } else { statusCrl = VERIFICATION_STATUS_GOOD; } - LogDebug("== Certificate collection validation end =="); + WrtLogD("== Certificate collection validation end =="); return getStatus(statusOcsp, statusCrl); } VerificationStatus CertificateVerifier::obtainOcspStatus( const CertificateCollection &chain) const { - LogDebug("== Obtain ocsp status =="); + WrtLogD("== Obtain ocsp status =="); CachedOCSP ocsp; return ocsp.check(chain); } @@ -67,7 +67,7 @@ VerificationStatus CertificateVerifier::obtainOcspStatus( VerificationStatus CertificateVerifier::obtainCrlStatus( const CertificateCollection &chain) const { - LogDebug("== Obtain crl status =="); + WrtLogD("== Obtain crl status =="); CachedCRL crl; return crl.check(chain); } @@ -79,26 +79,26 @@ VerificationStatus CertificateVerifier::getStatus( if (ocsp == VERIFICATION_STATUS_REVOKED || crl == VERIFICATION_STATUS_REVOKED) { - LogDebug("Return status: REVOKED"); + WrtLogD("Return status: REVOKED"); return VERIFICATION_STATUS_REVOKED; } if (ocsp == VERIFICATION_STATUS_GOOD) { - LogDebug("Return status: GOOD"); + WrtLogD("Return status: GOOD"); return VERIFICATION_STATUS_GOOD; } if (ocsp == VERIFICATION_STATUS_UNKNOWN) { - LogDebug("Return status: UNKNOWN"); + WrtLogD("Return status: UNKNOWN"); return VERIFICATION_STATUS_UNKNOWN; } if (ocsp == VERIFICATION_STATUS_NOT_SUPPORT) { - LogDebug("Return status: NOT_SUPPORT"); + WrtLogD("Return status: NOT_SUPPORT"); return VERIFICATION_STATUS_GOOD; } - LogDebug("Return status: ERROR"); + WrtLogD("Return status: ERROR"); return VERIFICATION_STATUS_ERROR; } @@ -125,7 +125,7 @@ VerificationStatus CertificateVerifier::checkEndEntity( } else { statusCrl.add(VERIFICATION_STATUS_GOOD); } - LogDebug("== Certificate collection validateion end =="); + WrtLogD("== Certificate collection validateion end =="); return getStatus(statusOcsp.convertToStatus(), statusCrl.convertToStatus()); } diff --git a/vcore/src/vcore/Config.h b/vcore/src/vcore/Config.h index a810414..8dccbe0 100644 --- a/vcore/src/vcore/Config.h +++ b/vcore/src/vcore/Config.h @@ -65,7 +65,7 @@ private: std::string m_certificateXMLSchemaPath; }; -typedef DPL::Singleton<Config> ConfigSingleton; +typedef VcoreDPL::Singleton<Config> ConfigSingleton; } // namespace ValidationCore diff --git a/vcore/src/vcore/CryptoHash.cpp b/vcore/src/vcore/CryptoHash.cpp index 2827b16..7ec4869 100644 --- a/vcore/src/vcore/CryptoHash.cpp +++ b/vcore/src/vcore/CryptoHash.cpp @@ -37,42 +37,6 @@ namespace Hash namespace // anonymous { const size_t HASH_DIGEST_STREAM_FEED_SIZE = 1024; - -std::string Raw2Base64(const void *buffer, size_t bufferSize) -{ - BIO *bio64, *biomem; - - if ((bio64 = BIO_new(BIO_f_base64())) == NULL) - ThrowMsg(AppendFailed, "BIO_new(BIO_f_base64()) failed!"); - - if ((biomem = BIO_new(BIO_s_mem())) == NULL) - { - BIO_free_all(bio64); - ThrowMsg(AppendFailed, "BIO_new(BIO_s_mem()) failed!"); - } - - bio64 = BIO_push(bio64, biomem); - - if (BIO_write(bio64, buffer, static_cast<int>(bufferSize)) <= 0) - { - BIO_free_all(bio64); - ThrowMsg(AppendFailed, "BIO_write failed!"); - } - - if (BIO_flush(bio64) <= 0) - { - BIO_free_all(bio64); - ThrowMsg(AppendFailed, "BIO_flush failed!"); - } - - BUF_MEM *bioptr; - BIO_get_mem_ptr(bio64, &bioptr); - - std::string base64 = std::string(static_cast<const char *>(bioptr->data), static_cast<const char *>(bioptr->data + bioptr->length)); - - BIO_free_all(bio64); - return base64; -} } // namespace anonymous Base::Base() @@ -87,7 +51,8 @@ Base::~Base() void Base::Append(const char *buffer) { if (m_hasFinal) - ThrowMsg(OutOfSequence, "Cannot append hash after final update!"); + VcoreThrowMsg(Crypto::Hash::OutOfSequence, + "Cannot append hash after final update!"); HashUpdate(buffer, strlen(buffer)); } @@ -95,7 +60,8 @@ void Base::Append(const char *buffer) void Base::Append(const char *buffer, size_t bufferSize) { if (m_hasFinal) - ThrowMsg(OutOfSequence, "Cannot append hash after final update!"); + VcoreThrowMsg(Crypto::Hash::OutOfSequence, + "Cannot append hash after final update!"); HashUpdate(buffer, bufferSize); } @@ -103,7 +69,8 @@ void Base::Append(const char *buffer, size_t bufferSize) void Base::Append(const std::string &buffer) { if (m_hasFinal) - ThrowMsg(OutOfSequence, "Cannot append hash after final update!"); + VcoreThrowMsg(Crypto::Hash::OutOfSequence, + "Cannot append hash after final update!"); HashUpdate(buffer.c_str(), buffer.size()); } @@ -111,7 +78,8 @@ void Base::Append(const std::string &buffer) void Base::Append(std::istream &stream) { if (m_hasFinal) - ThrowMsg(OutOfSequence, "Cannot append hash after final update!"); + VcoreThrowMsg(Crypto::Hash::OutOfSequence, + "Cannot append hash after final update!"); char buffer[HASH_DIGEST_STREAM_FEED_SIZE]; @@ -128,7 +96,8 @@ void Base::Append(std::istream &stream) void Base::Append(const void *data, size_t dataSize) { if (m_hasFinal) - ThrowMsg(OutOfSequence, "Cannot append hash after final update!"); + VcoreThrowMsg(Crypto::Hash::OutOfSequence, + "Cannot append hash after final update!"); HashUpdate(data, dataSize); } @@ -167,7 +136,8 @@ OpenSSL::OpenSSL(const EVP_MD *evpMd) EVP_MD_CTX_init(&m_context); if (EVP_DigestInit(&m_context, evpMd) != 1) - ThrowMsg(AppendFailed, "EVP_DigestInit failed!"); + VcoreThrowMsg(Crypto::Hash::AppendFailed, + "EVP_DigestInit failed!"); } OpenSSL::~OpenSSL() @@ -183,23 +153,27 @@ OpenSSL::~OpenSSL() void OpenSSL::HashUpdate(const void *data, size_t dataSize) { if (m_finalized) - ThrowMsg(AppendFailed, "OpenSSLHash hash already finalized!"); + VcoreThrowMsg(Crypto::Hash::AppendFailed, + "OpenSSLHash hash already finalized!"); if (EVP_DigestUpdate(&m_context, data, dataSize) != 1) - ThrowMsg(AppendFailed, "EVP_DigestUpdate failed!"); + VcoreThrowMsg(Crypto::Hash::AppendFailed, + "EVP_DigestUpdate failed!"); } Hash::Raw OpenSSL::HashFinal() { if (m_finalized) - ThrowMsg(AppendFailed, "OpenSSLHash hash already finalized!"); + VcoreThrowMsg(Crypto::Hash::AppendFailed, + "OpenSSLHash hash already finalized!"); unsigned char hash[EVP_MAX_MD_SIZE] = {}; unsigned int hashLength; // Also cleans context if (EVP_DigestFinal(&m_context, hash, &hashLength) != 1) - ThrowMsg(AppendFailed, "EVP_DigestFinal failed!"); + VcoreThrowMsg(Crypto::Hash::AppendFailed, + "EVP_DigestFinal failed!"); m_finalized = true; return Raw(hash, hash + hashLength); diff --git a/vcore/src/vcore/CryptoHash.h b/vcore/src/vcore/CryptoHash.h index aaed9e0..5611daf 100644 --- a/vcore/src/vcore/CryptoHash.h +++ b/vcore/src/vcore/CryptoHash.h @@ -22,32 +22,23 @@ #ifndef _CRYPTO_HASH_H_ #define _CRYPTO_HASH_H_ -#include <dpl/exception.h> #include <openssl/evp.h> #include <istream> #include <string> #include <vector> +#include <vcore/exception.h> + namespace ValidationCore { namespace Crypto { namespace Hash { -/** - * Raw hash buffer - */ typedef std::vector<unsigned char> Raw; -/** - * Append called out of sequence - */ -DECLARE_EXCEPTION_TYPE(DPL::Exception, OutOfSequence) - -/** - * Append failed internally - */ -DECLARE_EXCEPTION_TYPE(DPL::Exception, AppendFailed) +VCORE_DECLARE_EXCEPTION_TYPE(ValidationCore::Exception, OutOfSequence) +VCORE_DECLARE_EXCEPTION_TYPE(ValidationCore::Exception, AppendFailed) class Base { diff --git a/vcore/src/vcore/Database.cpp b/vcore/src/vcore/Database.cpp index 5f03e45..839af32 100644 --- a/vcore/src/vcore/Database.cpp +++ b/vcore/src/vcore/Database.cpp @@ -20,5 +20,6 @@ * @brief This file contains the definition of webruntime database */ #include <vcore/Database.h> +#include <mutex> -DPL::Mutex g_vcoreDbQueriesMutex; +std::mutex g_vcoreDbQueriesMutex; diff --git a/vcore/src/vcore/Database.h b/vcore/src/vcore/Database.h index ca6efa2..f4a5d17 100644 --- a/vcore/src/vcore/Database.h +++ b/vcore/src/vcore/Database.h @@ -24,21 +24,21 @@ #include <dpl/db/thread_database_support.h> #include <dpl/db/sql_connection.h> -#include <dpl/mutex.h> #include <dpl/thread.h> +#include <mutex> -extern DPL::Mutex g_vcoreDbQueriesMutex; +extern std::mutex g_vcoreDbQueriesMutex; #define VCORE_DB_INTERNAL(tlsCommand, InternalType, interface) \ - static DPL::ThreadLocalVariable<InternalType> *tlsCommand ## Ptr = NULL; \ + static VcoreDPL::ThreadLocalVariable<InternalType> *tlsCommand ## Ptr = NULL; \ { \ - DPL::Mutex::ScopedLock lock(&g_vcoreDbQueriesMutex); \ + std::lock_guard<std::mutex> lock(g_vcoreDbQueriesMutex); \ if (!tlsCommand ## Ptr) { \ - static DPL::ThreadLocalVariable<InternalType> tmp; \ + static VcoreDPL::ThreadLocalVariable<InternalType> tmp; \ tlsCommand ## Ptr = &tmp; \ } \ } \ - DPL::ThreadLocalVariable<InternalType> &tlsCommand = *tlsCommand ## Ptr; \ + VcoreDPL::ThreadLocalVariable<InternalType> &tlsCommand = *tlsCommand ## Ptr; \ if (tlsCommand.IsNull()) { tlsCommand = InternalType(interface); } #define VCORE_DB_SELECT(name, type, interface) \ diff --git a/vcore/src/vcore/DeveloperModeValidator.cpp b/vcore/src/vcore/DeveloperModeValidator.cpp deleted file mode 100644 index a861728..0000000 --- a/vcore/src/vcore/DeveloperModeValidator.cpp +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/* - * @file DeveloperModeValidator.cpp - * @author Bartosz Janiak (b.janiak@samsung.com) - * @version 1.0 - * @brief DeveloperModeValidatorValidator - implementing WAC 2.0 spec, including TargetRestriction - */ - -#include <vcore/DeveloperModeValidator.h> - -#include <algorithm> -#include <vconf.h> -#include <dpl/log/log.h> -#include <dpl/scoped_free.h> - -namespace ValidationCore { - -DeveloperModeValidator::DeveloperModeValidator(bool complianceMode, - const std::string& fakeIMEI, - const std::string& fakeMEID) : - m_complianceModeEnabled(complianceMode), - m_developerModeEnabled(true), - m_fakeIMEI(fakeIMEI), - m_fakeMEID(fakeMEID) -{ -} - -DeveloperModeValidator::DeveloperModeValidator(bool complianceMode, - bool developerMode, - const std::string& fakeIMEI, - const std::string& fakeMEID, - const std::string& realMEID) : - m_complianceModeEnabled(complianceMode), - m_developerModeEnabled(developerMode), - m_fakeIMEI(fakeIMEI), - m_fakeMEID(fakeMEID), - m_realMEID(realMEID) -{ -} - -void DeveloperModeValidator::check(const SignatureData &data) -{ - LogDebug("entered"); - const SignatureData::IMEIList& IMEIList = data.getIMEIList(); - const SignatureData::MEIDList& MEIDList = data.getMEIDList(); - - if (IMEIList.empty() && MEIDList.empty()) { - LogDebug("No TargetRestriction in signature."); - return; - } - - if (!m_developerModeEnabled) { - Throw(Exception::NoTargetRestrictionSatisfied); - } - - if (!IMEIList.empty()) { - std::string phoneIMEIString = m_fakeIMEI; - if (!m_complianceModeEnabled) { - LogDebug("Compilance Mode is not enabled"); - DPL::ScopedFree<char> phoneIMEI( - vconf_get_str(VCONFKEY_TELEPHONY_IMEI)); - if (!phoneIMEI.Get()) { - ThrowMsg(Exception::NoTargetRestrictionSatisfied, - "Unable to get phone IMEI from vconf."); - } - phoneIMEIString = phoneIMEI.Get(); - } - - LogDebug("Phone IMEI: " << phoneIMEIString); - if (IMEIList.end() == - std::find(IMEIList.begin(), IMEIList.end(), phoneIMEIString)) - { - Throw(Exception::NoTargetRestrictionSatisfied); - } - } - - if (!MEIDList.empty()) { - std::string phoneMEIDString = m_fakeMEID; - if (!m_complianceModeEnabled) - { - if (m_realMEID.empty()) - { - ThrowMsg(Exception::NoTargetRestrictionSatisfied, - "Unable to get phone MEID from Tapi service."); - } - phoneMEIDString = m_realMEID; - } - - LogDebug("Phone MEID: " << phoneMEIDString); - if (MEIDList.end() == - std::find(MEIDList.begin(), MEIDList.end(), phoneMEIDString)) - { - Throw(Exception::NoTargetRestrictionSatisfied); - } - } - LogDebug("exit: ok"); -} - -} //ValidationCore diff --git a/vcore/src/vcore/DeveloperModeValidator.h b/vcore/src/vcore/DeveloperModeValidator.h deleted file mode 100644 index a0c37ba..0000000 --- a/vcore/src/vcore/DeveloperModeValidator.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/* - * @file DeveloperModeValidator.h - * @author Bartosz Janiak (b.janiak@samsung.com) - * @version 1.0 - * @brief DeveloperModeValidatorValidator - implementing WAC 2.0 spec, including TargetRestriction - */ -#ifndef _VALIDATION_CORE_DEVELOPER_MODE_VALIDATOR_H_ -#define _VALIDATION_CORE_DEVELOPER_MODE_VALIDATOR_H_ - -#include <string> -#include <dpl/exception.h> -#include <vcore/SignatureData.h> - -namespace ValidationCore { - -class DeveloperModeValidator -{ - public: - explicit DeveloperModeValidator( - bool complianceMode = false, - const std::string &fakeIMEI = "", - const std::string &fakeMEID = "") __attribute__((deprecated)); - - explicit DeveloperModeValidator(bool complianceMode = false, - bool developerMode = false, - const std::string &fakeIMEI = "", - const std::string &fakeMEID = "", - const std::string &realMEID = ""); - - class Exception - { - public: - DECLARE_EXCEPTION_TYPE(DPL::Exception, Base) - DECLARE_EXCEPTION_TYPE(Base, UnableToLoadTestCertificate) - DECLARE_EXCEPTION_TYPE(Base, NoTargetRestrictionSatisfied) - }; - - void check(const SignatureData &data); - private: - bool m_complianceModeEnabled; - bool m_developerModeEnabled; - std::string m_fakeIMEI; - std::string m_fakeMEID; - std::string m_realMEID; -}; - -} -#endif /* _VALIDATION_CORE_DEVELOPER_MODE_VALIDATOR_H_ */ - diff --git a/vcore/src/vcore/OCSP.cpp b/vcore/src/vcore/OCSP.cpp index 26f81c3..1e94b17 100644 --- a/vcore/src/vcore/OCSP.cpp +++ b/vcore/src/vcore/OCSP.cpp @@ -24,11 +24,12 @@ namespace ValidationCore { -OCSP::OCSP() : - m_impl(new OCSPImpl()) +OCSP::OCSP() + : m_impl(new OCSPImpl()) {} -OCSP::~OCSP(){ +OCSP::~OCSP() +{ delete m_impl; } diff --git a/vcore/src/vcore/OCSP.h b/vcore/src/vcore/OCSP.h index 59c6969..76ac117 100644 --- a/vcore/src/vcore/OCSP.h +++ b/vcore/src/vcore/OCSP.h @@ -25,8 +25,6 @@ #include <ctime> -#include <dpl/noncopyable.h> - #include <vcore/Certificate.h> #include <vcore/CertificateCollection.h> #include <vcore/VerificationStatus.h> @@ -35,9 +33,12 @@ namespace ValidationCore { class OCSPImpl; -class OCSP : DPL::Noncopyable -{ +class OCSP { public: + + OCSP(const OCSP &) = delete; + const OCSP &operator=(const OCSP &) = delete; + OCSP(); VerificationStatus checkEndEntity(const CertificateCollection &certList); @@ -82,6 +83,7 @@ public: virtual ~OCSP(); private: OCSPImpl *m_impl; + }; } // namespace ValidationCore diff --git a/vcore/src/vcore/OCSPCertMgrUtil.cpp b/vcore/src/vcore/OCSPCertMgrUtil.cpp index 5db4290..019cd1f 100644 --- a/vcore/src/vcore/OCSPCertMgrUtil.cpp +++ b/vcore/src/vcore/OCSPCertMgrUtil.cpp @@ -27,7 +27,8 @@ #include <openssl/pem.h> #include <openssl/x509.h> -#include <dpl/log/log.h> +#include <dpl/assert.h> +#include <dpl/log/wrt_log.h> #include <dpl/scoped_resource.h> #include <string.h> #include <iostream> @@ -68,11 +69,11 @@ void getCertFromStore(X509_NAME *subject, X509 **xcert) { if (!xcert || *xcert || !subject) { - LogError("Invalid input!"); + WrtLogE("Invalid input!"); return; } - typedef DPL::ScopedResource<ContextDeleter> ScopedContext; + typedef VcoreDPL::ScopedResource<ContextDeleter> ScopedContext; int result; char buffer[MAX_BUF]; @@ -84,43 +85,43 @@ void getCertFromStore(X509_NAME *subject, ScopedContext ctx(cert_svc_cert_context_init()); if (ctx.Get() == NULL) { - LogWarning("Error in cert_svc_cert_context_init."); + WrtLogW("Error in cert_svc_cert_context_init."); return; } - LogDebug("Search certificate with subject: " << buffer); + WrtLogD("Search certificate with subject: %s", buffer); result = cert_svc_search_certificate(ctx.Get(), SUBJECT_STR, buffer); - LogDebug("Search finished!"); + WrtLogD("Search finished!"); if (CERT_SVC_ERR_NO_ERROR != result) { - LogWarning("Error during certificate search"); + WrtLogW("Error during certificate search"); return; } fileList = ctx.Get()->fileNames; if (fileList == NULL) { - LogDebug("No certificate found"); + WrtLogD("No certificate found"); return; } if (fileList->filename == NULL) { - LogWarning("Empty filename"); + WrtLogW("Empty filename"); return; } - LogDebug("Found cert file: " << fileList->filename); + WrtLogD("Found cert file: %s", fileList->filename); ScopedContext ctx2(cert_svc_cert_context_init()); if (ctx2.Get() == NULL) { - LogWarning("Error in cert_svc_cert_context_init."); + WrtLogW("Error in cert_svc_cert_context_init."); return; } // TODO add read_certifcate_from_file function to Certificate.h if (CERT_SVC_ERR_NO_ERROR != cert_svc_load_file_to_context(ctx2.Get(), fileList->filename)) { - LogWarning("Error in cert_svc_load_file_to_context"); + WrtLogW("Error in cert_svc_load_file_to_context"); return; } @@ -129,20 +130,18 @@ void getCertFromStore(X509_NAME *subject, pCertificate = d2i_X509(NULL, &ptr, ctx2.Get()->certBuf->size); if (pCertificate == NULL) { - LogWarning("Error during certificate conversion in d2i_X509"); + WrtLogW("Error during certificate conversion in d2i_X509"); return; } *xcert = pCertificate; if (fileList->next != NULL) { - LogError("There is more then one certificate with same subject :/"); + WrtLogE("There is more then one certificate with same subject :/"); // TODO Implement me. for (fileList = fileList->next; fileList != NULL; fileList = fileList->next) { - LogError( - "Additional certificate with same subject: " << - fileList->filename); + WrtLogE("Additional certificate with same subject: %s", fileList->filename); } } } diff --git a/vcore/src/vcore/OCSPImpl.cpp b/vcore/src/vcore/OCSPImpl.cpp index face891..98fc030 100644 --- a/vcore/src/vcore/OCSPImpl.cpp +++ b/vcore/src/vcore/OCSPImpl.cpp @@ -22,7 +22,6 @@ * @brief Routines for certificate validation over OCSP */ -#include <vcore/OCSP.h> #include <vcore/OCSPImpl.h> #include <string.h> @@ -32,11 +31,11 @@ #include <openssl/crypto.h> #include <openssl/err.h> #include <openssl/x509v3.h> +#include <boost/optional.hpp> -#include <dpl/log/log.h> +#include <dpl/log/wrt_log.h> #include <dpl/assert.h> #include <dpl/foreach.h> -#include <dpl/scoped_array.h> #include <dpl/scoped_free.h> #include <libsoup/soup.h> @@ -100,21 +99,19 @@ OCSPImpl::OCSPImpl() : m_bUseDefResponder(false), m_bSignRequest(false), m_pSignKey(0) -{ -} +{} SoupWrapper::SoupMessageSendBase::RequestStatus OCSPImpl::sendOcspRequest( OCSP_REQUEST* argRequest, - const DPL::OptionalString& argUri) + const std::string& argUri) { using namespace SoupWrapper; // convert OCSP_REQUEST to memory buffer - std::string url = DPL::ToUTF8String(*argUri); char* requestBuffer; int requestSizeInt; if (!convertToBuffer(argRequest, &requestBuffer, &requestSizeInt)) { - ThrowMsg(Exception::VerificationError, - "OCSP: failed to convert OCSP_REQUEST to mem buffer"); + VcoreThrowMsg(OCSPImpl::Exception::VerificationError, + "OCSP: failed to convert OCSP_REQUEST to mem buffer"); } Assert(requestSizeInt >= 0); @@ -127,13 +124,13 @@ SoupWrapper::SoupMessageSendBase::RequestStatus OCSPImpl::sendOcspRequest( char *cport = 0,*chost = 0,*cpath = 0; int use_ssl = 0; - if (!OCSP_parse_url(const_cast<char*>(url.c_str()), + if (!OCSP_parse_url(const_cast<char*>(argUri.c_str()), &chost, &cport, &cpath, &use_ssl)) { - LogWarning("Error in OCSP_parse_url"); + WrtLogW("Error in OCSP_parse_url"); return SoupMessageSendBase::REQUEST_STATUS_CONNECTION_ERROR; } @@ -148,7 +145,7 @@ SoupWrapper::SoupMessageSendBase::RequestStatus OCSPImpl::sendOcspRequest( free(chost); free(cpath); - m_soupMessage.setHost(url); + m_soupMessage.setHost(argUri); m_soupMessage.setHeader("Host", host); m_soupMessage.setRequest(std::string("application/ocsp-request"), buffer); @@ -163,9 +160,8 @@ ValidationCore::VerificationStatusSet OCSPImpl::validateCertificateList( if (certs.size() < 2) { // no certificates to verify, just return a error - LogWarning("No validation will be proceed. OCSP require at" - " least 2 certificates in chain. Found only " << - certs.size()); + WrtLogW("No validation will be proceed. OCSP require at" + " least 2 certificates in chain. Found only %d", certs.size()); statusSet.add(VERIFICATION_STATUS_ERROR); return statusSet; } @@ -173,7 +169,7 @@ ValidationCore::VerificationStatusSet OCSPImpl::validateCertificateList( CertificatePtr root = certs.back(); CertStoreId::Set storedSetId = createCertificateIdentifier().find(root); char* ocspUrl = storedSetId.getOcspUrl(); - + if (ocspUrl != NULL) { setUseDefaultResponder(true); @@ -185,10 +181,8 @@ ValidationCore::VerificationStatusSet OCSPImpl::validateCertificateList( time_t minValidity = 0; for (++parent; parent != certs.end(); ++iter, ++parent) { - LogDebug("Certificate validation (CN:" << - (*iter)->getOneLine() << ")"); - LogDebug("Parent certificate (CN:" << - (*parent)->getOneLine() << ")"); + WrtLogD("Certificate validation (CN:%s)", (*iter)->getOneLine().c_str()); + WrtLogD("Parent certificate (CN:%s)", (*parent)->getOneLine().c_str()); statusSet.add(validateCertificate(*iter, *parent)); if ((0 == minValidity || minValidity > m_responseValidity) && m_responseValidity > 0) @@ -227,20 +221,20 @@ VerificationStatus OCSPImpl::validateCertificate(CertificatePtr argCert, Assert(!!argCert); Assert(!!argIssuer); - Try { - DPL::OptionalString uri; + VcoreTry { + std::string uri; if (!m_bUseDefResponder) { uri = argCert->getOCSPURL(); - if (!uri) { + if (uri.empty()) { return VERIFICATION_STATUS_NOT_SUPPORT; } } else { if (m_strResponderURI.empty()) { - ThrowMsg(Exception::VerificationError, - "Default responder is not set"); + VcoreThrowMsg(OCSPImpl::Exception::VerificationError, + "Default responder is not set"); } - LogWarning("Default responder will be used"); + WrtLogW("Default responder will be used"); uri = m_strResponderURI; } @@ -248,7 +242,7 @@ VerificationStatus OCSPImpl::validateCertificate(CertificatePtr argCert, // creates a request CreateRequestResult newRequest = createRequest(argCert, argIssuer); if (!newRequest.success) { - ThrowMsg(Exception::VerificationError, "Request creation failed"); + VcoreThrowMsg(OCSPImpl::Exception::VerificationError, "Request creation failed"); } // SSLSmartContainer <OCSP_CERTID> certIdCont(certId); @@ -267,8 +261,8 @@ VerificationStatus OCSPImpl::validateCertificate(CertificatePtr argCert, OcspResponse response = convertToResponse(); if (!response.first) { - ThrowMsg(OCSPImpl::Exception::VerificationError, - "OCSP: failed to convert mem buffer to OCSP_RESPONSE"); + VcoreThrowMsg(OCSPImpl::Exception::VerificationError, + "OCSP: failed to convert mem buffer to OCSP_RESPONSE"); } SSLSmartContainer <OCSP_RESPONSE> responseCont(response.second); @@ -277,33 +271,49 @@ VerificationStatus OCSPImpl::validateCertificate(CertificatePtr argCert, validateResponse(requestCont, responseCont, newRequest.ocspCertId); - } Catch(Exception::ConnectionError) { - LogWarning("OCSP: ConnectionError"); + } VcoreCatch(OCSPImpl::Exception::ConnectionError) { + WrtLogW("OCSP: ConnectionError"); return VERIFICATION_STATUS_CONNECTION_FAILED; - } Catch(Exception::CertificateRevoked) { - LogWarning("OCSP: Revoked"); + } VcoreCatch(OCSPImpl::Exception::CertificateRevoked) { + WrtLogW("OCSP: Revoked"); return VERIFICATION_STATUS_REVOKED; - } Catch(Exception::CertificateUnknown) { - LogWarning("OCSP: Unknown"); + } VcoreCatch(OCSPImpl::Exception::CertificateUnknown) { + WrtLogW("OCSP: Unknown"); return VERIFICATION_STATUS_UNKNOWN; - } Catch(Exception::VerificationError) { - LogWarning("OCSP: Verification error"); + } VcoreCatch(OCSPImpl::Exception::VerificationError) { + WrtLogW("OCSP: Verification error"); return VERIFICATION_STATUS_VERIFICATION_ERROR; - } Catch(Exception::Base) { - LogWarning("OCSP: Error"); + } VcoreCatch(OCSPImpl::Exception::Base) { + WrtLogW("OCSP: Error"); return VERIFICATION_STATUS_ERROR; } - LogWarning("OCSP: Good"); + WrtLogW("OCSP: Good"); return VERIFICATION_STATUS_GOOD; } +void OCSPImpl::setDefaultResponder(const char *uri) +{ + Assert(uri); + m_strResponderURI = std::string(uri); +} + +void OCSPImpl::setUseDefaultResponder(bool value) +{ + m_bUseDefResponder = value; +} + +time_t OCSPImpl::getResponseValidity() +{ + return m_responseValidity; +} + OCSPImpl::CreateRequestResult OCSPImpl::createRequest(CertificatePtr argCert, CertificatePtr argIssuer) { OCSP_REQUEST* newRequest = OCSP_REQUEST_new(); if (!newRequest) { - LogWarning("OCSP: Failed to create a request"); + WrtLogW("OCSP: Failed to create a request"); return CreateRequestResult(); } @@ -312,14 +322,14 @@ OCSPImpl::CreateRequestResult OCSPImpl::createRequest(CertificatePtr argCert, OCSP_CERTID* certId = addSerial(argCert, argIssuer); if (!certId) { - LogWarning("OCSP: Unable to create a serial id"); + WrtLogW("OCSP: Unable to create a serial id"); return CreateRequestResult(); } SSLSmartContainer <OCSP_CERTID> certIdCont(certId); // Inserting certificate ID to request if (!OCSP_request_add0_id(requestCont, certIdCont)) { - LogWarning("OCSP: Unable to create a certificate id"); + WrtLogW("OCSP: Unable to create a certificate id"); return CreateRequestResult(); } @@ -329,7 +339,7 @@ OCSPImpl::CreateRequestResult OCSPImpl::createRequest(CertificatePtr argCert, if (m_bSignRequest) { if (!m_pSignCert || !m_pSignKey) { - LogWarning("OCSP: Unable to sign request if " + WrtLogW("OCSP: Unable to sign request if " "SignCert or SignKey was not set"); return CreateRequestResult(); } @@ -341,7 +351,7 @@ OCSPImpl::CreateRequestResult OCSPImpl::createRequest(CertificatePtr argCert, 0, 0)) { - LogWarning("OCSP: Unable to sign request"); + WrtLogW("OCSP: Unable to sign request"); return CreateRequestResult(); } } @@ -367,7 +377,7 @@ void OCSPImpl::setDigestAlgorithmForCertId(OCSP::DigestAlgorithm alg) if (NULL != foundAlg) { m_pCertIdDigestAlg = foundAlg; } else { - LogDebug("Request for unsupported CertId digest algorithm" + WrtLogD("Request for unsupported CertId digest algorithm" "ignored!"); } } @@ -379,7 +389,7 @@ void OCSPImpl::setDigestAlgorithmForRequest(OCSP::DigestAlgorithm alg) if (NULL != foundAlg) { m_pRequestDigestAlg = foundAlg; } else { - LogDebug("Request for unsupported OCSP request digest algorithm" + WrtLogD("Request for unsupported OCSP request digest algorithm" "ignored!"); } } @@ -402,24 +412,24 @@ void OCSPImpl::validateResponse(OCSP_REQUEST* argRequest, if (result != OCSP_RESPONSE_STATUS_SUCCESSFUL) { handleInvalidResponse(result); - ThrowMsg(Exception::VerificationError, "OCSP_response_status failed"); + VcoreThrowMsg(OCSPImpl::Exception::VerificationError, "OCSP_response_status failed"); } // get response object OCSP_BASICRESP* basic = OCSP_response_get1_basic(argResponse); if (!basic) { - ThrowMsg(Exception::VerificationError, - "OCSP: Unable to get a BASICRESP object."); + VcoreThrowMsg(OCSPImpl::Exception::VerificationError, + "OCSP: Unable to get a BASICRESP object."); } SSLSmartContainer <OCSP_BASICRESP> basicRespCont(basic); if (m_bUseNonce && OCSP_check_nonce(argRequest, basicRespCont) <= 0) { - ThrowMsg(Exception::VerificationError, "OCSP: Invalid nonce"); + VcoreThrowMsg(OCSPImpl::Exception::VerificationError, "OCSP: Invalid nonce"); } if (!verifyResponse(basic)) { - ThrowMsg(Exception::VerificationError, - "Unable to verify the OCSP responder's certificate"); + VcoreThrowMsg(OCSPImpl::Exception::VerificationError, + "Unable to verify the OCSP responder's certificate"); } checkRevocationStatus(basicRespCont, argCertId); @@ -431,7 +441,7 @@ bool OCSPImpl::verifyResponse(OCSP_BASICRESP* basic) // verify ocsp response int response = OCSP_basic_verify(basic, NULL, m_pTrustedStore, 0); if (response <= 0) { - LogWarning("OCSP verification failed"); + WrtLogW("OCSP verification failed"); } return response > 0; @@ -456,8 +466,8 @@ void OCSPImpl::checkRevocationStatus(OCSP_BASICRESP* basic, &thisUpdate, &nextUpdate)) { - ThrowMsg(Exception::VerificationError, - "OCSP: Failed to find certificate status."); + VcoreThrowMsg(OCSPImpl::Exception::VerificationError, + "OCSP: Failed to find certificate status."); } if (!OCSP_check_validity(thisUpdate, @@ -465,27 +475,26 @@ void OCSPImpl::checkRevocationStatus(OCSP_BASICRESP* basic, MaxValidatyPeriodInSeconds, MaxAge)) { - ThrowMsg(Exception::VerificationError, - "OCSP: Failed to check certificate validate."); + VcoreThrowMsg(OCSPImpl::Exception::VerificationError, + "OCSP: Failed to check certificate validate."); } if (nextUpdate) { asn1GeneralizedTimeToTimeT(nextUpdate,&m_responseValidity); time_t now; time(&now); - LogDebug("Time of next OCSP update got from server: " << - m_responseValidity); - LogDebug("Expires in: " << (m_responseValidity - now)); - LogDebug("Original: " << nextUpdate->data); + WrtLogD("Time of next OCSP update got from server: %d", m_responseValidity); + WrtLogD("Expires in: %d", (m_responseValidity - now)); + WrtLogD("Original: %d", nextUpdate->data); } switch (status) { case V_OCSP_CERTSTATUS_GOOD: return; case V_OCSP_CERTSTATUS_REVOKED: - ThrowMsg(Exception::CertificateRevoked, "Certificate is Revoked"); + VcoreThrowMsg(OCSPImpl::Exception::CertificateRevoked, "Certificate is Revoked"); case V_OCSP_CERTSTATUS_UNKNOWN: - ThrowMsg(Exception::CertificateUnknown, "Certificate is Unknown"); + VcoreThrowMsg(OCSPImpl::Exception::CertificateUnknown, "Certificate is Unknown"); default: Assert(false && "Invalid status"); } @@ -512,7 +521,7 @@ OCSPImpl::OcspResponse OCSPImpl::convertToResponse() BIO_free_all(res_mem_bio); if (!response) { - LogWarning("OCSP: Failed to convert OCSP Response to DER format"); + WrtLogW("OCSP: Failed to convert OCSP Response to DER format"); return std::make_pair(false, static_cast<OCSP_RESPONSE*>(NULL)); } @@ -523,23 +532,23 @@ void OCSPImpl::handleInvalidResponse(int result) { switch (result) { case OCSP_RESPONSE_STATUS_MALFORMEDREQUEST: - LogWarning("OCSP: Server returns " + WrtLogW("OCSP: Server returns " "OCSP_RESPONSE_STATUS_MALFORMEDREQUEST status"); break; case OCSP_RESPONSE_STATUS_INTERNALERROR: - LogWarning("OCSP: Server returns " + WrtLogW("OCSP: Server returns " "OCSP_RESPONSE_STATUS_INTERNALERROR status"); break; case OCSP_RESPONSE_STATUS_TRYLATER: - LogWarning("OCSP: Server returns " + WrtLogW("OCSP: Server returns " "OCSP_RESPONSE_STATUS_TRYLATER status"); break; case OCSP_RESPONSE_STATUS_SIGREQUIRED: - LogWarning("OCSP: Server returns " + WrtLogW("OCSP: Server returns " "OCSP_RESPONSE_STATUS_SIGREQUIRED status"); break; case OCSP_RESPONSE_STATUS_UNAUTHORIZED: - LogWarning("OCSP: Server returns " + WrtLogW("OCSP: Server returns " "OCSP_RESPONSE_STATUS_UNAUTHORIZED status"); break; default: diff --git a/vcore/src/vcore/OCSPImpl.h b/vcore/src/vcore/OCSPImpl.h index 11cd647..00f568f 100644 --- a/vcore/src/vcore/OCSPImpl.h +++ b/vcore/src/vcore/OCSPImpl.h @@ -36,9 +36,6 @@ #include <openssl/ocsp.h> #include <libsoup/soup.h> -#include <dpl/assert.h> -#include <dpl/exception.h> - #include <vcore/scoped_gpointer.h> #include <vcore/OCSPCertMgrUtil.h> #include <vcore/CertificateCollection.h> @@ -48,6 +45,7 @@ #include <vcore/SoupMessageSendBase.h> #include <vcore/SoupMessageSendSync.h> #include <vcore/TimeConversion.h> +#include <vcore/exception.h> /* * The WRT MUST NOT allow installation of widgets with revoked signatures. * @@ -82,13 +80,13 @@ namespace ValidationCore { -class OCSPImpl -{ - public: +class OCSPImpl { +public: + OCSPImpl(); + static const char* DEFAULT_RESPONDER_URI_ENV; VerificationStatus checkEndEntity(const CertificateCollection &certList); - OCSPImpl(); /** * Sets digest algorithm for certid in ocsp request @@ -107,28 +105,28 @@ class OCSPImpl VerificationStatus validateCertificate(CertificatePtr argCert, CertificatePtr argIssuer); - void setDefaultResponder(const char* uri) - { - Assert(uri); - m_strResponderURI = DPL::FromUTF8String(uri); - } + void setDefaultResponder(const char* uri); - void setUseDefaultResponder(bool value) - { - m_bUseDefResponder = value; - } + void setUseDefaultResponder(bool value); /** * @return time when response will become invalid - for list of * certificates, this is the minimum of all validities; value is * valid only for not-revoked certificates (non error validation result) */ - time_t getResponseValidity() - { - return m_responseValidity; - } - - private: + time_t getResponseValidity(); + +private: + class Exception { + public: + VCORE_DECLARE_EXCEPTION_TYPE(ValidationCore::Exception, Base) + VCORE_DECLARE_EXCEPTION_TYPE(Base, ConnectionError) + VCORE_DECLARE_EXCEPTION_TYPE(Base, CertificateRevoked) + VCORE_DECLARE_EXCEPTION_TYPE(Base, CertificateUnknown) + VCORE_DECLARE_EXCEPTION_TYPE(Base, VerificationError) + VCORE_DECLARE_EXCEPTION_TYPE(Base, RetrieveCertFromStoreError) + VCORE_DECLARE_EXCEPTION_TYPE(Base, VerificationNotSupport) + }; typedef WRT::ScopedGPointer<SoupSession> ScopedSoupSession; typedef WRT::ScopedGPointer<SoupMessage> ScopedSoupMessage; @@ -146,18 +144,6 @@ class OCSPImpl char** responseBuffer, size_t* responseSize); - class Exception - { - public: - DECLARE_EXCEPTION_TYPE(DPL::Exception, Base) - DECLARE_EXCEPTION_TYPE(Base, ConnectionError) - DECLARE_EXCEPTION_TYPE(Base, CertificateRevoked) - DECLARE_EXCEPTION_TYPE(Base, CertificateUnknown) - DECLARE_EXCEPTION_TYPE(Base, VerificationError) - DECLARE_EXCEPTION_TYPE(Base, RetrieveCertFromStoreError) - DECLARE_EXCEPTION_TYPE(Base, VerificationNotSupport) - }; - const EVP_MD* m_pCertIdDigestAlg; const EVP_MD* m_pRequestDigestAlg; @@ -165,7 +151,7 @@ class OCSPImpl SoupWrapper::SoupMessageSendBase::RequestStatus sendOcspRequest( OCSP_REQUEST* argRequest, - const DPL::String& argUri); + const std::string& argUri); @@ -220,7 +206,7 @@ class OCSPImpl time_t m_responseValidity; bool m_bUseNonce; bool m_bUseDefResponder; - DPL::String m_strResponderURI; + std::string m_strResponderURI; bool m_bSignRequest; EVP_PKEY* m_pSignKey; CertificatePtr m_pSignCert; diff --git a/vcore/src/vcore/ParserSchema.h b/vcore/src/vcore/ParserSchema.h index ed9eb68..8e7b507 100644 --- a/vcore/src/vcore/ParserSchema.h +++ b/vcore/src/vcore/ParserSchema.h @@ -25,25 +25,23 @@ #include <map> #include <string> -#include <dpl/log/log.h> - #include <vcore/SaxReader.h> +#include <vcore/exception.h> namespace ValidationCore { namespace ParserSchemaException { -DECLARE_EXCEPTION_TYPE(DPL::Exception, Base) -DECLARE_EXCEPTION_TYPE(Base, XmlReaderError) -DECLARE_EXCEPTION_TYPE(Base, CertificateLoaderError) -DECLARE_EXCEPTION_TYPE(Base, UnsupportedAlgorithm) -DECLARE_EXCEPTION_TYPE(Base, UnsupportedValue) + VCORE_DECLARE_EXCEPTION_TYPE(ValidationCore::Exception, Base); + VCORE_DECLARE_EXCEPTION_TYPE(Base, XmlReaderError); + VCORE_DECLARE_EXCEPTION_TYPE(Base, CertificateLoaderError); + VCORE_DECLARE_EXCEPTION_TYPE(Base, UnsupportedAlgorithm); + VCORE_DECLARE_EXCEPTION_TYPE(Base, UnsupportedValue); } template<typename ParserType, typename DataType> -class ParserSchema -{ - public: - struct TagDescription - { +class ParserSchema { +public: + + struct TagDescription { TagDescription(const std::string &tag, const std::string & xmlNamespace) : tagName(tag), @@ -69,27 +67,25 @@ class ParserSchema } }; - ParserSchema(ParserType * parser) : - m_functions(parser) - { - } - virtual ~ParserSchema() - { - } + ParserSchema(ParserType *parser) + : m_functions(parser) {} + + virtual ~ParserSchema() {} - void initialize(const std::string &filename, + void initialize( + const std::string &filename, bool defaultArgs, SaxReader::ValidationType valType, const std::string &xmlschema) { - Try + VcoreTry { m_reader.initialize(filename, defaultArgs, valType, xmlschema); } - Catch(SaxReader::Exception::Base) + VcoreCatch (SaxReader::Exception::Base) { - ReThrowMsg(ParserSchemaException::XmlReaderError, "XmlReaderError"); + VcoreReThrowMsg(ParserSchemaException::XmlReaderError, "XmlReaderError"); } } @@ -100,7 +96,8 @@ class ParserSchema void read(DataType &dataContainer) { - Try { + VcoreTry + { while (m_reader.next()) { switch (m_reader.type()) { case SaxReader::NODE_BEGIN: @@ -113,21 +110,21 @@ class ParserSchema textNode(dataContainer); break; default: - // LogInfo("Unknown Type Node"); break; } } } - Catch(SaxReader::Exception::Base) + VcoreCatch (SaxReader::Exception::Base) { - ReThrowMsg(ParserSchemaException::XmlReaderError, "XmlReaderError"); + VcoreReThrowMsg(ParserSchemaException::XmlReaderError, "XmlReaderError"); } } typedef void (ParserType::*FunctionPtr)(DataType &data); typedef std::map<TagDescription, FunctionPtr> FunctionMap; - void addBeginTagCallback(const std::string &tag, + void addBeginTagCallback( + const std::string &tag, const std::string &namespaceUri, FunctionPtr function) { @@ -135,7 +132,8 @@ class ParserSchema m_beginFunctionMap[desc] = function; } - void addEndTagCallback(const std::string &tag, + void addEndTagCallback( + const std::string &tag, const std::string &namespaceUri, FunctionPtr function) { @@ -143,24 +141,23 @@ class ParserSchema m_endFunctionMap[desc] = function; } - SaxReader& getReader(void) + SaxReader& getReader() { return m_reader; } - std::string& getText(void) + std::string& getText() { return m_textNode; } - protected: +protected: void beginNode(DataType &dataContainer) { TagDescription desc(m_reader.name(), m_reader.namespaceURI()); FunctionPtr fun = m_beginFunctionMap[desc]; if (fun == 0) { - LogDebug("No function found for xml tag: " << m_reader.name()); return; } @@ -173,7 +170,6 @@ class ParserSchema FunctionPtr fun = m_endFunctionMap[desc]; if (fun == 0) { - LogDebug("No function found for xml tag: " << m_reader.name()); return; } @@ -187,7 +183,6 @@ class ParserSchema } ParserType *m_functions; - SaxReader m_reader; FunctionMap m_beginFunctionMap; FunctionMap m_endFunctionMap; @@ -195,5 +190,6 @@ class ParserSchema // temporary values require due parsing textNode std::string m_textNode; }; + } // namespace ValidationCore #endif diff --git a/vcore/src/vcore/ReferenceValidator.cpp b/vcore/src/vcore/ReferenceValidator.cpp index e99436c..188a24e 100644 --- a/vcore/src/vcore/ReferenceValidator.cpp +++ b/vcore/src/vcore/ReferenceValidator.cpp @@ -29,7 +29,7 @@ #include <pcrecpp.h> #include <dpl/errno_string.h> -#include <dpl/log/log.h> +#include <dpl/log/wrt_log.h> namespace { @@ -97,7 +97,7 @@ int ReferenceValidator::Impl::hexToInt(char a) { if (a >= '0' && a <= '9') return a-'0'; if (a >= 'A' && a <= 'F') return a-'A' + 10; if (a >= 'a' && a <= 'f') return a-'a' + 10; - LogError("Symbol '" << a << "' is out of scope."); + WrtLogE("Symbol '%c' is out of scope.", a); throw ERROR_DECODING_URL; } @@ -125,7 +125,7 @@ std::string ReferenceValidator::Impl::decodeProcent(const std::string &path) { } } } catch (Result &) { - LogError("Error while decoding url path: " << path); + WrtLogE("Error while decoding url path: %s", path.c_str()); throw ERROR_DECODING_URL; } return std::string(output.begin(), output.end()); @@ -138,14 +138,10 @@ ReferenceValidator::Result ReferenceValidator::Impl::dfsCheckDirectories( { DIR *dp; struct dirent *dirp; - std::string currentDir = m_dirpath; - if (!directory.empty()) { - currentDir += "/"; - currentDir += directory; - } + std::string currentDir = m_dirpath + directory; if ((dp = opendir(currentDir.c_str())) == NULL) { - LogError("Error opening directory: " << currentDir.c_str()); + WrtLogE("Error opening directory: %s", currentDir.c_str()); m_errorDescription = currentDir; return ERROR_OPENING_DIR; } @@ -172,7 +168,7 @@ ReferenceValidator::Result ReferenceValidator::Impl::dfsCheckDirectories( } if (dirp->d_type == DT_DIR) { - LogDebug("Open directory: " << (directory + dirp->d_name)); + WrtLogD("Open directory: %s", (directory + dirp->d_name).c_str()); std::string tmp_directory = directory + dirp->d_name + "/"; Result result = dfsCheckDirectories(referenceSet, tmp_directory, @@ -185,14 +181,14 @@ ReferenceValidator::Result ReferenceValidator::Impl::dfsCheckDirectories( if (referenceSet.end() == referenceSet.find(directory + dirp->d_name)) { - LogDebug("Found file: " << (directory + dirp->d_name)); - LogError("Unknown ERROR_REFERENCE_NOT_FOUND."); + WrtLogD("Found file: %s", (directory + dirp->d_name).c_str()); + WrtLogE("Unknown ERROR_REFERENCE_NOT_FOUND."); closedir(dp); m_errorDescription = directory + dirp->d_name; return ERROR_REFERENCE_NOT_FOUND; } } else { - LogError("Unknown file type."); + WrtLogE("Unknown file type."); closedir(dp); m_errorDescription = directory + dirp->d_name; return ERROR_UNSUPPORTED_FILE_TYPE; @@ -200,9 +196,8 @@ ReferenceValidator::Result ReferenceValidator::Impl::dfsCheckDirectories( } if (errno != 0) { - m_errorDescription = DPL::GetErrnoString(); - LogError("readdir failed. Errno code: " << errno << - " Description: " << m_errorDescription); + m_errorDescription = VcoreDPL::GetErrnoString(); + WrtLogE("readdir failed. Errno code: %d, Description: ", errno, m_errorDescription.c_str()); closedir(dp); return ERROR_READING_DIR; } diff --git a/vcore/src/vcore/ReferenceValidator.h b/vcore/src/vcore/ReferenceValidator.h index d7d964f..b370773 100644 --- a/vcore/src/vcore/ReferenceValidator.h +++ b/vcore/src/vcore/ReferenceValidator.h @@ -28,7 +28,7 @@ namespace ValidationCore { -class ReferenceValidator : DPL::Noncopyable +class ReferenceValidator : VcoreDPL::Noncopyable { public: enum Result diff --git a/vcore/src/vcore/RevocationCheckerBase.cpp b/vcore/src/vcore/RevocationCheckerBase.cpp index 8aa1d62..777da78 100644 --- a/vcore/src/vcore/RevocationCheckerBase.cpp +++ b/vcore/src/vcore/RevocationCheckerBase.cpp @@ -28,19 +28,17 @@ #include <dpl/scoped_fclose.h> -#include <tzplatform_config.h> - #include "Certificate.h" #include "CertificateCollection.h" namespace { -const char *DefaultBundlePatch = tzplatform_mkpath(TZ_SYS_ETC, "ssl/certs/ca-certificates.crt"); +const char DefaultBundlePatch[] = "/opt/etc/ssl/certs/ca-certificates.crt"; } //Anonymous name space namespace ValidationCore { CertificatePtr RevocationCheckerBase::loadPEMFile(const char* fileName) { - DPL::ScopedFClose fd(fopen(fileName, "rb")); + VcoreDPL::ScopedFClose fd(fopen(fileName, "rb")); // no such file, return NULL if (!fd.Get()) { diff --git a/vcore/src/vcore/SaxReader.cpp b/vcore/src/vcore/SaxReader.cpp index 1a0261b..5c49ece 100644 --- a/vcore/src/vcore/SaxReader.cpp +++ b/vcore/src/vcore/SaxReader.cpp @@ -20,12 +20,13 @@ * @brief Simple c++ interface for libxml2. */ #include <dpl/assert.h> -#include <dpl/exception.h> -#include <dpl/log/log.h> +#include <dpl/log/wrt_log.h> #include <vcore/SaxReader.h> namespace ValidationCore { + + SaxReader::SaxReader() : m_reader(0) { @@ -38,54 +39,49 @@ SaxReader::~SaxReader() } } -void SaxReader::initialize(const std::string &filename, - bool defaultArgs, - ValidationType validate, - const std::string &schema) +void SaxReader::initialize( + const std::string &filename, + bool defaultArgs, + ValidationType validate, + const std::string &schema) { Assert(m_reader == 0 && "Double initialization of SaxReader"); - LogDebug("SaxReader opening file: " << filename); + WrtLogD("SaxReader opening file: %s", filename.c_str()); - /* - * create a new xml text reader - */ m_reader = xmlNewTextReaderFilename(filename.c_str()); - if (m_reader == NULL) { - /* - * no such file, return - */ - LogWarning("Error during opening file " << filename); - Throw(Exception::FileOpeningError); + if (!m_reader) { + VcoreThrowMsg(SaxReader::Exception::FileOpeningError, + "opening file " << filename << " error"); } + if (validate == VALIDATION_XMLSCHEME && xmlTextReaderSchemaValidate(m_reader, schema.c_str())) { /* * unable to turn on schema validation */ - LogError("Turn on Schema validation failed."); - ThrowMsg(Exception::ParserInternalError, - "Turn on Scheme validation failed!"); + VcoreThrowMsg(SaxReader::Exception::ParserInternalError, + "Turn on Schema validation failed"); } + // Path to DTD schema is taken from xml file. if (validate == VALIDATION_DTD && xmlTextReaderSetParserProp(m_reader, XML_PARSER_VALIDATE, 1)) { /* * unable to turn on DTD validation */ - LogError("Turn on DTD validation failed!"); - ThrowMsg(Exception::ParserInternalError, - "Turn on DTD validation failed!"); + VcoreThrowMsg(SaxReader::Exception::ParserInternalError, + "Turn on DTD validation failed!"); } + if (defaultArgs && xmlTextReaderSetParserProp(m_reader, XML_PARSER_DEFAULTATTRS, 1)) { /* * unable to turn on default arguments */ - LogError("Turn on default arguments failed"); - ThrowMsg(Exception::ParserInternalError, - "Turn on Default Arguments failed!"); + VcoreThrowMsg(SaxReader::Exception::ParserInternalError, + "Turn on default arguments failed"); } } @@ -99,149 +95,117 @@ bool SaxReader::next() { int res = xmlTextReaderRead(m_reader); - if (0 == xmlTextReaderIsValid(m_reader)) { - LogWarning("Throw exception file not valid!"); - Throw(Exception::FileNotValid); - } + if (res < 0) + VcoreThrowMsg(SaxReader::Exception::ParserInternalError, + "xmlTextReaderRead error"); - if (res == 1) { - return true; - } + if (!xmlTextReaderIsValid(m_reader)) + VcoreThrowMsg(SaxReader::Exception::FileNotValid, + "xmlTextReader is invalid"); - if (res == 0) { - return false; - } - LogError("ParserInternalError"); - Throw(Exception::ParserInternalError); + return res ? true : false; } void SaxReader::next(const std::string &token) { - xmlTextReaderRead(m_reader); - if (0 == xmlTextReaderIsValid(m_reader)) { - /* - * invalid file - */ - LogWarning("Throw exception file not valid!"); - Throw(Exception::FileNotValid); - } + int res = xmlTextReaderRead(m_reader); + + if (res < 0) + VcoreThrowMsg(SaxReader::Exception::ParserInternalError, + "xmlTextReaderRead error"); + + if (!xmlTextReaderIsValid(m_reader)) + VcoreThrowMsg(SaxReader::Exception::FileNotValid, + "xmlTextReader is invalid"); xmlChar *name = xmlTextReaderName(m_reader); - if (name == NULL) { - /* - * invalid file - */ - LogWarning("File not Valid"); - Throw(Exception::FileNotValid); - } + if (!name) + VcoreThrowMsg(SaxReader::Exception::ParserInternalError, + "xmlTextReaderName returns NULL"); - if (token == reinterpret_cast<const char*>(name)) { - xmlFree(name); - } else { - /* - * we encountered wrong token - */ + xmlChar *xmlToken = xmlCharStrdup(token.c_str()); + + if (xmlStrcmp(name, xmlToken)) { xmlFree(name); - LogWarning("Wrong Token"); - Throw(Exception::WrongToken); + xmlFree(xmlToken); + + VcoreThrowMsg(SaxReader::Exception::WrongToken, "Wrong Token"); } + + xmlFree(name); + xmlFree(xmlToken); } bool SaxReader::isEmpty(void) { int ret = xmlTextReaderIsEmptyElement(m_reader); - if (-1 == ret) { - LogError("Parser Internal Error"); - Throw(Exception::ParserInternalErrorInEmptyQuery); - } - return ret; + if (-1 == ret) + VcoreThrowMsg(SaxReader::Exception::ParserInternalError, + "xmlTextReaderIsEmptyElement error"); + + return ret ? true : false; } -std::string SaxReader::attribute(const std::string &token, - ThrowType throwStatus) +std::string SaxReader::attribute(const std::string &token, ThrowType throwStatus) { - std::string value; xmlChar *attr = xmlTextReaderGetAttribute(m_reader, BAD_CAST(token.c_str())); - if ((NULL == attr) && (throwStatus == THROW_DISABLE)) { - /* - * return empty string - */ - //TODO why not DPL::Optional? - return std::string(); - } - if (NULL == attr) { - /* - * error during read attribute - */ - LogError("Error in reading attribute."); - Throw(Exception::ParserInternalErrorInReadingAttribute); + if (!attr) { + if (throwStatus == THROW_DISABLE) { + return std::string(); + } + else { + VcoreThrowMsg(SaxReader::Exception::ParserInternalError, + "xmlTextReaderGetAttribute error"); + } } - /* - * cast it to val and return it - */ - value = reinterpret_cast<const char *>(attr); + std::string value = reinterpret_cast<const char *>(attr); xmlFree(attr); + return value; } -// KW std::string SaxReader::fullName(){ -// KW std::string value; -// KW xmlChar *name = xmlTextReaderName(m_reader); -// KW if(NULL == name) { -// KW LogError("Error in reading name."); -// KW Throw(Exception::ErrorReadingName); -// KW } -// KW value = reinterpret_cast<const char *>(name); -// KW xmlFree(name); -// KW return value; -// KW } - std::string SaxReader::name() { - std::string value; xmlChar *name = xmlTextReaderName(m_reader); - if (NULL == name) { - LogError("Error in reading name."); - Throw(Exception::ErrorReadingName); - } - value = reinterpret_cast<const char *>(name); + if (!name) + VcoreThrowMsg(SaxReader::Exception::ReadingNameError, + "reading name error"); + + std::string value = reinterpret_cast<const char *>(name); xmlFree(name); size_t pos = value.find_last_of(":"); if (pos != std::string::npos) { value.erase(0, pos + 1); } + return value; } std::string SaxReader::namespaceURI() { - std::string value; xmlChar *name = xmlTextReaderNamespaceUri(m_reader); - if (NULL != name) { - value = reinterpret_cast<const char *>(name); - xmlFree(name); + if (!name) { + return std::string(); } + + std::string value = reinterpret_cast<const char *>(name); + xmlFree(name); + return value; } std::string SaxReader::value() { - std::string value; - /* - * get value of node - */ xmlChar *text = xmlTextReaderValue(m_reader); - if (NULL == text) { - LogError("Error in reading value"); - Throw(Exception::ErrorReadingValue); - } - value = reinterpret_cast<const char*>(text); - /* - * free text and return the val - */ + if (!text) + VcoreThrowMsg(SaxReader::Exception::ReadingValueError, + "reading value error"); + + std::string value = reinterpret_cast<const char*>(text); xmlFree(text); + return value; } @@ -278,31 +242,20 @@ SaxReader::NodeType SaxReader::type() void SaxReader::dumpNode(std::string &buffer) { - /* - * size of buffer - */ - int size; - /* - * pointer to buffer - */ xmlBufferPtr buff = xmlBufferCreate(); xmlNodePtr node = xmlTextReaderExpand(m_reader); - - if (node == NULL) { - /* - * internal parser error - */ + if (!node) { xmlBufferFree(buff); - LogError("Parser Internal Error"); - Throw(Exception::ParserInternalError); + VcoreThrowMsg(SaxReader::Exception::ParserInternalError, + "xmlTextReaderExpand error"); } - /* - * get a size and fill in a buffer - */ - size = xmlNodeDump(buff, node->doc, node, 0, 0); - buffer.insert(0, reinterpret_cast<char*>(buff->content), size); + int size = xmlNodeDump(buff, node->doc, node, 0, 0); + if (size > 0) { + buffer.insert(0, reinterpret_cast<char*>(buff->content), size); + } xmlBufferFree(buff); } + } // namespace ValidationCore diff --git a/vcore/src/vcore/SaxReader.h b/vcore/src/vcore/SaxReader.h index 3fd4efc..000ce1c 100644 --- a/vcore/src/vcore/SaxReader.h +++ b/vcore/src/vcore/SaxReader.h @@ -26,31 +26,25 @@ #include <string> #include <libxml/xmlreader.h> -#include <dpl/exception.h> + +#include <vcore/exception.h> namespace ValidationCore { -class SaxReader -{ - public: +class SaxReader { +public: SaxReader(); ~SaxReader(); - /* - * custom exceptions - */ - class Exception - { - public: - DECLARE_EXCEPTION_TYPE(DPL::Exception, Base) - DECLARE_EXCEPTION_TYPE(Base, FileOpeningError) - DECLARE_EXCEPTION_TYPE(Base, FileNotValid) - DECLARE_EXCEPTION_TYPE(Base, ParserInternalError) - DECLARE_EXCEPTION_TYPE(Base, WrongToken) - DECLARE_EXCEPTION_TYPE(Base, ParserInternalErrorInReadingAttribute) - DECLARE_EXCEPTION_TYPE(Base, ParserInternalErrorInEmptyQuery) - DECLARE_EXCEPTION_TYPE(Base, ErrorReadingValue) - DECLARE_EXCEPTION_TYPE(Base, ErrorReadingName) - DECLARE_EXCEPTION_TYPE(Base, UnsupportedType) + class Exception { + public: + VCORE_DECLARE_EXCEPTION_TYPE(ValidationCore::Exception, Base); + VCORE_DECLARE_EXCEPTION_TYPE(Base, FileOpeningError); + VCORE_DECLARE_EXCEPTION_TYPE(Base, FileNotValid); + VCORE_DECLARE_EXCEPTION_TYPE(Base, ParserInternalError); + VCORE_DECLARE_EXCEPTION_TYPE(Base, WrongToken); + VCORE_DECLARE_EXCEPTION_TYPE(Base, ReadingValueError); + VCORE_DECLARE_EXCEPTION_TYPE(Base, ReadingNameError); + VCORE_DECLARE_EXCEPTION_TYPE(Base, UnsupportedType); }; enum NodeType @@ -80,7 +74,8 @@ class SaxReader /* * initializes parser */ - void initialize(const std::string &filename, + void initialize( + const std::string &filename, bool defaultArgs = false, ValidationType validation = VALIDATION_DISABLE, const std::string &schema = std::string()); @@ -95,8 +90,8 @@ class SaxReader bool next(); /** - * Move to next xml node. If next node name is differ from token the exception will - * be thrown. + * Move to next xml node. If next node name is differ from token the exception wiil + * be thronw. */ void next(const std::string &token); @@ -108,13 +103,7 @@ class SaxReader /** * Read attribute tag. */ - std::string attribute(const std::string &token, - ThrowType throwStatus = THROW_ENABLE); - - /** - * Read xml tag name with namespace. - */ - // KW std::string fullName(); + std::string attribute(const std::string &token, ThrowType throwStatus = THROW_ENABLE); /** * Read xml tag name without namespace. @@ -142,7 +131,7 @@ class SaxReader */ void dumpNode(std::string &buffer); - private: +private: /* * internal libxml text reader */ diff --git a/vcore/src/vcore/SignatureData.cpp b/vcore/src/vcore/SignatureData.cpp new file mode 100644 index 0000000..a8a84fa --- /dev/null +++ b/vcore/src/vcore/SignatureData.cpp @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file SignatureData.cpp + * @author Bartlomiej Grzelewski (b.grzelewski@samsung.com) + * @version 1.0 + * @brief SignatureData is used to storage data parsed from digsig file. + */ +#include <vcore/SignatureData.h> + +#include <dpl/log/log.h> + +namespace ValidationCore { + +SignatureData::SignatureData() + : m_signatureNumber(-1) + , m_certificateSorted(false) +{} + +SignatureData::SignatureData(const std::string &fileName, int fileNumber) + : m_signatureNumber(fileNumber) + , m_fileName(fileName) + , m_certificateSorted(false) +{} + +SignatureData::~SignatureData() +{} + +const ReferenceSet& SignatureData::getReferenceSet() const +{ + return m_referenceSet; +} + +void SignatureData::setReference(const ReferenceSet &referenceSet) +{ + m_referenceSet = referenceSet; +} + +CertificateList SignatureData::getCertList() const +{ + return m_certList; +} + +void SignatureData::setSortedCertificateList(const CertificateList &list) +{ + m_certList = list; + m_certificateSorted = true; +} + +bool SignatureData::isAuthorSignature() const +{ + return m_signatureNumber == -1; +} + +std::string SignatureData::getSignatureFileName() const +{ + return m_fileName; +} + +int SignatureData::getSignatureNumber() const +{ + return m_signatureNumber; +} + +std::string SignatureData::getRoleURI() const +{ + return m_roleURI; +} + +std::string SignatureData::getProfileURI() const +{ + return m_profileURI; +} + +bool SignatureData::containObjectReference(const std::string &ref) const +{ + std::string rName = "#"; + rName += ref; + return m_referenceSet.end() != m_referenceSet.find(rName); +} + +ObjectList SignatureData::getObjectList() const +{ + return m_objectList; +} + +void SignatureData::setStorageType(const CertStoreId::Set &storeIdSet) +{ + m_storeIdSet = storeIdSet; +} + +const CertStoreId::Set& SignatureData::getStorageType() const +{ + return m_storeIdSet; +} + +CertStoreId::Type SignatureData::getVisibilityLevel() const +{ + if (m_storeIdSet.contains(CertStoreId::VIS_PLATFORM)) + return CertStoreId::VIS_PLATFORM; + else if (m_storeIdSet.contains(CertStoreId::VIS_PARTNER_MANUFACTURER)) + return CertStoreId::VIS_PLATFORM; + else if (m_storeIdSet.contains(CertStoreId::VIS_PARTNER_OPERATOR)) + return CertStoreId::VIS_PLATFORM; + else if (m_storeIdSet.contains(CertStoreId::VIS_PARTNER)) + return CertStoreId::VIS_PARTNER; + else if (m_storeIdSet.contains(CertStoreId::VIS_PUBLIC)) + return CertStoreId::VIS_PUBLIC; + else { + LogWarning("Visibility level was broken."); + return 0; + } +} + +const SignatureData::IMEIList& SignatureData::getIMEIList() const +{ + return m_imeiList; +} + +const SignatureData::MEIDList& SignatureData::getMEIDList() const +{ + return m_meidList; +} + +CertificatePtr SignatureData::getEndEntityCertificatePtr() const +{ + if (m_certificateSorted) + return m_certList.front(); + + return CertificatePtr(); +} + +CertificatePtr SignatureData::getRootCaCertificatePtr() const +{ + if (m_certificateSorted) + return m_certList.back(); + + return CertificatePtr(); +} + +} // ValidationCore diff --git a/vcore/src/vcore/SignatureData.h b/vcore/src/vcore/SignatureData.h index 5afba19..64310e3 100644 --- a/vcore/src/vcore/SignatureData.h +++ b/vcore/src/vcore/SignatureData.h @@ -14,7 +14,7 @@ * limitations under the License. */ /* - * @file SignatureData.cpp + * @file SignatureData.h * @author Bartlomiej Grzelewski (b.grzelewski@samsung.com) * @version 1.0 * @brief SignatureData is used to storage data parsed from digsig file. @@ -26,10 +26,6 @@ #include <set> #include <string> -#include <dpl/log/log.h> -#include <dpl/noncopyable.h> -#include <dpl/string.h> - #include <vcore/Certificate.h> #include <vcore/CertStoreType.h> @@ -38,143 +34,39 @@ namespace ValidationCore { typedef std::set<std::string> ReferenceSet; typedef std::list<std::string> ObjectList; -class SignatureData -{ - public: - - SignatureData() : - m_signatureNumber(-1), - m_certificateSorted(false) - { - } - - SignatureData(std::string fileName, int fileNumber) - : m_signatureNumber(fileNumber) - , m_fileName(fileName) - , m_certificateSorted(false) - {} +class SignatureData { +public: + SignatureData(); + SignatureData(const std::string &fileName, int fileNumber); - virtual ~SignatureData() - {} + virtual ~SignatureData(); typedef std::list<std::string> IMEIList; typedef std::list<std::string> MEIDList; - const ReferenceSet& getReferenceSet() const - { - return m_referenceSet; - } - - void setReference(const ReferenceSet &referenceSet) - { - m_referenceSet = referenceSet; - } - - CertificateList getCertList(void) const - { - return m_certList; - } - - void setSortedCertificateList(const CertificateList &list) - { - m_certList = list; - m_certificateSorted = true; - } - - bool isAuthorSignature(void) const - { - return m_signatureNumber == -1; - } - - std::string getSignatureFileName(void) const - { - return m_fileName; - } - - int getSignatureNumber() const - { - return m_signatureNumber; - } - - std::string getRoleURI() const - { - return m_roleURI; - } - - std::string getProfileURI() const - { - return m_profileURI; - } - - bool containObjectReference(const std::string &ref) const - { - std::string rName = "#"; - rName += ref; - return m_referenceSet.end() != m_referenceSet.find(rName); - } - - ObjectList getObjectList() const - { - return m_objectList; - } - - void setStorageType(const CertStoreId::Set &storeIdSet) - { - m_storeIdSet = storeIdSet; - } - - const CertStoreId::Set& getStorageType(void) const - { - return m_storeIdSet; - } - - const CertStoreId::Type getVisibilityLevel(void) const - { - if (m_storeIdSet.contains(CertStoreId::VIS_PLATFORM) == true) - return CertStoreId::VIS_PLATFORM; - else if (m_storeIdSet.contains(CertStoreId::VIS_PARTNER_MANUFACTURER) == true) - return CertStoreId::VIS_PLATFORM; - else if (m_storeIdSet.contains(CertStoreId::VIS_PARTNER_OPERATOR) == true) - return CertStoreId::VIS_PLATFORM; - else if (m_storeIdSet.contains(CertStoreId::VIS_PARTNER) == true) - return CertStoreId::VIS_PARTNER; - else if (m_storeIdSet.contains(CertStoreId::VIS_PUBLIC) == true) - return CertStoreId::VIS_PUBLIC; - else { - LogWarning("Visibility level was broken."); - return 0; - } - } - - const IMEIList& getIMEIList() const - { - return m_imeiList; - } - - const MEIDList& getMEIDList() const - { - return m_meidList; - } - - CertificatePtr getEndEntityCertificatePtr() const - { - if (m_certificateSorted) { - return m_certList.front(); - } - return CertificatePtr(); - } - - CertificatePtr getRootCaCertificatePtr() const - { - if (m_certificateSorted) { - return m_certList.back(); - } - return CertificatePtr(); - } + void setReference(const ReferenceSet &referenceSet); + void setSortedCertificateList(const CertificateList &list); + void setStorageType(const CertStoreId::Set &storeIdSet); + + const ReferenceSet& getReferenceSet() const; + CertificateList getCertList() const; + ObjectList getObjectList() const; + bool containObjectReference(const std::string &ref) const; + bool isAuthorSignature() const; + int getSignatureNumber() const; + std::string getSignatureFileName() const; + std::string getRoleURI() const; + std::string getProfileURI() const; + const CertStoreId::Set& getStorageType() const; + CertStoreId::Type getVisibilityLevel() const; + const IMEIList& getIMEIList() const; + const MEIDList& getMEIDList() const; + CertificatePtr getEndEntityCertificatePtr() const; + CertificatePtr getRootCaCertificatePtr() const; friend class SignatureReader; - private: +private: ReferenceSet m_referenceSet; CertificateList m_certList; diff --git a/vcore/src/vcore/SignatureFinder.cpp b/vcore/src/vcore/SignatureFinder.cpp index cc0a408..0c864b7 100644 --- a/vcore/src/vcore/SignatureFinder.cpp +++ b/vcore/src/vcore/SignatureFinder.cpp @@ -20,14 +20,15 @@ * @brief Search for author-signature.xml and signatureN.xml files. */ #include <vcore/SignatureFinder.h> +#include <dpl/log/wrt_log.h> #include <dirent.h> #include <errno.h> #include <istream> +#include <sstream> #include <pcrecpp.h> -#include <dpl/log/log.h> namespace ValidationCore { static const char *SIGNATURE_AUTHOR = "author-signature.xml"; @@ -35,7 +36,7 @@ static const char *REGEXP_DISTRIBUTOR_SIGNATURE = "^(signature)([1-9][0-9]*)(\\.xml)"; class SignatureFinder::Impl { - public: +public: Impl(const std::string& dir) : m_dir(dir) , m_signatureRegexp(REGEXP_DISTRIBUTOR_SIGNATURE) @@ -45,7 +46,7 @@ class SignatureFinder::Impl { Result find(SignatureFileInfoSet &set); - private: +private: std::string m_dir; pcrecpp::RE m_signatureRegexp; }; @@ -59,7 +60,7 @@ SignatureFinder::Result SignatureFinder::Impl::find(SignatureFileInfoSet &set) * find a dir */ if ((dp = opendir(m_dir.c_str())) == NULL) { - LogError("Error opening directory:" << m_dir); + WrtLogE("Error opening directory: %s", m_dir.c_str()); return ERROR_OPENING_DIR; } @@ -88,7 +89,7 @@ SignatureFinder::Result SignatureFinder::Impl::find(SignatureFileInfoSet &set) } if (errno != 0) { - LogError("Error in readdir"); + WrtLogE("Error in readdir"); closedir(dp); return ERROR_READING_DIR; } @@ -101,7 +102,8 @@ SignatureFinder::SignatureFinder(const std::string& dir) : m_impl(new Impl(dir)) {} -SignatureFinder::~SignatureFinder(){ +SignatureFinder::~SignatureFinder() +{ delete m_impl; } diff --git a/vcore/src/vcore/SignatureFinder.h b/vcore/src/vcore/SignatureFinder.h index c1545cc..4809096 100644 --- a/vcore/src/vcore/SignatureFinder.h +++ b/vcore/src/vcore/SignatureFinder.h @@ -27,12 +27,10 @@ #include <set> #include <string> -#include <dpl/noncopyable.h> - namespace ValidationCore { -class SignatureFileInfo -{ - public: + +class SignatureFileInfo { +public: SignatureFileInfo(const std::string &fileName, int num) : m_fileName(fileName) , m_fileNumber(num) @@ -52,15 +50,16 @@ class SignatureFileInfo { return m_fileNumber < second.m_fileNumber; } - private: + +private: std::string m_fileName; int m_fileNumber; }; typedef std::set<SignatureFileInfo> SignatureFileInfoSet; -class SignatureFinder : DPL::Noncopyable { - public: +class SignatureFinder { +public: enum Result { NO_ERROR, @@ -69,15 +68,19 @@ class SignatureFinder : DPL::Noncopyable { ERROR_ISTREAM }; - SignatureFinder(const std::string& dir); + SignatureFinder() = delete; + explicit SignatureFinder(const std::string& dir); virtual ~SignatureFinder(); Result find(SignatureFileInfoSet &set); - private: +private: class Impl; Impl *m_impl; + + SignatureFinder(const SignatureFinder &); + const SignatureFinder &operator=(const SignatureFinder &); }; } // namespace ValidationCore diff --git a/vcore/src/vcore/SignatureReader.cpp b/vcore/src/vcore/SignatureReader.cpp index 80553b6..229c93d 100644 --- a/vcore/src/vcore/SignatureReader.cpp +++ b/vcore/src/vcore/SignatureReader.cpp @@ -162,11 +162,9 @@ SignatureReader::SignatureReader() : m_parserSchema.addBeginTagCallback(TOKEN_OBJECT, XML_NAMESPACE, &SignatureReader::tokenObject); - m_parserSchema.addBeginTagCallback( - TOKEN_SIGNATURE_PROPERTIES, - XML_NAMESPACE, - &SignatureReader:: - tokenSignatureProperties); + m_parserSchema.addBeginTagCallback(TOKEN_SIGNATURE_PROPERTIES, + XML_NAMESPACE, + &SignatureReader::tokenSignatureProperties); m_parserSchema.addBeginTagCallback(TOKEN_SIGNATURE_PROPERTY, XML_NAMESPACE, &SignatureReader::blankFunction); @@ -306,11 +304,9 @@ SignatureReader::SignatureReader() : m_parserSchema.addEndTagCallback(TOKEN_DSA_SEED_COMPONENT, XML_NAMESPACE, &SignatureReader::tokenEndDSASeedComponent); - m_parserSchema.addEndTagCallback( - TOKEN_DSA_PGENCOUNTER_COMPONENT, - XML_NAMESPACE, - &SignatureReader:: - tokenEndDSAPGenCounterComponent); + m_parserSchema.addEndTagCallback(TOKEN_DSA_PGENCOUNTER_COMPONENT, + XML_NAMESPACE, + &SignatureReader::tokenEndDSAPGenCounterComponent); m_parserSchema.addEndTagCallback(TOKEN_RSA_KEY_VALUE, XML_NAMESPACE, &SignatureReader::tokenEndRSAKeyValue); @@ -325,46 +321,58 @@ SignatureReader::SignatureReader() : &SignatureReader::blankFunction); } -void SignatureReader::tokenKeyInfo(SignatureData &signatureData) + +void SignatureReader::initialize( + SignatureData &signatureData, + const std::string &xmlscheme) { - (void)signatureData; + m_parserSchema.initialize( + signatureData.getSignatureFileName(), + true, + SaxReader::VALIDATION_XMLSCHEME, + xmlscheme); } -void SignatureReader::tokenX509Data(SignatureData &signatureData) + +void SignatureReader::read(SignatureData &signatureData) { - (void)signatureData; + m_parserSchema.read(signatureData); } -void SignatureReader::tokenX509Certificate(SignatureData &signatureData) + +void SignatureReader::blankFunction(SignatureData &) { - (void)signatureData; } -void SignatureReader::tokenPublicKey(SignatureData &signatureData) + +void SignatureReader::tokenKeyInfo(SignatureData &) +{ +} + +void SignatureReader::tokenX509Data(SignatureData &) { - (void)signatureData; } -void SignatureReader::tokenNamedCurve(SignatureData &signatureData) +void SignatureReader::tokenX509Certificate(SignatureData &) +{ +} + +void SignatureReader::tokenPublicKey(SignatureData &) +{ +} + +void SignatureReader::tokenNamedCurve(SignatureData &) { - (void)signatureData; m_nameCurveURI = m_parserSchema.getReader().attribute(TOKEN_URI); } void SignatureReader::tokenTargetRestriction(SignatureData &signatureData) { - std::string IMEI = m_parserSchema.getReader().attribute( - TOKEN_IMEI, - SaxReader:: - THROW_DISABLE); - std::string MEID = m_parserSchema.getReader().attribute( - TOKEN_MEID, - SaxReader:: - THROW_DISABLE); + std::string IMEI = m_parserSchema.getReader().attribute(TOKEN_IMEI); + std::string MEID = m_parserSchema.getReader().attribute(TOKEN_MEID); //less verbose way to say (IMEI && MEID) || (!IMEI && !MEID) if (IMEI.empty() == MEID.empty()) { //WAC 2.0 WR-4650 point 4 - ThrowMsg(Exception::TargetRestrictionException, - "TargetRestriction should contain exactly one attribute."); - return; + VcoreThrowMsg(SignatureReader::Exception::TargetRestriction, + "TargetRestriction should contain exactly one attribute."); } if (!IMEI.empty()) { @@ -375,14 +383,12 @@ void SignatureReader::tokenTargetRestriction(SignatureData &signatureData) } } -void SignatureReader::tokenEndKeyInfo(SignatureData &signatureData) +void SignatureReader::tokenEndKeyInfo(SignatureData &) { - (void)signatureData; } -void SignatureReader::tokenEndX509Data(SignatureData &signatureData) +void SignatureReader::tokenEndX509Data(SignatureData &) { - (void)signatureData; } void SignatureReader::tokenEndX509Certificate(SignatureData &signatureData) @@ -391,20 +397,11 @@ void SignatureReader::tokenEndX509Certificate(SignatureData &signatureData) if (CertificateLoader::NO_ERROR != loader.loadCertificateFromRawData(m_parserSchema.getText())) { fprintf(stderr, "## [validate error]: Certificate could not be loaded\n"); - LogWarning("Certificate could not be loaded!"); - ThrowMsg(ParserSchemaException::CertificateLoaderError, - "Certificate could not be loaded."); + VcoreThrowMsg(ParserSchemaException::CertificateLoaderError, + "Certificate could not be loaded"); } signatureData.m_certList.push_back(loader.getCertificatePtr()); } -// KW void SignatureReader::tokenEndKeyName(SignatureData &signatureData){ -// KW CertificateLoader loader; -// KW if(CertificateLoader::NO_ERROR != loader.loadCertificateBasedOnSubjectName(m_parserSchema.getText())){ -// KW LogError("Certificate could not be loaded!"); -// KW ThrowMsg(ParserSchemaException::CertificateLoaderError, "Certificate could not be loaded."); -// KW } -// KW signatureData.m_certList.push_back(loader); -// KW } void SignatureReader::tokenEndRSAKeyValue(SignatureData &signatureData) { @@ -413,28 +410,24 @@ void SignatureReader::tokenEndRSAKeyValue(SignatureData &signatureData) loader.loadCertificateBasedOnExponentAndModulus(m_modulus, m_exponent)) { fprintf(stderr, "## [validate error]: Certificate could not be loaded\n"); - LogWarning("Certificate could not be loaded!"); - ThrowMsg(ParserSchemaException::CertificateLoaderError, - "Certificate could not be loaded."); + VcoreThrowMsg(ParserSchemaException::CertificateLoaderError, + "Certificate could not be loaded"); } signatureData.m_certList.push_back(loader.getCertificatePtr()); } -void SignatureReader::tokenEndKeyModulus(SignatureData &signatureData) +void SignatureReader::tokenEndKeyModulus(SignatureData &) { - (void)signatureData; m_modulus = m_parserSchema.getText(); } -void SignatureReader::tokenEndKeyExponent(SignatureData &signatureData) +void SignatureReader::tokenEndKeyExponent(SignatureData &) { - (void)signatureData; m_exponent = m_parserSchema.getText(); } -void SignatureReader::tokenEndPublicKey(SignatureData &signatureData) +void SignatureReader::tokenEndPublicKey(SignatureData &) { - (void)signatureData; m_publicKey = m_parserSchema.getText(); } @@ -444,8 +437,8 @@ void SignatureReader::tokenEndECKeyValue(SignatureData &signatureData) if (CertificateLoader::NO_ERROR != loader.loadCertificateWithECKEY(m_nameCurveURI, m_publicKey)) { fprintf(stderr, "## [validate error]: Certificate could not be loaded\n"); - ThrowMsg(ParserSchemaException::CertificateLoaderError, - "Certificate could not be loaded."); + VcoreThrowMsg(ParserSchemaException::CertificateLoaderError, + "Certificate could not be loaded"); } signatureData.m_certList.push_back(loader.getCertificatePtr()); } @@ -458,60 +451,53 @@ void SignatureReader::tokenEndObject(SignatureData &signatureData) (!signatureData.m_meidList.empty())) && m_targetRestrictionObjectFound) { //WAC 2.0 WR-4650 point 1 - ThrowMsg( - Exception::TargetRestrictionException, - "TargetRestriction should contain exactly one ds:Object containing zero or more wac:TargetRestriction children."); - return; + VcoreThrowMsg(SignatureReader::Exception::TargetRestriction, + "TargetRestriction should contain exactly one ds:Object " + "containing zero or more wac:TargetRestriction children."); } + if ((!signatureData.m_imeiList.empty()) || (!signatureData.m_meidList.empty())) { m_targetRestrictionObjectFound = true; } + } -void SignatureReader::tokenEndDSAPComponent(SignatureData& signatureData) +void SignatureReader::tokenEndDSAPComponent(SignatureData &) { - (void)signatureData; m_dsaKeyPComponent = m_parserSchema.getText(); } -void SignatureReader::tokenEndDSAQComponent(SignatureData& signatureData) +void SignatureReader::tokenEndDSAQComponent(SignatureData &) { - (void)signatureData; m_dsaKeyQComponent = m_parserSchema.getText(); } -void SignatureReader::tokenEndDSAGComponent(SignatureData& signatureData) +void SignatureReader::tokenEndDSAGComponent(SignatureData &) { - (void)signatureData; m_dsaKeyGComponent = m_parserSchema.getText(); } -void SignatureReader::tokenEndDSAYComponent(SignatureData& signatureData) +void SignatureReader::tokenEndDSAYComponent(SignatureData &) { - (void)signatureData; m_dsaKeyYComponent = m_parserSchema.getText(); } -void SignatureReader::tokenEndDSAJComponent(SignatureData& signatureData) +void SignatureReader::tokenEndDSAJComponent(SignatureData &) { - (void)signatureData; m_dsaKeyJComponent = m_parserSchema.getText(); } -void SignatureReader::tokenEndDSASeedComponent(SignatureData& signatureData) +void SignatureReader::tokenEndDSASeedComponent(SignatureData &) { - (void)signatureData; m_dsaKeySeedComponent = m_parserSchema.getText(); } -void SignatureReader::tokenEndDSAPGenCounterComponent( - SignatureData& signatureData) +void SignatureReader::tokenEndDSAPGenCounterComponent(SignatureData &) { - (void)signatureData; m_dsaKeyPGenCounter = m_parserSchema.getText(); } -void SignatureReader::tokenEndDSAKeyValue(SignatureData& signatureData) +void SignatureReader::tokenEndDSAKeyValue(SignatureData &signatureData) { CertificateLoader loader; @@ -524,9 +510,8 @@ void SignatureReader::tokenEndDSAKeyValue(SignatureData& signatureData) m_dsaKeySeedComponent, m_dsaKeyPGenCounter)) { fprintf(stderr, "## [validate error]: Certificate could not be loaded\n"); - LogWarning("Certificate could not be loaded."); - ThrowMsg(ParserSchemaException::CertificateLoaderError, - "Certificate could not be loaded."); + VcoreThrowMsg(ParserSchemaException::CertificateLoaderError, + "Certificate could not be loaded."); } signatureData.m_certList.push_back(loader.getCertificatePtr()); } @@ -535,9 +520,8 @@ void SignatureReader::tokenRole(SignatureData &signatureData) { if (!signatureData.m_roleURI.empty()) { fprintf(stderr, "## [validate error]: Multiple definition of Role is not allowed\n"); - LogWarning("Multiple definition of Role is not allowed."); - ThrowMsg(ParserSchemaException::UnsupportedValue, - "Multiple definition of Role is not allowed."); + VcoreThrowMsg(ParserSchemaException::UnsupportedValue, + "Multiple definition of Role is not allowed."); } signatureData.m_roleURI = m_parserSchema.getReader().attribute(TOKEN_URI); } @@ -546,9 +530,8 @@ void SignatureReader::tokenProfile(SignatureData &signatureData) { if (!signatureData.m_profileURI.empty()) { fprintf(stderr, "## [validate error]: Multiple definition of Profile is not allowed\n"); - LogWarning("Multiple definition of Profile is not allowed."); - ThrowMsg(ParserSchemaException::UnsupportedValue, - "Multiple definition of Profile is not allowed."); + VcoreThrowMsg(ParserSchemaException::UnsupportedValue, + "Multiple definition of Profile is not allowed."); } signatureData.m_profileURI = m_parserSchema.getReader().attribute(TOKEN_URI); } @@ -557,9 +540,8 @@ void SignatureReader::tokenEndIdentifier(SignatureData &signatureData) { if (!signatureData.m_identifier.empty()) { fprintf(stderr, "## [validate error]: Multiple definition of Identifier is not allowed\n"); - LogWarning("Multiple definition of Identifier is not allowed."); - ThrowMsg(ParserSchemaException::UnsupportedValue, - "Multiple definition of Identifier is not allowed."); + VcoreThrowMsg(ParserSchemaException::UnsupportedValue, + "Multiple definition of Identifier is not allowed."); } signatureData.m_identifier = m_parserSchema.getText(); } @@ -570,22 +552,19 @@ void SignatureReader::tokenObject(SignatureData &signatureData) if (id.empty()) { fprintf(stderr, "## [validate error]: Unsupported value of Attribute Id in Object tag\n"); - LogWarning("Unsupported value of Attribute Id in Object tag."); - ThrowMsg(ParserSchemaException::UnsupportedValue, - "Unsupported value of Attribute Id in Object tag."); + VcoreThrowMsg(ParserSchemaException::UnsupportedValue, + "Unsupported value of Attribute Id in Object tag."); } signatureData.m_objectList.push_back(id); } -void SignatureReader::tokenSignatureProperties(SignatureData &signatureData) +void SignatureReader::tokenSignatureProperties(SignatureData &) { - (void)signatureData; if (++m_signaturePropertiesCounter > 1) { fprintf(stderr, "## [validate error]: Only one SignatureProperties tag is allowed in Object\n"); - LogWarning("Only one SignatureProperties tag is allowed in Object"); - ThrowMsg(ParserSchemaException::UnsupportedValue, - "Only one SignatureProperties tag is allowed in Object"); + VcoreThrowMsg(ParserSchemaException::UnsupportedValue, + "Only one SignatureProperties tag is allowed in Object"); } } } // namespace ValidationCore diff --git a/vcore/src/vcore/SignatureReader.h b/vcore/src/vcore/SignatureReader.h index 2f2f9a8..309a915 100644 --- a/vcore/src/vcore/SignatureReader.h +++ b/vcore/src/vcore/SignatureReader.h @@ -22,42 +22,30 @@ #ifndef _VALIDATION_CORE_SIGNATUREREADER_H_ #define _VALIDATION_CORE_SIGNATUREREADER_H_ -#include <map> -#include <dpl/log/log.h> - #include <vcore/SignatureData.h> #include <vcore/ParserSchema.h> +#include <vcore/exception.h> + +#include <map> namespace ValidationCore { -class SignatureReader -{ - public: - class Exception - { - public: - DECLARE_EXCEPTION_TYPE(DPL::Exception, Base) - DECLARE_EXCEPTION_TYPE(Base, TargetRestrictionException) + +class SignatureReader { +public: + class Exception { + public: + VCORE_DECLARE_EXCEPTION_TYPE(ValidationCore::Exception, Base); + VCORE_DECLARE_EXCEPTION_TYPE(Base, TargetRestriction); }; SignatureReader(); - void initialize(SignatureData &data, - const std::string &xmlscheme) - { - m_parserSchema.initialize( - data.getSignatureFileName(), true, SaxReader::VALIDATION_XMLSCHEME, - xmlscheme); - } + void initialize(SignatureData &signatureData, const std::string &xmlscheme); - void read(SignatureData &data) - { - m_parserSchema.read(data); - } + void read(SignatureData &signatureData); - private: - void blankFunction(SignatureData &) - { - } +private: + void blankFunction(SignatureData &signatureData); void tokenKeyInfo(SignatureData &signatureData); void tokenKeyModulus(SignatureData &signatureData); @@ -70,15 +58,20 @@ class SignatureReader void tokenProfile(SignatureData &signatureData); void tokenObject(SignatureData &signatureData); void tokenSignatureProperties(SignatureData &signatureData); + void tokenTargetRestriction(SignatureData &signatureData); void tokenEndKeyInfo(SignatureData &signatureData); // KW void tokenEndKeyName(SignatureData &signatureData); + void tokenEndRSAKeyValue(SignatureData &signatureData); + void tokenEndKeyModulus(SignatureData &signatureData); void tokenEndKeyExponent(SignatureData &signatureData); void tokenEndX509Data(SignatureData &signatureData); + void tokenEndX509Certificate(SignatureData &signatureData); + void tokenEndPublicKey(SignatureData &signatureData); void tokenEndECKeyValue(SignatureData &signatureData); void tokenEndIdentifier(SignatureData &signatureData); diff --git a/vcore/src/vcore/SignatureValidator.cpp b/vcore/src/vcore/SignatureValidator.cpp index 35ffaa3..2a51402 100644 --- a/vcore/src/vcore/SignatureValidator.cpp +++ b/vcore/src/vcore/SignatureValidator.cpp @@ -21,15 +21,16 @@ */ #include <vcore/SignatureValidator.h> #include <vcore/CertificateCollection.h> -#include <dpl/log/log.h> -#ifdef TIZEN_FEATURE_CERT_SVC_OCSP_CRL -#include <vcore/CertificateVerifier.h> -#endif #include <vcore/Certificate.h> #include <vcore/OCSPCertMgrUtil.h> #include <vcore/ReferenceValidator.h> #include <vcore/ValidatorFactories.h> #include <vcore/XmlsecAdapter.h> +#ifdef TIZEN_FEATURE_CERT_SVC_OCSP_CRL +#include <vcore/CertificateVerifier.h> +#endif + +#include <dpl/log/wrt_log.h> namespace { const time_t TIMET_DAY = 60 * 60 * 24; @@ -41,8 +42,6 @@ const std::string TOKEN_ROLE_DISTRIBUTOR_URI = const std::string TOKEN_PROFILE_URI = "http://www.w3.org/ns/widgets-digsig#profile"; -//const char* TIZEN_STORE_CN = "Tizen Store"; //un-used variable - } // namespace anonymouse @@ -56,20 +55,26 @@ static tm _ASN1_GetTimeT(ASN1_TIME* time) if (time->type == V_ASN1_UTCTIME) /* two digit year */ { - t.tm_year = (str[i++] - '0') * 10 + (str[++i] - '0'); + t.tm_year = (str[i] - '0') * 10 + (str[i+1] - '0'); + i += 2; if (t.tm_year < 70) t.tm_year += 100; } else if (time->type == V_ASN1_GENERALIZEDTIME) /* four digit year */ { - t.tm_year = (str[i++] - '0') * 1000 + (str[++i] - '0') * 100 + (str[++i] - '0') * 10 + (str[++i] - '0'); + t.tm_year = + (str[i] - '0') * 1000 + + (str[i+1] - '0') * 100 + + (str[i+2] - '0') * 10 + + (str[i+3] - '0'); + i += 4; t.tm_year -= 1900; } - t.tm_mon = ((str[i++] - '0') * 10 + (str[++i] - '0')) - 1; // -1 since January is 0 not 1. - t.tm_mday = (str[i++] - '0') * 10 + (str[++i] - '0'); - t.tm_hour = (str[i++] - '0') * 10 + (str[++i] - '0'); - t.tm_min = (str[i++] - '0') * 10 + (str[++i] - '0'); - t.tm_sec = (str[i++] - '0') * 10 + (str[++i] - '0'); + t.tm_mon = ((str[i] - '0') * 10 + (str[i+1] - '0')) - 1; // -1 since January is 0 not 1. + t.tm_mday = (str[i+2] - '0') * 10 + (str[i+3] - '0'); + t.tm_hour = (str[i+4] - '0') * 10 + (str[i+5] - '0'); + t.tm_min = (str[i+6] - '0') * 10 + (str[i+7] - '0'); + t.tm_sec = (str[i+8] - '0') * 10 + (str[i+9] - '0'); /* Note: we did not adjust the time based on time zone information */ return t; @@ -93,11 +98,15 @@ public: bool crlEnable, bool complianceMode) : m_complianceModeEnabled(complianceMode) - #ifdef TIZEN_FEATURE_CERT_SVC_OCSP_CRL - , m_ocspEnable(ocspEnable) - , m_crlEnable(crlEnable) - #endif - {} + { +#ifdef TIZEN_FEATURE_CERT_SVC_OCSP_CRL + m_ocspEnable = ocspEnable; + m_crlEnable = crlEnable; +#else + (void) ocspEnable; + (void) crlEnable; +#endif + } virtual ~ImplSignatureValidator(){ } @@ -105,18 +114,18 @@ public: std::string roleURI = data.getRoleURI(); if (roleURI.empty()) { - LogWarning("URI attribute in Role tag couldn't be empty."); + WrtLogW("URI attribute in Role tag couldn't be empty."); return false; } if (roleURI != TOKEN_ROLE_AUTHOR_URI && data.isAuthorSignature()) { - LogWarning("URI attribute in Role tag does not " + WrtLogW("URI attribute in Role tag does not " "match with signature filename."); return false; } if (roleURI != TOKEN_ROLE_DISTRIBUTOR_URI && !data.isAuthorSignature()) { - LogWarning("URI attribute in Role tag does not " + WrtLogW("URI attribute in Role tag does not " "match with signature filename."); return false; } @@ -125,9 +134,8 @@ public: bool checkProfileURI(const SignatureData &data) { if (TOKEN_PROFILE_URI != data.getProfileURI()) { - LogWarning( - "Profile tag contains unsupported value in URI attribute(" << - data.getProfileURI() << ")."); + WrtLogW( + "Profile tag contains unsupported value in URI attribute( %s ).", (data.getProfileURI()).c_str()); return false; } return true; @@ -138,8 +146,7 @@ public: ObjectList::const_iterator iter; for (iter = objectList.begin(); iter != objectList.end(); ++iter) { if (!data.containObjectReference(*iter)) { - LogWarning("Signature does not contain reference for object " << - *iter); + WrtLogW("Signature does not contain reference for object %s", (*iter).c_str()); return false; } } @@ -177,7 +184,6 @@ SignatureValidator::Result ImplTizenSignatureValidator::check( { bool disregard = false; - DPL::Log::LogSystemSingleton::Instance().SetTag("OSP"); if (!checkRoleURI(data)) { return SignatureValidator::SIGNATURE_INVALID; } @@ -193,14 +199,14 @@ SignatureValidator::Result ImplTizenSignatureValidator::check( // First step - sort certificate if (!collection.sort()) { - LogWarning("Certificates do not form valid chain."); - return SignatureValidator::SIGNATURE_INVALID; + WrtLogW("Certificates do not form valid chain."); + return SignatureValidator::SIGNATURE_INVALID_CERT_CHAIN;//SIGNATURE_INVALID; } // Check for error if (collection.empty()) { - LogWarning("Certificate list in signature is empty."); - return SignatureValidator::SIGNATURE_INVALID; + WrtLogW("Certificate list in signature is empty."); + return SignatureValidator::SIGNATURE_INVALID_CERT_CHAIN;//SIGNATURE_INVALID; } CertificateList sortedCertificateList = collection.getChain(); @@ -215,50 +221,46 @@ SignatureValidator::Result ImplTizenSignatureValidator::check( // Is Root CA certificate trusted? CertStoreId::Set storeIdSet = createCertificateIdentifier().find(root); - LogDebug("Is root certificate from TIZEN_DEVELOPER domain: " - << storeIdSet.contains(CertStoreId::TIZEN_DEVELOPER)); - LogDebug("Is root certificate from TIZEN_TEST domain: " - << storeIdSet.contains(CertStoreId::TIZEN_TEST)); - LogDebug("Is root certificate from TIZEN_VERIFY domain: " - << storeIdSet.contains(CertStoreId::TIZEN_VERIFY)); - LogDebug("Is root certificate from TIZEN_PUBLIC domain: " - << storeIdSet.contains(CertStoreId::VIS_PUBLIC)); - LogDebug("Is root certificate from TIZEN_PARTNER domain: " - << storeIdSet.contains(CertStoreId::VIS_PARTNER)); - LogDebug("Is root certificate from TIZEN_PLATFORM domain: " - << storeIdSet.contains(CertStoreId::VIS_PLATFORM)); - - LogDebug("Visibility level is public : " - << storeIdSet.contains(CertStoreId::VIS_PUBLIC)); - LogDebug("Visibility level is partner : " - << storeIdSet.contains(CertStoreId::VIS_PARTNER)); - LogDebug("Visibility level is platform : " - << storeIdSet.contains(CertStoreId::VIS_PLATFORM)); + WrtLogD("Is root certificate from TIZEN_DEVELOPER domain: %d", storeIdSet.contains(CertStoreId::TIZEN_DEVELOPER)); + WrtLogD("Is root certificate from TIZEN_TEST domain: %d", storeIdSet.contains(CertStoreId::TIZEN_TEST)); + WrtLogD("Is root certificate from TIZEN_VERIFY domain: %d", storeIdSet.contains(CertStoreId::TIZEN_VERIFY)); + WrtLogD("Is root certificate from TIZEN_STORE domain: %d", storeIdSet.contains(CertStoreId::TIZEN_STORE)); + WrtLogD("Is root certificate from TIZEN_PUBLIC domain: %d", storeIdSet.contains(CertStoreId::VIS_PUBLIC)); + WrtLogD("Is root certificate from TIZEN_PARTNER domain: %d", storeIdSet.contains(CertStoreId::VIS_PARTNER)); + WrtLogD("Is root certificate from TIZEN_PLATFORM domain: %d", storeIdSet.contains(CertStoreId::VIS_PLATFORM)); - if (data.isAuthorSignature()) - { - if (!storeIdSet.contains(CertStoreId::TIZEN_DEVELOPER)) - { - LogWarning("author-signature.xml has got unrecognized Root CA " - "certificate. Signature will be disregarded."); - disregard = true; - } - LogDebug("Root CA for author signature is correct."); + WrtLogD("Visibility level is public : %d", storeIdSet.contains(CertStoreId::VIS_PUBLIC)); + WrtLogD("Visibility level is partner : %d", storeIdSet.contains(CertStoreId::VIS_PARTNER)); + WrtLogD("Visibility level is platform : %d", storeIdSet.contains(CertStoreId::VIS_PLATFORM)); + + if (data.isAuthorSignature()) + { + if (!storeIdSet.contains(CertStoreId::TIZEN_DEVELOPER)) + { + WrtLogW("author-signature.xml has got unrecognized Root CA " + "certificate. Signature will be disregarded."); + disregard = true; + } } else { -LogDebug("signaturefile name = " << data.getSignatureFileName().c_str()); - //Additional Check for certificate registration + WrtLogD("signaturefile name = %s", data.getSignatureFileName().c_str()); + if (storeIdSet.contains(CertStoreId::TIZEN_DEVELOPER)) + { + WrtLogE("distributor has author level siganture! Signature will be disregarded."); + return SignatureValidator::SIGNATURE_IN_DISTRIBUTOR_CASE_AUTHOR_CERT;//SIGNATURE_INVALID; + } + if (data.getSignatureNumber() == 1) { if (storeIdSet.contains(CertStoreId::VIS_PUBLIC) || storeIdSet.contains(CertStoreId::VIS_PARTNER) || storeIdSet.contains(CertStoreId::VIS_PLATFORM)) { - LogDebug("Root CA for signature1.xml is correct."); + WrtLogD("Root CA for signature1.xml is correct."); } else { - LogWarning("signature1.xml has got unrecognized Root CA " + WrtLogW("signature1.xml has got unrecognized Root CA " "certificate. Signature will be disregarded."); disregard = true; } @@ -278,7 +280,7 @@ LogDebug("signaturefile name = " << data.getSignatureFileName().c_str()); // If the end certificate is not ROOT CA we should disregard signature // but still signature must be valid... Aaaaaa it's so stupid... if (!(root->isSignedBy(root))) { - LogWarning("Root CA certificate not found. Chain is incomplete."); + WrtLogW("Root CA certificate not found. Chain is incomplete."); // context.allowBrokenChain = true; } @@ -297,44 +299,46 @@ LogDebug("signaturefile name = " << data.getSignatureFileName().c_str()); char msg[1024]; t = localtime(&nowTime); + if (!t) + return SignatureValidator::SIGNATURE_INVALID_CERT_TIME; memset(&tc, 0, sizeof(tc)); snprintf(msg, sizeof(msg), "Year: %d, month: %d, day : %d", t->tm_year + 1900, t->tm_mon + 1,t->tm_mday ); - LogDebug("## System's currentTime : " << msg); + WrtLogD("## System's currentTime : %s", msg); fprintf(stderr, "## System's currentTime : %s\n", msg); tb = _ASN1_GetTimeT(notBeforeTime); snprintf(msg, sizeof(msg), "Year: %d, month: %d, day : %d", tb.tm_year + 1900, tb.tm_mon + 1,tb.tm_mday ); - LogDebug("## certificate's notBeforeTime : " << msg); + WrtLogD("## certificate's notBeforeTime : %s", msg); fprintf(stderr, "## certificate's notBeforeTime : %s\n", msg); ta = _ASN1_GetTimeT(notAfterTime); snprintf(msg, sizeof(msg), "Year: %d, month: %d, day : %d", ta.tm_year + 1900, ta.tm_mon + 1,ta.tm_mday ); - LogDebug("## certificate's notAfterTime : " << msg); + WrtLogD("## certificate's notAfterTime : %s", msg); fprintf(stderr, "## certificate's notAfterTime : %s\n", msg); - if (storeIdSet.contains(CertStoreId::TIZEN_VERIFY)) + if (storeIdSet.contains(CertStoreId::TIZEN_TEST) || storeIdSet.contains(CertStoreId::TIZEN_VERIFY)) { - LogDebug("## TIZEN_VERIFY : check certificate Time : FALSE"); + WrtLogD("## TIZEN_VERIFY : check certificate Time : FALSE"); fprintf(stderr, "## TIZEN_VERIFY : check certificate Time : FALSE\n"); - return SignatureValidator::SIGNATURE_INVALID; + return SignatureValidator::SIGNATURE_INVALID_CERT_TIME;//SIGNATURE_INVALID; } int year = (ta.tm_year - tb.tm_year) / 4; if(year == 0) { - tc.tm_year = tb.tm_year; + tc.tm_year = tb.tm_year; tc.tm_mon = tb.tm_mon + 1; tc.tm_mday = tb.tm_mday; if(tc.tm_mon == 12) { - tc.tm_year = ta.tm_year; + tc.tm_year = ta.tm_year; tc.tm_mon = ta.tm_mon - 1; tc.tm_mday = ta.tm_mday; - + if(tc.tm_mon < 0) { tc.tm_year = ta.tm_year; @@ -343,21 +347,21 @@ LogDebug("signaturefile name = " << data.getSignatureFileName().c_str()); if(tc.tm_mday == 0) { - tc.tm_year = tb.tm_year; + tc.tm_year = tb.tm_year; tc.tm_mon = tb.tm_mon; tc.tm_mday = tb.tm_mday +1; } } - } + } } else{ tc.tm_year = tb.tm_year + year; tc.tm_mon = (tb.tm_mon + ta.tm_mon )/2; - tc.tm_mday = (tb.tm_mday + ta.tm_mday)/2; + tc.tm_mday = (tb.tm_mday + ta.tm_mday)/2; } snprintf(msg, sizeof(msg), "Year: %d, month: %d, day : %d", tc.tm_year + 1900, tc.tm_mon + 1,tc.tm_mday ); - LogDebug("## cmp cert with validation time : " << msg); + WrtLogD("## cmp cert with validation time : %s", msg); fprintf(stderr, "## cmp cert with validation time : %s\n", msg); time_t outCurrent = mktime(&tc); @@ -376,36 +380,36 @@ LogDebug("signaturefile name = " << data.getSignatureFileName().c_str()); struct tm *t; if (data.isAuthorSignature()) - { + { // time_t 2038 year bug exist. So, notAtter() cann't check... /* if (notAfter < nowTime) { context.validationTime = notAfter - TIMET_DAY; - LogWarning("Author certificate is expired. notAfter..."); + WrtLogW("Author certificate is expired. notAfter..."); } */ if (notBefore > nowTime) { - LogWarning("Author certificate is expired. notBefore time is greater than system-time."); + WrtLogW("Author certificate is expired. notBefore time is greater than system-time."); t = localtime(&nowTime); - LogDebug("System's current Year : " << t->tm_year + 1900); - LogDebug("System's current month : " << t->tm_mon + 1); - LogDebug("System's current day : " << t->tm_mday); + WrtLogD("System's current Year : %d", (t->tm_year + 1900)); + WrtLogD("System's current month : %d", (t->tm_mon + 1)); + WrtLogD("System's current day : %d", (t->tm_mday)); t = localtime(¬Before); - LogDebug("Author certificate's notBefore Year : " << t->tm_year + 1900); - LogDebug("Author certificate's notBefore month : " << t->tm_mon + 1); - LogDebug("Author certificate's notBefore day : " << t->tm_mday); + WrtLogD("Author certificate's notBefore Year : %d", (t->tm_year + 1900)); + WrtLogD("Author certificate's notBefore month : %d", (t->tm_mon + 1)); + WrtLogD("Author certificate's notBefore day : %d", (t->tm_mday)); context.validationTime = notBefore + TIMET_DAY; t = localtime(&context.validationTime); - LogDebug("Modified current Year : " << t->tm_year + 1900); - LogDebug("Modified current notBefore month : " << t->tm_mon + 1); - LogDebug("Modified current notBefore day : " << t->tm_mday); + WrtLogD("Modified current Year : %d", (t->tm_year + 1900)); + WrtLogD("Modified current notBefore month : %d", (t->tm_mon + 1)); + WrtLogD("Modified current notBefore day : %d", (t->tm_mday)); } } #endif @@ -414,23 +418,28 @@ LogDebug("signaturefile name = " << data.getSignatureFileName().c_str()); // end - if (XmlSec::NO_ERROR != XmlSecSingleton::Instance().validate(&context)) { - LogWarning("Installation break - invalid package! >> validate"); - return SignatureValidator::SIGNATURE_INVALID; - } - - data.setReference(context.referenceSet); - if (!checkObjectReferences(data)) { - return SignatureValidator::SIGNATURE_INVALID; - } - + if (!data.isAuthorSignature()) + { + if (XmlSec::NO_ERROR != XmlSecSingleton::Instance().validate(&context)) { + WrtLogW("Installation break - invalid package!"); + return SignatureValidator::SIGNATURE_INVALID_HASH_SIGNATURE;//SIGNATURE_INVALID; + } + + data.setReference(context.referenceSet); + if (!checkObjectReferences(data)) { + WrtLogW("Failed to check Object References"); + return SignatureValidator::SIGNATURE_INVALID_HASH_SIGNATURE;//SIGNATURE_INVALID; + } + + (void) widgetContentPath; /* ReferenceValidator fileValidator(widgetContentPath); if (ReferenceValidator::NO_ERROR != fileValidator.checkReferences(data)) { - LogWarning("Invalid package - file references broken"); - return SignatureValidator::SIGNATURE_INVALID; + WrtLogW("Invalid package - file references broken"); + return SignatureValidator::SIGNATURE_INVALID_NO_HASH_FILE;//SIGNATURE_INVALID; } */ + } #ifdef TIZEN_FEATURE_CERT_SVC_OCSP_CRL // It is good time to do OCSP check @@ -442,8 +451,8 @@ LogDebug("signaturefile name = " << data.getSignatureFileName().c_str()); coll.load(sortedCertificateList); if (!coll.sort()) { - LogDebug("Collection does not contain chain!"); - return SignatureValidator::SIGNATURE_INVALID; + WrtLogD("Collection does not contain chain!"); + return SignatureValidator::SIGNATURE_INVALID_CERT_CHAIN;//SIGNATURE_INVALID; } CertificateVerifier verificator(m_ocspEnable, m_crlEnable); @@ -464,8 +473,8 @@ LogDebug("signaturefile name = " << data.getSignatureFileName().c_str()); #endif if (disregard) { - LogWarning("Signature is disregard. RootCA is not a member of Tizen."); - return SignatureValidator::SIGNATURE_DISREGARD; + WrtLogW("Signature is disregard. RootCA is not a member of Tizen"); + return SignatureValidator::SIGNATURE_INVALID_DISTRIBUTOR_CERT;//SIGNATURE_DISREGARD; } return SignatureValidator::SIGNATURE_VERIFIED; } @@ -474,13 +483,11 @@ SignatureValidator::Result ImplTizenSignatureValidator::checkList(SignatureData const std::string &widgetContentPath, const std::list<std::string>& uriList) { - DPL::Log::LogSystemSingleton::Instance().SetTag("OSP"); if(uriList.size() == 0 ) - LogWarning("checkList >> no hash"); + WrtLogW("checkList >> no hash"); bool disregard = false; - bool partialHash = false; - + if (!checkRoleURI(data)) { return SignatureValidator::SIGNATURE_INVALID; } @@ -496,13 +503,13 @@ SignatureValidator::Result ImplTizenSignatureValidator::checkList(SignatureData // First step - sort certificate if (!collection.sort()) { - LogWarning("Certificates do not form valid chain."); + WrtLogW("Certificates do not form valid chain."); return SignatureValidator::SIGNATURE_INVALID; } // Check for error if (collection.empty()) { - LogWarning("Certificate list in signature is empty."); + WrtLogW("Certificate list in signature is empty."); return SignatureValidator::SIGNATURE_INVALID; } @@ -518,50 +525,40 @@ SignatureValidator::Result ImplTizenSignatureValidator::checkList(SignatureData // Is Root CA certificate trusted? CertStoreId::Set storeIdSet = createCertificateIdentifier().find(root); - LogDebug("Is root certificate from TIZEN_DEVELOPER domain: " - << storeIdSet.contains(CertStoreId::TIZEN_DEVELOPER)); - LogDebug("Is root certificate from TIZEN_TEST domain: " - << storeIdSet.contains(CertStoreId::TIZEN_TEST)); - LogDebug("Is root certificate from TIZEN_VERIFY domain: " - << storeIdSet.contains(CertStoreId::TIZEN_VERIFY)); - LogDebug("Is root certificate from TIZEN_PUBLIC domain: " - << storeIdSet.contains(CertStoreId::VIS_PUBLIC)); - LogDebug("Is root certificate from TIZEN_PARTNER domain: " - << storeIdSet.contains(CertStoreId::VIS_PARTNER)); - LogDebug("Is root certificate from TIZEN_PLATFORM domain: " - << storeIdSet.contains(CertStoreId::VIS_PLATFORM)); - - LogDebug("Visibility level is public : " - << storeIdSet.contains(CertStoreId::VIS_PUBLIC)); - LogDebug("Visibility level is partner : " - << storeIdSet.contains(CertStoreId::VIS_PARTNER)); - LogDebug("Visibility level is platform : " - << storeIdSet.contains(CertStoreId::VIS_PLATFORM)); + WrtLogD("Is root certificate from TIZEN_DEVELOPER domain: %d", storeIdSet.contains(CertStoreId::TIZEN_DEVELOPER)); + WrtLogD("Is root certificate from TIZEN_TEST domain: %d", storeIdSet.contains(CertStoreId::TIZEN_TEST)); + WrtLogD("Is root certificate from TIZEN_VERIFY domain: %d", storeIdSet.contains(CertStoreId::TIZEN_VERIFY)); + WrtLogD("Is root certificate from TIZEN_PUBLIC domain: %d", storeIdSet.contains(CertStoreId::VIS_PUBLIC)); + WrtLogD("Is root certificate from TIZEN_PARTNER domain: %d", storeIdSet.contains(CertStoreId::VIS_PARTNER)); + WrtLogD("Is root certificate from TIZEN_PLATFORM domain: %d", storeIdSet.contains(CertStoreId::VIS_PLATFORM)); + + WrtLogD("Visibility level is public : %d", storeIdSet.contains(CertStoreId::VIS_PUBLIC)); + WrtLogD("Visibility level is partner : %d", storeIdSet.contains(CertStoreId::VIS_PARTNER)); + WrtLogD("Visibility level is platform : %d", storeIdSet.contains(CertStoreId::VIS_PLATFORM)); if (data.isAuthorSignature()) { if (!storeIdSet.contains(CertStoreId::TIZEN_DEVELOPER)) { - LogWarning("author-signature.xml has got unrecognized Root CA " + WrtLogW("author-signature.xml has got unrecognized Root CA " "certificate. Signature will be disregarded."); disregard = true; } - LogDebug("Root CA for author signature is correct."); + WrtLogD("Root CA for author signature is correct."); } else { - LogDebug("signaturefile name = " << data.getSignatureFileName().c_str()); - //Additional Check for certificate registration + WrtLogD("signaturefile name = %s", data.getSignatureFileName().c_str()); if (data.getSignatureNumber() == 1) { if (storeIdSet.contains(CertStoreId::VIS_PUBLIC) || storeIdSet.contains(CertStoreId::VIS_PARTNER) || storeIdSet.contains(CertStoreId::VIS_PLATFORM)) { - LogDebug("Root CA for signature1.xml is correct."); + WrtLogD("Root CA for signature1.xml is correct."); } else { - LogWarning("signature1.xml has got unrecognized Root CA " + WrtLogW("signature1.xml has got unrecognized Root CA " "certificate. Signature will be disregarded."); disregard = true; } @@ -581,7 +578,7 @@ SignatureValidator::Result ImplTizenSignatureValidator::checkList(SignatureData // If the end certificate is not ROOT CA we should disregard signature // but still signature must be valid... Aaaaaa it's so stupid... if (!(root->isSignedBy(root))) { - LogWarning("Root CA certificate not found. Chain is incomplete."); + WrtLogW("Root CA certificate not found. Chain is incomplete."); // context.allowBrokenChain = true; } @@ -595,7 +592,7 @@ SignatureValidator::Result ImplTizenSignatureValidator::checkList(SignatureData ASN1_TIME* notAfterTime = data.getEndEntityCertificatePtr()->getNotAfterTime(); ASN1_TIME* notBeforeTime = data.getEndEntityCertificatePtr()->getNotBeforeTime(); - + if (X509_cmp_time(notBeforeTime, &nowTime) > 0 || X509_cmp_time(notAfterTime, &nowTime) < 0) { struct tm *t; @@ -603,26 +600,28 @@ SignatureValidator::Result ImplTizenSignatureValidator::checkList(SignatureData char msg[1024]; t = localtime(&nowTime); + if (!t) + return SignatureValidator::SIGNATURE_INVALID_CERT_TIME; memset(&tc, 0, sizeof(tc)); snprintf(msg, sizeof(msg), "Year: %d, month: %d, day : %d", t->tm_year + 1900, t->tm_mon + 1,t->tm_mday ); - LogDebug("## System's currentTime : " << msg); + WrtLogD("## System's currentTime : %s", msg); fprintf(stderr, "## System's currentTime : %s\n", msg); tb = _ASN1_GetTimeT(notBeforeTime); snprintf(msg, sizeof(msg), "Year: %d, month: %d, day : %d", tb.tm_year + 1900, tb.tm_mon + 1,tb.tm_mday ); - LogDebug("## certificate's notBeforeTime : " << msg); + WrtLogD("## certificate's notBeforeTime : %s", msg); fprintf(stderr, "## certificate's notBeforeTime : %s\n", msg); ta = _ASN1_GetTimeT(notAfterTime); snprintf(msg, sizeof(msg), "Year: %d, month: %d, day : %d", ta.tm_year + 1900, ta.tm_mon + 1,ta.tm_mday ); - LogDebug("## certificate's notAfterTime : " << msg); + WrtLogD("## certificate's notAfterTime : %s", msg); fprintf(stderr, "## certificate's notAfterTime : %s\n", msg); if (storeIdSet.contains(CertStoreId::TIZEN_VERIFY)) { - LogDebug("## TIZEN_VERIFY : check certificate Time : FALSE"); + WrtLogD("## TIZEN_VERIFY : check certificate Time : FALSE"); fprintf(stderr, "## TIZEN_VERIFY : check certificate Time : FALSE\n"); return SignatureValidator::SIGNATURE_INVALID; } @@ -633,7 +632,7 @@ SignatureValidator::Result ImplTizenSignatureValidator::checkList(SignatureData tc.tm_mday = (tb.tm_mday + ta.tm_mday)/2; snprintf(msg, sizeof(msg), "Year: %d, month: %d, day : %d", tc.tm_year + 1900, tc.tm_mon + 1,tc.tm_mday ); - LogDebug("## cmp cert with validation time : " << msg); + WrtLogD("## cmp cert with validation time : %s", msg); fprintf(stderr, "## cmp cert with validation time : %s\n", msg); time_t outCurrent = mktime(&tc); @@ -656,30 +655,30 @@ SignatureValidator::Result ImplTizenSignatureValidator::checkList(SignatureData if (notAfter < nowTime) { context.validationTime = notAfter - TIMET_DAY; - LogWarning("Author certificate is expired. notAfter..."); + WrtLogW("Author certificate is expired. notAfter..."); } */ if (notBefore > nowTime) { - LogWarning("Author certificate is expired. notBefore time is greater than system-time."); + WrtLogW("Author certificate is expired. notBefore time is greater than system-time."); t = localtime(&nowTime); - LogDebug("System's current Year : " << t->tm_year + 1900); - LogDebug("System's current month : " << t->tm_mon + 1); - LogDebug("System's current day : " << t->tm_mday); + WrtLogD("System's current Year : %d", (t->tm_year + 1900)); + WrtLogD("System's current month : %d", (t->tm_mon + 1)); + WrtLogD("System's current day : %d", (t->tm_mday)); t = localtime(¬Before); - LogDebug("Author certificate's notBefore Year : " << t->tm_year + 1900); - LogDebug("Author certificate's notBefore month : " << t->tm_mon + 1); - LogDebug("Author certificate's notBefore day : " << t->tm_mday); + WrtLogD("Author certificate's notBefore Year : %d", (t->tm_year + 1900)); + WrtLogD("Author certificate's notBefore month : %d", (t->tm_mon + 1)); + WrtLogD("Author certificate's notBefore day : %d", (t->tm_mday)); context.validationTime = notBefore + TIMET_DAY; t = localtime(&context.validationTime); - LogDebug("Modified current Year : " << t->tm_year + 1900); - LogDebug("Modified current notBefore month : " << t->tm_mon + 1); - LogDebug("Modified current notBefore day : " << t->tm_mday); + WrtLogD("Modified current Year : %d", (t->tm_year + 1900)); + WrtLogD("Modified current notBefore month : %d", (t->tm_mon + 1)); + WrtLogD("Modified current notBefore day : %d", (t->tm_mday)); } } #endif @@ -690,16 +689,15 @@ SignatureValidator::Result ImplTizenSignatureValidator::checkList(SignatureData if(uriList.size() == 0) { if (XmlSec::NO_ERROR != XmlSecSingleton::Instance().validateNoHash(&context)) { - LogWarning("Installation break - invalid package! >> validateNoHash"); + WrtLogW("Installation break - invalid package! >> validateNoHash"); return SignatureValidator::SIGNATURE_INVALID; } } else if(uriList.size() != 0) { - partialHash = true; XmlSecSingleton::Instance().setPartialHashList(uriList); if (XmlSec::NO_ERROR != XmlSecSingleton::Instance().validatePartialHash(&context)) { - LogWarning("Installation break - invalid package! >> validatePartialHash"); + WrtLogW("Installation break - invalid package! >> validatePartialHash"); return SignatureValidator::SIGNATURE_INVALID; } } @@ -709,10 +707,11 @@ SignatureValidator::Result ImplTizenSignatureValidator::checkList(SignatureData // return SignatureValidator::SIGNATURE_INVALID; // } + (void) widgetContentPath; /* ReferenceValidator fileValidator(widgetContentPath); if (ReferenceValidator::NO_ERROR != fileValidator.checkReferences(data)) { - LogWarning("Invalid package - file references broken"); + WrtLogW("Invalid package - file references broken"); return SignatureValidator::SIGNATURE_INVALID; } */ @@ -727,7 +726,7 @@ SignatureValidator::Result ImplTizenSignatureValidator::checkList(SignatureData coll.load(sortedCertificateList); if (!coll.sort()) { - LogDebug("Collection does not contain chain!"); + WrtLogD("Collection does not contain chain!"); return SignatureValidator::SIGNATURE_INVALID; } @@ -749,7 +748,7 @@ SignatureValidator::Result ImplTizenSignatureValidator::checkList(SignatureData #endif if (disregard) { - LogWarning("Signature is disregard. RootCA is not a member of Tizen."); + WrtLogW("Signature is disregard. RootCA is not a member of Tizen."); return SignatureValidator::SIGNATURE_DISREGARD; } return SignatureValidator::SIGNATURE_VERIFIED; @@ -775,9 +774,9 @@ class ImplWacSignatureValidator : public SignatureValidator::ImplSignatureValida SignatureValidator::Result ImplWacSignatureValidator::checkList( - SignatureData &data, - const std::string &widgetContentPath, - const std::list<std::string>& uriList) + SignatureData & /* data */, + const std::string & /* widgetContentPath */, + const std::list<std::string>& /* uriList */) { return SignatureValidator::SIGNATURE_INVALID; } @@ -804,13 +803,13 @@ SignatureValidator::Result ImplWacSignatureValidator::check( // First step - sort certificate if (!collection.sort()) { - LogWarning("Certificates do not form valid chain."); + WrtLogW("Certificates do not form valid chain."); return SignatureValidator::SIGNATURE_INVALID; } // Check for error if (collection.empty()) { - LogWarning("Certificate list in signature is empty."); + WrtLogW("Certificate list in signature is empty."); return SignatureValidator::SIGNATURE_INVALID; } @@ -826,49 +825,43 @@ SignatureValidator::Result ImplWacSignatureValidator::check( // Is Root CA certificate trusted? CertStoreId::Set storeIdSet = createCertificateIdentifier().find(root); - LogDebug("Is root certificate from TIZEN_DEVELOPER domain: " - << storeIdSet.contains(CertStoreId::TIZEN_DEVELOPER)); - LogDebug("Is root certificate from TIZEN_TEST domain: " - << storeIdSet.contains(CertStoreId::TIZEN_TEST)); - LogDebug("Is root certificate from TIZEN_VERIFY domain: " - << storeIdSet.contains(CertStoreId::TIZEN_VERIFY)); - LogDebug("Is root certificate from TIZEN_PUBLIC domain: " - << storeIdSet.contains(CertStoreId::VIS_PUBLIC)); - LogDebug("Is root certificate from TIZEN_PARTNER domain: " - << storeIdSet.contains(CertStoreId::VIS_PARTNER)); - LogDebug("Is root certificate from TIZEN_PLATFORM domain: " - << storeIdSet.contains(CertStoreId::VIS_PLATFORM)); - - LogDebug("Visibility level is public : " - << storeIdSet.contains(CertStoreId::VIS_PUBLIC)); - LogDebug("Visibility level is partner : " - << storeIdSet.contains(CertStoreId::VIS_PARTNER)); - LogDebug("Visibility level is platform : " - << storeIdSet.contains(CertStoreId::VIS_PLATFORM)); + WrtLogD("Is root certificate from TIZEN_DEVELOPER domain: %d", storeIdSet.contains(CertStoreId::TIZEN_DEVELOPER)); + WrtLogD("Is root certificate from TIZEN_TEST domain: %d", storeIdSet.contains(CertStoreId::TIZEN_TEST)); + WrtLogD("Is root certificate from TIZEN_VERIFY domain: %d", storeIdSet.contains(CertStoreId::TIZEN_VERIFY)); + WrtLogD("Is root certificate from TIZEN_PUBLIC domain: %d", storeIdSet.contains(CertStoreId::VIS_PUBLIC)); + WrtLogD("Is root certificate from TIZEN_PARTNER domain: %d", storeIdSet.contains(CertStoreId::VIS_PARTNER)); + WrtLogD("Is root certificate from TIZEN_PLATFORM domain: %d", storeIdSet.contains(CertStoreId::VIS_PLATFORM)); - if (data.isAuthorSignature()) - { - if (!storeIdSet.contains(CertStoreId::TIZEN_DEVELOPER)) - { - LogWarning("author-signature.xml has got unrecognized Root CA " - "certificate. Signature will be disregarded."); - disregard = true; - } - LogDebug("Root CA for author signature is correct."); - } else { - LogDebug("signaturefile name = " << data.getSignatureFileName().c_str()); + WrtLogD("Visibility level is public : %d", storeIdSet.contains(CertStoreId::VIS_PUBLIC)); + WrtLogD("Visibility level is partner : %d", storeIdSet.contains(CertStoreId::VIS_PARTNER)); + WrtLogD("Visibility level is platform : %d", storeIdSet.contains(CertStoreId::VIS_PLATFORM)); + + if (data.isAuthorSignature()) + { + if (!storeIdSet.contains(CertStoreId::TIZEN_DEVELOPER)) + { + WrtLogW("author-signature.xml has got unrecognized Root CA " + "certificate. Signature will be disregarded."); + disregard = true; + } + } else { + WrtLogD("signaturefile name = %s", data.getSignatureFileName().c_str()); + if (storeIdSet.contains(CertStoreId::TIZEN_DEVELOPER)) + { + WrtLogE("distributor has author level siganture! Signature will be disregarded."); + return SignatureValidator::SIGNATURE_INVALID; + } - //Additional Check for certificate registration if (data.getSignatureNumber() == 1) { if (storeIdSet.contains(CertStoreId::VIS_PUBLIC) || storeIdSet.contains(CertStoreId::VIS_PARTNER) || storeIdSet.contains(CertStoreId::VIS_PLATFORM)) { - LogDebug("Root CA for signature1.xml is correct."); + WrtLogD("Root CA for signature1.xml is correct."); } else { - LogWarning("signature1.xml has got unrecognized Root CA " + WrtLogW("signature1.xml has got unrecognized Root CA " "certificate. Signature will be disregarded."); disregard = true; } @@ -888,7 +881,7 @@ SignatureValidator::Result ImplWacSignatureValidator::check( // If the end certificate is not ROOT CA we should disregard signature // but still signature must be valid... Aaaaaa it's so stupid... if (!(root->isSignedBy(root))) { - LogWarning("Root CA certificate not found. Chain is incomplete."); + WrtLogW("Root CA certificate not found. Chain is incomplete."); // context.allowBrokenChain = true; } @@ -908,26 +901,28 @@ SignatureValidator::Result ImplWacSignatureValidator::check( char msg[1024]; t = localtime(&nowTime); + if (!t) + return SignatureValidator::SIGNATURE_INVALID_CERT_TIME; memset(&tc, 0, sizeof(tc)); snprintf(msg, sizeof(msg), "Year: %d, month: %d, day : %d", t->tm_year + 1900, t->tm_mon + 1,t->tm_mday ); - LogDebug("## System's currentTime : " << msg); + WrtLogD("## System's currentTime : %s", msg); fprintf(stderr, "## System's currentTime : %s\n", msg); tb = _ASN1_GetTimeT(notBeforeTime); snprintf(msg, sizeof(msg), "Year: %d, month: %d, day : %d", tb.tm_year + 1900, tb.tm_mon + 1,tb.tm_mday ); - LogDebug("## certificate's notBeforeTime : " << msg); + WrtLogD("## certificate's notBeforeTime : %s", msg); fprintf(stderr, "## certificate's notBeforeTime : %s\n", msg); ta = _ASN1_GetTimeT(notAfterTime); snprintf(msg, sizeof(msg), "Year: %d, month: %d, day : %d", ta.tm_year + 1900, ta.tm_mon + 1,ta.tm_mday ); - LogDebug("## certificate's notAfterTime : " << msg); + WrtLogD("## certificate's notAfterTime : %s", msg); fprintf(stderr, "## certificate's notAfterTime : %s\n", msg); if (storeIdSet.contains(CertStoreId::TIZEN_VERIFY)) { - LogDebug("## TIZEN_VERIFY : check certificate Time : FALSE"); + WrtLogD("## TIZEN_VERIFY : check certificate Time : FALSE"); fprintf(stderr, "## TIZEN_VERIFY : check certificate Time : FALSE\n"); return SignatureValidator::SIGNATURE_INVALID; } @@ -938,14 +933,14 @@ SignatureValidator::Result ImplWacSignatureValidator::check( tc.tm_mday = (tb.tm_mday + ta.tm_mday)/2; snprintf(msg, sizeof(msg), "Year: %d, month: %d, day : %d", tc.tm_year + 1900, tc.tm_mon + 1,tc.tm_mday ); - LogDebug("## cmp cert with validation time : " << msg); + WrtLogD("## cmp cert with validation time : %s", msg); fprintf(stderr, "## cmp cert with validation time : %s\n", msg); time_t outCurrent = mktime(&tc); context.validationTime = outCurrent; //return SignatureValidator::SIGNATURE_INVALID; } - + #endif #if 0 @@ -961,49 +956,52 @@ SignatureValidator::Result ImplWacSignatureValidator::check( if (notAfter < nowTime) { context.validationTime = notAfter - TIMET_DAY; - LogWarning("Author certificate is expired. notAfter..."); + WrtLogW("Author certificate is expired. notAfter..."); } */ if (notBefore > nowTime) { - LogWarning("Author certificate is expired. notBefore time is greater than system-time."); + WrtLogW("Author certificate is expired. notBefore time is greater than system-time."); t = localtime(&nowTime); - LogDebug("System's current Year : " << t->tm_year + 1900); - LogDebug("System's current month : " << t->tm_mon + 1); - LogDebug("System's current day : " << t->tm_mday); + WrtLogD("System's current Year : %d", (t->tm_year + 1900)); + WrtLogD("System's current month : %d", (t->tm_mon + 1)); + WrtLogD("System's current day : %d", (t->tm_mday)); t = localtime(¬Before); - LogDebug("Author certificate's notBefore Year : " << t->tm_year + 1900); - LogDebug("Author certificate's notBefore month : " << t->tm_mon + 1); - LogDebug("Author certificate's notBefore day : " << t->tm_mday); + WrtLogD("Author certificate's notBefore Year : %d", (t->tm_year + 1900)); + WrtLogD("Author certificate's notBefore month : %d", (t->tm_mon + 1)); + WrtLogD("Author certificate's notBefore day : %d", (t->tm_mday)); context.validationTime = notBefore + TIMET_DAY; t = localtime(&context.validationTime); - LogDebug("Modified current Year : " << t->tm_year + 1900); - LogDebug("Modified current notBefore month : " << t->tm_mon + 1); - LogDebug("Modified current notBefore day : " << t->tm_mday); + WrtLogD("Modified current Year : %d", (t->tm_year + 1900)); + WrtLogD("Modified current notBefore month : %d", (t->tm_mon + 1)); + WrtLogD("Modified current notBefore day : %d", (t->tm_mday)); } } #endif - if (XmlSec::NO_ERROR != XmlSecSingleton::Instance().validate(&context)) { - LogWarning("Installation break - invalid package!"); - return SignatureValidator::SIGNATURE_INVALID; - } + if (!data.isAuthorSignature()) + { + if (XmlSec::NO_ERROR != XmlSecSingleton::Instance().validate(&context)) { + WrtLogW("Installation break - invalid package!"); + return SignatureValidator::SIGNATURE_INVALID; + } - data.setReference(context.referenceSet); + data.setReference(context.referenceSet); - if (!checkObjectReferences(data)) { - return SignatureValidator::SIGNATURE_INVALID; - } + if (!checkObjectReferences(data)) { + return SignatureValidator::SIGNATURE_INVALID; + } - ReferenceValidator fileValidator(widgetContentPath); - if (ReferenceValidator::NO_ERROR != fileValidator.checkReferences(data)) { - LogWarning("Invalid package - file references broken"); - return SignatureValidator::SIGNATURE_INVALID; - } + ReferenceValidator fileValidator(widgetContentPath); + if (ReferenceValidator::NO_ERROR != fileValidator.checkReferences(data)) { + WrtLogW("Invalid package - file references broken"); + return SignatureValidator::SIGNATURE_INVALID; + } + } #ifdef TIZEN_FEATURE_CERT_SVC_OCSP_CRL // It is good time to do OCSP check @@ -1015,7 +1013,7 @@ SignatureValidator::Result ImplWacSignatureValidator::check( coll.load(sortedCertificateList); if (!coll.sort()) { - LogDebug("Collection does not contain chain!"); + WrtLogD("Collection does not contain chain!"); return SignatureValidator::SIGNATURE_INVALID; } @@ -1037,7 +1035,7 @@ SignatureValidator::Result ImplWacSignatureValidator::check( #endif if (disregard) { - LogWarning("Signature is disregard. RootCA is not a member of Tizen."); + WrtLogW("Signature is disregard. RootCA is not a member of Tizen."); return SignatureValidator::SIGNATURE_DISREGARD; } return SignatureValidator::SIGNATURE_VERIFIED; @@ -1052,7 +1050,7 @@ SignatureValidator::SignatureValidator( bool complianceMode) : m_impl(0) { - LogDebug( "appType :" << appType ); + WrtLogD( "appType :%d", appType ); if(appType == TIZEN) { diff --git a/vcore/src/vcore/SignatureValidator.h b/vcore/src/vcore/SignatureValidator.h index 512cd6b..1f3900c 100644 --- a/vcore/src/vcore/SignatureValidator.h +++ b/vcore/src/vcore/SignatureValidator.h @@ -22,15 +22,18 @@ #ifndef _VALIDATION_CORE_SIGNATUREVALIDATOR_H_ #define _VALIDATION_CORE_SIGNATUREVALIDATOR_H_ -#include <string> +#ifndef LOG_TAG +#undef LOG_TAG +#define LOG_TAG "OSP" +#endif -#include <dpl/noncopyable.h> +#include <string> #include <vcore/SignatureData.h> namespace ValidationCore { -class SignatureValidator : public DPL::Noncopyable { +class SignatureValidator { public: class ImplSignatureValidator; @@ -46,9 +49,22 @@ public: SIGNATURE_INVALID, SIGNATURE_VERIFIED, SIGNATURE_DISREGARD, // no ocsp response or ocsp return unknown status - SIGNATURE_REVOKED + SIGNATURE_REVOKED, + SIGNATURE_INVALID_CERT_CHAIN, //5, from here, new error enum + SIGNATURE_INVALID_DISTRIBUTOR_CERT, + SIGNATURE_INVALID_SDK_DEFAULT_AUTHOR_CERT, + SIGNATURE_IN_DISTRIBUTOR_CASE_AUTHOR_CERT, + SIGNATURE_INVALID_CERT_TIME, + SIGNATURE_NO_DEVICE_PROFILE, + SIGNATURE_INVALID_DEVICE_UNIQUE_ID, + SIGNATURE_INVALID_NO_HASH_FILE, + SIGNATURE_INVALID_HASH_SIGNATURE }; + SignatureValidator() = delete; + SignatureValidator(const SignatureValidator &) = delete; + const SignatureValidator &operator=(const SignatureValidator &) = delete; + explicit SignatureValidator( AppType appType, bool ocspEnable, diff --git a/vcore/src/vcore/SoupMessageSendAsync.h b/vcore/src/vcore/SoupMessageSendAsync.h deleted file mode 100644 index 07fcad5..0000000 --- a/vcore/src/vcore/SoupMessageSendAsync.h +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/*! - * @author Bartlomiej Grzelewski (b.grzelewski@samsung.com) - * @version 0.1 - * @file SoupMessageSendAsync.h - * @brief Routines for certificate validation over OCSP - */ -#ifndef _SRC_VALIDATION_CORE_SOUP_MESSAGE_SEND_ASYNC_H_ -#define _SRC_VALIDATION_CORE_SOUP_MESSAGE_SEND_ASYNC_H_ - -#include <map> -#include <vector> - -#include <dpl/assert.h> - -#include <dpl/event/inter_context_delegate.h> - -#include <vcore/SoupMessageSendBase.h> - -namespace SoupWrapper { - -class SoupMessageSendAsync - : public SoupMessageSendBase - , public DPL::Event::ICDelegateSupport<SoupMessageSendAsync> -{ - typedef DPL::Event::ICDelegate<SoupSession*, SoupMessage*, void*> SoupDelegate; - public: - void sendAsync() { - Assert(m_status == STATUS_IDLE); - Assert(!m_soupSession); - Assert(!m_soupMessage); - - m_status = STATUS_SEND_ASYNC; - m_tryLeft = m_tryCount; - m_mainContext = g_main_context_new(); - - if (!m_mainContext){ - m_status = STATUS_IDLE; - - // call the delegate to outside with error! - return; - } - - m_soupSession = soup_session_async_new_with_options( - SOUP_SESSION_ASYNC_CONTEXT, - m_mainContext, - SOUP_SESSION_TIMEOUT, - m_timeout, - NULL); - - if (!m_soupSession){ - m_status = STATUS_IDLE; - g_object_unref(m_mainContext); - m_mainContext = 0; - - // call the deletage to outside with error! - return; - } - - m_soupMessage = createRequest(); - - if (!m_soupMessage){ - m_status = STATUS_IDLE; - g_object_unref(m_soupSession); - m_soupSession = 0; - g_object_unref(m_mainContext); - m_mainContext = 0; - - // call the delegate to outsize with error! - return; - } - - sendAsyncIterationStart(); - } - - protected: - - struct SoupDelegateOpaque { - SoupDelegate dlg; - }; - - void sendAsyncIterationStart(){ - // ICDelegate could be called only once. - // We can set user data only once. - // We need nasty hack because we will call ICDelegate m_tryCount times. - SoupDelegateOpaque *opaq = new SoupDelegateOpaque; - opaq->dlg = makeICDelegate(&SoupMessageSendAsync::requestReceiver); - - soup_session_queue_message(m_soupSession, - m_soupMessage, - soupSessionCallback, - reinterpret_cast<gpointer>(opaq)); - } - - void sendAsyncIteration(SoupDelegateOpaque *opaq){ - // Replace used ICDelegate with new one without changing - // userdata ;-) - opaq->dlg = makeICDelegate(&SoupMessageSendAsync::requestReceiver); - soup_session_requeue_message(m_soupSession, - m_soupMessage); - } - - void requestReceiver(SoupSession *session, SoupMessage *msg, void *opaque){ - // We are in thread which called sendAsync function. - Assert(session == m_soupSession); - Assert(msg == m_soupMessage); - Assert(opaque != 0); - Assert(m_status == STATUS_SEND_ASYNC); - - m_tryLeft--; - - if (msg->status_code == SOUP_STATUS_OK) { - m_responseBuffer.resize(msg->response_body->length); - memcpy(&m_responseBuffer[0], - msg->response_body->data, - msg->response_body->length); - // We are done. - m_status = STATUS_IDLE; - delete static_cast<SoupDelegateOpaque*>(opaque); - - // call the delegate to outside! - return; - } - - // Error protocol // - if (m_tryLeft <= 0) { - m_status = STATUS_IDLE; - delete static_cast<SoupDelegateOpaque*>(opaque); - - // call the delegate to outside with error! - return; - } - - // create delegate and send the request once again. - sendAsyncIteration(reinterpret_cast<SoupDelegateOpaque*>(opaque)); - } - - static void soupSessionCallback(SoupSession *session, - SoupMessage *msg, - gpointer userdata) - { - // We are in main thread. We need to switch context. - // This delegate can switch context to dpl thread or main thread. - SoupDelegateOpaque *opaque; - opaque = reinterpret_cast<SoupDelegateOpaque*>(userdata); - opaque->dlg(session, msg, userdata); - } - - int m_tryLeft; - - GMainContext *m_mainContext; - SoupSession *m_soupSession; - SoupMessage *m_soupMessage; -}; - -} // namespace ValidationCore - -#endif diff --git a/vcore/src/vcore/SoupMessageSendBase.cpp b/vcore/src/vcore/SoupMessageSendBase.cpp index e7f4742..a361c18 100644 --- a/vcore/src/vcore/SoupMessageSendBase.cpp +++ b/vcore/src/vcore/SoupMessageSendBase.cpp @@ -23,7 +23,7 @@ #include <dpl/assert.h> #include <dpl/foreach.h> -#include <dpl/log/log.h> +#include <dpl/log/wrt_log.h> namespace SoupWrapper { @@ -74,7 +74,7 @@ void SoupMessageSendBase::setRetry(int retry) { SoupMessage* SoupMessageSendBase::createRequest(){ SoupMessage *message; - LogInfo("Soup message will be send to: " << m_host.c_str()); + WrtLogI("Soup message will be send to: %s", m_host.c_str()); if (!m_requestBuffer.empty()) { message = soup_message_new("POST", m_host.c_str()); @@ -83,7 +83,7 @@ SoupMessage* SoupMessageSendBase::createRequest(){ } if (!message) { - LogError("Error creating request!"); + WrtLogE("Error creating request!"); return 0; } diff --git a/vcore/src/vcore/SoupMessageSendSync.cpp b/vcore/src/vcore/SoupMessageSendSync.cpp index e3f3ee4..8c7343c 100644 --- a/vcore/src/vcore/SoupMessageSendSync.cpp +++ b/vcore/src/vcore/SoupMessageSendSync.cpp @@ -26,7 +26,7 @@ #include <vconf.h> -#include <dpl/log/log.h> +#include <dpl/log/wrt_log.h> namespace SoupWrapper { @@ -43,11 +43,10 @@ SoupMessageSendBase::RequestStatus SoupMessageSendSync::sendSync() std::unique_ptr <SoupURI, std::function<void(SoupURI*)> > proxyURI(soup_uri_new (proxy.get()), soup_uri_free); - LogDebug("Proxy ptr:" << (void*)proxy.get() << - " Proxy addr: " << proxy.get()); + WrtLogD("Proxy ptr: %s Proxy addr: %s", (void*)proxy.get(), proxy.get()); for(int tryCount = 0; tryCount < m_tryCount; ++ tryCount){ - LogDebug("Try(" << tryCount << ") to download " << m_host); + WrtLogD("Try(%d) to download %s", tryCount, m_host.c_str()); ScopedSoupSession session(soup_session_async_new_with_options( SOUP_SESSION_ASYNC_CONTEXT, @@ -63,7 +62,7 @@ SoupMessageSendBase::RequestStatus SoupMessageSendSync::sendSync() msg.Reset(createRequest()); if (!msg) { - LogError("Unable to send HTTP request."); + WrtLogE("Unable to send HTTP request."); m_status = STATUS_IDLE; return REQUEST_STATUS_CONNECTION_ERROR; } @@ -80,10 +79,7 @@ SoupMessageSendBase::RequestStatus SoupMessageSendSync::sendSync() m_status = STATUS_IDLE; return REQUEST_STATUS_OK; } else { - LogWarning("Soup failed with code " << msg->status_code - << " message \n------------\n" - << msg->response_body->data - << "\n--------------\n"); + WrtLogW("Soup failed with code [%d] message [%s]", msg->status_code, msg->response_body->data); } } diff --git a/vcore/src/vcore/TimeConversion.cpp b/vcore/src/vcore/TimeConversion.cpp index 98c80f3..803f582 100644 --- a/vcore/src/vcore/TimeConversion.cpp +++ b/vcore/src/vcore/TimeConversion.cpp @@ -17,7 +17,7 @@ #include <string.h> -#include <dpl/log/log.h> +#include <dpl/log/wrt_log.h> #include <dpl/assert.h> namespace ValidationCore { @@ -97,12 +97,12 @@ int asn1GeneralizedTimeToTimeT(ASN1_GENERALIZEDTIME *tm, time_t *res) const int DATE_BUFFER_LENGTH = 15; // YYYYMMDDHHMMSSZ if (NULL == res || NULL == tm) { - LogError("NULL pointer"); + WrtLogE("NULL pointer"); return -1; } if (DATE_BUFFER_LENGTH != tm->length || NULL == tm->data) { - LogError("Invalid ASN1_GENERALIZEDTIME"); + WrtLogE("Invalid ASN1_GENERALIZEDTIME"); return -1; } @@ -116,7 +116,7 @@ int asn1GeneralizedTimeToTimeT(ASN1_GENERALIZEDTIME *tm, time_t *res) &time_s.tm_min, &time_s.tm_sec) < 6) { - LogError("Could not extract time data from ASN1_GENERALIZEDTIME"); + WrtLogE("Could not extract time data from ASN1_GENERALIZEDTIME"); return -1; } diff --git a/vcore/src/vcore/VCore.cpp b/vcore/src/vcore/VCore.cpp index fe1aa76..7788584 100644 --- a/vcore/src/vcore/VCore.cpp +++ b/vcore/src/vcore/VCore.cpp @@ -30,21 +30,13 @@ #include <glib-object.h> #include <dpl/assert.h> -#include <dpl/log/log.h> - -#include <tzplatform_config.h> - -namespace { +#include <dpl/log/wrt_log.h> #ifdef TIZEN_FEATURE_CERT_SVC_OCSP_CRL -DPL::DB::ThreadDatabaseSupport *threadInterface = NULL; -const std::string DatabasePath = tzplatform_mkpath(TZ_SYS_DB, ".cert_svc_vcore.db"); -#endif - -const std::string FingerprintListPath = tzplatform_mkpath(TZ_SYS_SHARE, "ca-certificates/fingerprint/fingerprint_list.xml"); -const std::string FingerprintListSchemaPath = tzplatform_mkpath(TZ_SYS_SHARE, "ca-certificates/fingerprint/fingerprint_list.xsd"); - +namespace { +VcoreDPL::DB::ThreadDatabaseSupport *threadInterface = NULL; } // namespace anonymous +#endif namespace ValidationCore { @@ -54,24 +46,24 @@ void AttachToThreadRO(void) Assert(threadInterface); static bool check = true; threadInterface->AttachToThread( - DPL::DB::SqlConnection::Flag::RO); + VcoreDPL::DB::SqlConnection::Flag::RO); // We can have race condition here but CheckTableExist // is thread safe and nothing bad will happend. if (check) { check = false; Assert(ThreadInterface().CheckTableExist(DB_CHECKSUM_STR) && - "Not a valid vcore database version"); + "Not a valid vcore database version"); } #endif } void AttachToThreadRW(void) { -#ifdef TIZEN_FEATURE_CERT_SVC_OCSP_CRL +#ifdef TIZEN_FEATURE_CERT_SVC_OCSP_CRL Assert(threadInterface); static bool check = true; threadInterface->AttachToThread( - DPL::DB::SqlConnection::Flag::RW); + VcoreDPL::DB::SqlConnection::Flag::RW); // We can have race condition here but CheckTableExist // is thread safe and nothing bad will happend. if (check) { @@ -89,31 +81,31 @@ void DetachFromThread(void){ #endif } #ifdef TIZEN_FEATURE_CERT_SVC_OCSP_CRL -DPL::DB::ThreadDatabaseSupport& ThreadInterface(void) { +VcoreDPL::DB::ThreadDatabaseSupport& ThreadInterface(void) { Assert(threadInterface); return *threadInterface; } #endif + void VCoreInit() { -#ifdef TIZEN_FEATURE_CERT_SVC_OCSP_CRL - if (threadInterface) { - LogDebug("Already Initialized"); - return; +#ifdef TIZEN_FEATURE_CERT_SVC_OCSP_CRL + if (threadInterface) { + WrtLogD("Already Initialized"); + return true; } - threadInterface = new DPL::DB::ThreadDatabaseSupport( - DatabasePath.c_str(), - DPL::DB::SqlConnection::Flag::UseLucene); + threadInterface = new VcoreDPL::DB::ThreadDatabaseSupport( + CERTSVC_VCORE_DB, + VcoreDPL::DB::SqlConnection::Flag::UseLucene); #endif SSL_library_init(); - g_type_init(); Config &globalConfig = ConfigSingleton::Instance(); - globalConfig.setXMLConfigPath(FingerprintListPath); - globalConfig.setXMLSchemaPath(FingerprintListSchemaPath); + globalConfig.setXMLConfigPath(std::string(FINGERPRINT_LIST_PATH)); + globalConfig.setXMLSchemaPath(std::string(FINGERPRINT_LIST_SCHEMA_PATH)); } void VCoreDeinit() diff --git a/vcore/src/vcore/VCorePrivate.h b/vcore/src/vcore/VCorePrivate.h index a2955b1..802d3fa 100644 --- a/vcore/src/vcore/VCorePrivate.h +++ b/vcore/src/vcore/VCorePrivate.h @@ -31,7 +31,7 @@ namespace ValidationCore { #ifdef TIZEN_FEATURE_CERT_SVC_OCSP_CRL -DPL::DB::ThreadDatabaseSupport& ThreadInterface(void); +VcoreDPL::DB::ThreadDatabaseSupport& ThreadInterface(void); #endif } // namespace ValidationCore diff --git a/vcore/src/vcore/ValidatorFactories.cpp b/vcore/src/vcore/ValidatorFactories.cpp index c068df7..93238c6 100644 --- a/vcore/src/vcore/ValidatorFactories.cpp +++ b/vcore/src/vcore/ValidatorFactories.cpp @@ -21,12 +21,12 @@ */ #include <vcore/ValidatorFactories.h> -#include <string> -#include <dpl/log/log.h> - #include <vcore/Certificate.h> #include <vcore/CertificateConfigReader.h> #include <vcore/Config.h> +#include <dpl/log/wrt_log.h> + +#include <string> namespace ValidationCore { @@ -38,12 +38,13 @@ const CertificateIdentifier& createCertificateIdentifier() CertificateConfigReader reader; std::string file = ConfigSingleton::Instance().getXMLConfigPath(); - LogDebug("File with fingerprint list is: " << file); + WrtLogD("File with fingerprint list is: %s", file.c_str()); std::string schema = ConfigSingleton::Instance().getXMLSchemaPath(); - LogDebug("File with fingerprint list schema is: " << schema); + WrtLogD("File with fingerprint list schema is: %s", schema.c_str()); reader.initialize(file, schema); reader.read(certificateIdentifier); + initialized = true; } return certificateIdentifier; diff --git a/vcore/src/vcore/WacOrigin.cpp b/vcore/src/vcore/WacOrigin.cpp index 7ca0174..304f0e8 100644 --- a/vcore/src/vcore/WacOrigin.cpp +++ b/vcore/src/vcore/WacOrigin.cpp @@ -113,7 +113,7 @@ void WacOrigin::parse(const char *url) char *output = NULL; if (IDNA_SUCCESS != idna_to_ascii_lz(m_host.c_str(), &output, IDNA_USE_STD3_ASCII_RULES)) { - LogError("libidn error"); + WrtLogE("libidn error"); m_parseFailed = true; free(output); return; @@ -144,7 +144,7 @@ void WacOrigin::setPort() m_port = PORT_HTTPS; return; } else { - LogDebug("Scheme " << m_scheme << " is not support by WAC2.0"); + WrtLogD("Scheme %s is not support by WAC2.0 ", m_scheme.c_str()); m_parseFailed = true; } } diff --git a/vcore/src/vcore/WrtSignatureValidator.cpp b/vcore/src/vcore/WrtSignatureValidator.cpp index 654b05b..81fc201 100644 --- a/vcore/src/vcore/WrtSignatureValidator.cpp +++ b/vcore/src/vcore/WrtSignatureValidator.cpp @@ -21,7 +21,6 @@ */ #include <vcore/WrtSignatureValidator.h> -#include <dpl/log/log.h> #include <vcore/CertificateVerifier.h> #include <vcore/Certificate.h> #include <vcore/OCSPCertMgrUtil.h> @@ -29,6 +28,8 @@ #include <vcore/ValidatorFactories.h> #include <vcore/XmlsecAdapter.h> +#include <dpl/log/wrt_log.h> + namespace { const time_t TIMET_DAY = 60 * 60 * 24; @@ -38,6 +39,7 @@ const std::string TOKEN_ROLE_DISTRIBUTOR_URI = "http://www.w3.org/ns/widgets-digsig#role-distributor"; const std::string TOKEN_PROFILE_URI = "http://www.w3.org/ns/widgets-digsig#profile"; + } // namespace anonymouse static tm _ASN1_GetTimeT(ASN1_TIME* time) @@ -50,20 +52,26 @@ static tm _ASN1_GetTimeT(ASN1_TIME* time) if (time->type == V_ASN1_UTCTIME) /* two digit year */ { - t.tm_year = (str[i++] - '0') * 10 + (str[++i] - '0'); + t.tm_year = (str[i] - '0') * 10 + (str[i+1] - '0'); + i += 2; if (t.tm_year < 70) t.tm_year += 100; } else if (time->type == V_ASN1_GENERALIZEDTIME) /* four digit year */ { - t.tm_year = (str[i++] - '0') * 1000 + (str[++i] - '0') * 100 + (str[++i] - '0') * 10 + (str[++i] - '0'); + t.tm_year = + (str[i] - '0') * 1000 + + (str[i+1] - '0') * 100 + + (str[i+2] - '0') * 10 + + (str[i+3] - '0'); + i += 4; t.tm_year -= 1900; } - t.tm_mon = ((str[i++] - '0') * 10 + (str[++i] - '0')) - 1; // -1 since January is 0 not 1. - t.tm_mday = (str[i++] - '0') * 10 + (str[++i] - '0'); - t.tm_hour = (str[i++] - '0') * 10 + (str[++i] - '0'); - t.tm_min = (str[i++] - '0') * 10 + (str[++i] - '0'); - t.tm_sec = (str[i++] - '0') * 10 + (str[++i] - '0'); + t.tm_mon = ((str[i] - '0') * 10 + (str[i+1] - '0')) - 1; // -1 since January is 0 not 1. + t.tm_mday = (str[i+2] - '0') * 10 + (str[i+3] - '0'); + t.tm_hour = (str[i+4] - '0') * 10 + (str[i+5] - '0'); + t.tm_min = (str[i+6] - '0') * 10 + (str[i+7] - '0'); + t.tm_sec = (str[i+8] - '0') * 10 + (str[i+9] - '0'); /* Note: we did not adjust the time based on time zone information */ return t; @@ -82,30 +90,34 @@ public: bool crlEnable, bool complianceMode) : m_complianceModeEnabled(complianceMode) - #ifdef TIZEN_FEATURE_CERT_SVC_OCSP_CRL - , m_ocspEnable(ocspEnable) - , m_crlEnable(crlEnable) - #endif - {} + { +#ifdef TIZEN_FEATURE_CERT_SVC_OCSP_CRL + m_ocspEnable = ocspEnable; + m_crlEnable = crlEnable; +#else + (void) ocspEnable; + (void) crlEnable; +#endif + } - virtual ~Impl(){} + virtual ~Impl() {} bool checkRoleURI(const SignatureData &data) { std::string roleURI = data.getRoleURI(); if (roleURI.empty()) { - LogWarning("URI attribute in Role tag couldn't be empty."); + WrtLogW("URI attribute in Role tag couldn't be empty."); return false; } if (roleURI != TOKEN_ROLE_AUTHOR_URI && data.isAuthorSignature()) { - LogWarning("URI attribute in Role tag does not " + WrtLogW("URI attribute in Role tag does not " "match with signature filename."); return false; } if (roleURI != TOKEN_ROLE_DISTRIBUTOR_URI && !data.isAuthorSignature()) { - LogWarning("URI attribute in Role tag does not " + WrtLogW("URI attribute in Role tag does not " "match with signature filename."); return false; } @@ -114,9 +126,7 @@ public: bool checkProfileURI(const SignatureData &data) { if (TOKEN_PROFILE_URI != data.getProfileURI()) { - LogWarning( - "Profile tag contains unsupported value in URI attribute(" << - data.getProfileURI() << ")."); + WrtLogW("Profile tag contains unsupported value in URI attribute (%s).", (data.getProfileURI()).c_str()); return false; } return true; @@ -127,8 +137,7 @@ public: ObjectList::const_iterator iter; for (iter = objectList.begin(); iter != objectList.end(); ++iter) { if (!data.containObjectReference(*iter)) { - LogWarning("Signature does not contain reference for object " << - *iter); + WrtLogW("Signature does not contain reference for object %s", (*iter).c_str()); return false; } } @@ -143,9 +152,8 @@ protected: }; -class ImplTizen : public WrtSignatureValidator::Impl -{ - public: +class ImplTizen : public WrtSignatureValidator::Impl { +public: WrtSignatureValidator::Result check(SignatureData &data, const std::string &widgetContentPath); @@ -179,14 +187,14 @@ WrtSignatureValidator::Result ImplTizen::check( // First step - sort certificate if (!collection.sort()) { - LogWarning("Certificates do not form valid chain."); - return WrtSignatureValidator::SIGNATURE_INVALID; + WrtLogW("Certificates do not form valid chain."); + return WrtSignatureValidator::SIGNATURE_INVALID_CERT_CHAIN;//SIGNATURE_INVALID; } // Check for error if (collection.empty()) { - LogWarning("Certificate list in signature is empty."); - return WrtSignatureValidator::SIGNATURE_INVALID; + WrtLogW("Certificate list in signature is empty."); + return WrtSignatureValidator::SIGNATURE_INVALID_CERT_CHAIN;//SIGNATURE_INVALID; } CertificateList sortedCertificateList = collection.getChain(); @@ -201,48 +209,44 @@ WrtSignatureValidator::Result ImplTizen::check( // Is Root CA certificate trusted? CertStoreId::Set storeIdSet = createCertificateIdentifier().find(root); - LogDebug("Is root certificate from TIZEN_DEVELOPER domain: " - << storeIdSet.contains(CertStoreId::TIZEN_DEVELOPER)); - LogDebug("Is root certificate from TIZEN_TEST domain: " - << storeIdSet.contains(CertStoreId::TIZEN_TEST)); - LogDebug("Is root certificate from TIZEN_VERIFY domain: " - << storeIdSet.contains(CertStoreId::TIZEN_VERIFY)); - LogDebug("Is root certificate from TIZEN_PUBLIC domain: " - << storeIdSet.contains(CertStoreId::VIS_PUBLIC)); - LogDebug("Is root certificate from TIZEN_PARTNER domain: " - << storeIdSet.contains(CertStoreId::VIS_PARTNER)); - LogDebug("Is root certificate from TIZEN_PLATFORM domain: " - << storeIdSet.contains(CertStoreId::VIS_PLATFORM)); - LogDebug("Visibility level is public : " - << storeIdSet.contains(CertStoreId::VIS_PUBLIC)); - LogDebug("Visibility level is partner : " - << storeIdSet.contains(CertStoreId::VIS_PARTNER)); - LogDebug("Visibility level is platform : " - << storeIdSet.contains(CertStoreId::VIS_PLATFORM)); + WrtLogD("Is root certificate from TIZEN_DEVELOPER domain: %d", storeIdSet.contains(CertStoreId::TIZEN_DEVELOPER)); + WrtLogD("Is root certificate from TIZEN_TEST domain: %d", storeIdSet.contains(CertStoreId::TIZEN_TEST)); + WrtLogD("Is root certificate from TIZEN_VERIFY domain: %d", storeIdSet.contains(CertStoreId::TIZEN_VERIFY)); + WrtLogD("Is root certificate from TIZEN_PUBLIC domain: %d", storeIdSet.contains(CertStoreId::VIS_PUBLIC)); + WrtLogD("Is root certificate from TIZEN_PARTNER domain: %d", storeIdSet.contains(CertStoreId::VIS_PARTNER)); + WrtLogD("Is root certificate from TIZEN_PLATFORM domain: %d", storeIdSet.contains(CertStoreId::VIS_PLATFORM)); + WrtLogD("Visibility level is public : %d", storeIdSet.contains(CertStoreId::VIS_PUBLIC)); + WrtLogD("Visibility level is partner : %d", storeIdSet.contains(CertStoreId::VIS_PARTNER)); + WrtLogD("Visibility level is platform : %d", storeIdSet.contains(CertStoreId::VIS_PLATFORM)); if (data.isAuthorSignature()) { if (!storeIdSet.contains(CertStoreId::TIZEN_DEVELOPER)) { - LogWarning("author-signature.xml has got unrecognized Root CA " - "certificate. Signature will be disregarded."); - disregard = true; + WrtLogW("author-signature.xml has got unrecognized Root CA " + "certificate. Signature will be disregarded."); + disregard = true; } - LogDebug("Root CA for author signature is correct."); } - else + else // distributor { - LogDebug("signaturefile name = " << data.getSignatureFileName().c_str()); + if (storeIdSet.contains(CertStoreId::TIZEN_DEVELOPER)) + { + WrtLogW("distributor has author level siganture! Signature will be disregarded."); + return WrtSignatureValidator::SIGNATURE_IN_DISTRIBUTOR_CASE_AUTHOR_CERT;//SIGNATURE_INVALID; + } + WrtLogD("signaturefile name = %s", data.getSignatureFileName().c_str()); + if (data.getSignatureNumber() == 1) { if (storeIdSet.contains(CertStoreId::VIS_PUBLIC) || storeIdSet.contains(CertStoreId::VIS_PARTNER) || storeIdSet.contains(CertStoreId::VIS_PLATFORM)) { - LogDebug("Root CA for signature1.xml is correct."); + WrtLogD("Root CA for signature1.xml is correct."); } else { - LogWarning("signature1.xml has got unrecognized Root CA " + WrtLogW("signature1.xml has got unrecognized Root CA " "certificate. Signature will be disregarded."); disregard = true; } @@ -262,7 +266,7 @@ WrtSignatureValidator::Result ImplTizen::check( // If the end certificate is not ROOT CA we should disregard signature // but still signature must be valid... Aaaaaa it's so stupid... if (!(root->isSignedBy(root))) { - LogWarning("Root CA certificate not found. Chain is incomplete."); + WrtLogW("Root CA certificate not found. Chain is incomplete."); //context.allowBrokenChain = true; } @@ -282,44 +286,46 @@ WrtSignatureValidator::Result ImplTizen::check( char msg[1024]; t = localtime(&nowTime); + if (!t) + return WrtSignatureValidator::SIGNATURE_INVALID_CERT_TIME; memset(&tc, 0, sizeof(tc)); snprintf(msg, sizeof(msg), "Year: %d, month: %d, day : %d", t->tm_year + 1900, t->tm_mon + 1,t->tm_mday ); - LogDebug("## System's currentTime : " << msg); + WrtLogD("## System's currentTime : %s", msg); fprintf(stderr, "## System's currentTime : %s\n", msg); tb = _ASN1_GetTimeT(notBeforeTime); snprintf(msg, sizeof(msg), "Year: %d, month: %d, day : %d", tb.tm_year + 1900, tb.tm_mon + 1,tb.tm_mday ); - LogDebug("## certificate's notBeforeTime : " << msg); + WrtLogD("## certificate's notBeforeTime : %s", msg); fprintf(stderr, "## certificate's notBeforeTime : %s\n", msg); ta = _ASN1_GetTimeT(notAfterTime); snprintf(msg, sizeof(msg), "Year: %d, month: %d, day : %d", ta.tm_year + 1900, ta.tm_mon + 1,ta.tm_mday ); - LogDebug("## certificate's notAfterTime : " << msg); + WrtLogD("## certificate's notAfterTime : %s", msg); fprintf(stderr, "## certificate's notAfterTime : %s\n", msg); - if (storeIdSet.contains(CertStoreId::TIZEN_VERIFY)) - { - LogDebug("## TIZEN_VERIFY : check certificate Time : FALSE"); + if (storeIdSet.contains(CertStoreId::TIZEN_TEST) || storeIdSet.contains(CertStoreId::TIZEN_VERIFY)) + { + WrtLogD("## TIZEN_VERIFY : check certificate Time : FALSE"); fprintf(stderr, "## TIZEN_VERIFY : check certificate Time : FALSE\n"); - return WrtSignatureValidator::SIGNATURE_INVALID; + return WrtSignatureValidator::SIGNATURE_INVALID_CERT_TIME;//SIGNATURE_INVALID; } int year = (ta.tm_year - tb.tm_year) / 4; if(year == 0) { - tc.tm_year = tb.tm_year; + tc.tm_year = tb.tm_year; tc.tm_mon = tb.tm_mon + 1; tc.tm_mday = tb.tm_mday; if(tc.tm_mon == 12) { - tc.tm_year = ta.tm_year; + tc.tm_year = ta.tm_year; tc.tm_mon = ta.tm_mon - 1; tc.tm_mday = ta.tm_mday; - + if(tc.tm_mon < 0) { tc.tm_year = ta.tm_year; @@ -328,21 +334,21 @@ WrtSignatureValidator::Result ImplTizen::check( if(tc.tm_mday == 0) { - tc.tm_year = tb.tm_year; + tc.tm_year = tb.tm_year; tc.tm_mon = tb.tm_mon; tc.tm_mday = tb.tm_mday +1; } } - } + } } else{ tc.tm_year = tb.tm_year + year; tc.tm_mon = (tb.tm_mon + ta.tm_mon )/2; - tc.tm_mday = (tb.tm_mday + ta.tm_mday)/2; + tc.tm_mday = (tb.tm_mday + ta.tm_mday)/2; } snprintf(msg, sizeof(msg), "Year: %d, month: %d, day : %d", tc.tm_year + 1900, tc.tm_mon + 1,tc.tm_mday ); - LogDebug("## cmp cert with validation time : " << msg); + WrtLogD("## cmp cert with validation time : %s", msg); fprintf(stderr, "## cmp cert with validation time : %s\n", msg); time_t outCurrent = mktime(&tc); @@ -351,7 +357,7 @@ WrtSignatureValidator::Result ImplTizen::check( fprintf(stderr, "## cmp outCurrent time : %ld\n", outCurrent); //return WrtSignatureValidator::SIGNATURE_INVALID; - } + } #endif @@ -368,30 +374,30 @@ WrtSignatureValidator::Result ImplTizen::check( if (notAfter < nowTime) { context.validationTime = notAfter - TIMET_DAY; - LogWarning("Author certificate is expired. notAfter..."); + WrtLogW("Author certificate is expired. notAfter..."); } */ if (notBefore > nowTime) { - LogWarning("Author certificate is expired. notBefore time is greater than system-time."); + WrtLogW("Author certificate is expired. notBefore time is greater than system-time."); t = localtime(&nowTime); - LogDebug("System's current Year : " << t->tm_year + 1900); - LogDebug("System's current month : " << t->tm_mon + 1); - LogDebug("System's current day : " << t->tm_mday); + WrtLogD("System's current Year : %d", (t->tm_year + 1900)); + WrtLogD("System's current month : %d", (t->tm_mon + 1)); + WrtLogD("System's current day : %d", (t->tm_mday)); t = localtime(¬Before); - LogDebug("Author certificate's notBefore Year : " << t->tm_year + 1900); - LogDebug("Author certificate's notBefore month : " << t->tm_mon + 1); - LogDebug("Author certificate's notBefore day : " << t->tm_mday); + WrtLogD("Author certificate's notBefore Year : %d", (t->tm_year + 1900)); + WrtLogD("Author certificate's notBefore month : %d", (t->tm_mon + 1)); + WrtLogD("Author certificate's notBefore day : %d", (t->tm_mday)); context.validationTime = notBefore + TIMET_DAY; t = localtime(&context.validationTime); - LogDebug("Modified current Year : " << t->tm_year + 1900); - LogDebug("Modified current notBefore month : " << t->tm_mon + 1); - LogDebug("Modified current notBefore day : " << t->tm_mday); + WrtLogD("Modified current Year : %d", (t->tm_year + 1900)); + WrtLogD("Modified current notBefore month : %d", (t->tm_mon + 1)); + WrtLogD("Modified current notBefore day : %d", (t->tm_mday)); } } #endif @@ -399,22 +405,26 @@ WrtSignatureValidator::Result ImplTizen::check( //context.allowBrokenChain = true; // end - if (XmlSec::NO_ERROR != XmlSecSingleton::Instance().validate(&context)) { - LogWarning("Installation break - invalid package!"); - return WrtSignatureValidator::SIGNATURE_INVALID; - } + if (!data.isAuthorSignature()) + { + if (XmlSec::NO_ERROR != XmlSecSingleton::Instance().validate(&context)) { + WrtLogW("Installation break - invalid package!"); + return WrtSignatureValidator::SIGNATURE_INVALID_HASH_SIGNATURE;//SIGNATURE_INVALID; + } - data.setReference(context.referenceSet); + data.setReference(context.referenceSet); - if (!checkObjectReferences(data)) { - return WrtSignatureValidator::SIGNATURE_INVALID; - } + if (!checkObjectReferences(data)) { + WrtLogW("Failed to check Object References"); + return WrtSignatureValidator::SIGNATURE_INVALID_HASH_SIGNATURE;//SIGNATURE_INVALID; + } - ReferenceValidator fileValidator(widgetContentPath); - if (ReferenceValidator::NO_ERROR != fileValidator.checkReferences(data)) { - LogWarning("Invalid package - file references broken"); - return WrtSignatureValidator::SIGNATURE_INVALID; - } + ReferenceValidator fileValidator(widgetContentPath); + if (ReferenceValidator::NO_ERROR != fileValidator.checkReferences(data)) { + WrtLogW("Invalid package - file references broken"); + return WrtSignatureValidator::SIGNATURE_INVALID_NO_HASH_FILE;//SIGNATURE_INVALID; + } + } #ifdef TIZEN_FEATURE_CERT_SVC_OCSP_CRL // It is good time to do OCSP check @@ -426,8 +436,8 @@ WrtSignatureValidator::Result ImplTizen::check( coll.load(sortedCertificateList); if (!coll.sort()) { - LogDebug("Collection does not contain chain!"); - return WrtSignatureValidator::SIGNATURE_INVALID; + WrtLogD("Collection does not contain chain!"); + return WrtSignatureValidator::SIGNATURE_INVALID_CERT_CHAIN;//SIGNATURE_INVALID; } CertificateVerifier verificator(m_ocspEnable, m_crlEnable); @@ -440,23 +450,23 @@ WrtSignatureValidator::Result ImplTizen::check( if (result == VERIFICATION_STATUS_UNKNOWN || result == VERIFICATION_STATUS_ERROR) { - #ifdef _OCSP_POLICY_DISREGARD_UNKNOWN_OR_ERROR_CERTS_ +#ifdef _OCSP_POLICY_DISREGARD_UNKNOWN_OR_ERROR_CERTS_ disregard = true; - #endif +#endif } } #endif if (disregard) { - LogWarning("Signature is disregard. RootCA is not a member of Tizen"); - return WrtSignatureValidator::SIGNATURE_DISREGARD; + WrtLogW("Signature is disregard. RootCA is not a member of Tizen"); + return WrtSignatureValidator::SIGNATURE_INVALID_DISTRIBUTOR_CERT;//SIGNATURE_DISREGARD; } return WrtSignatureValidator::SIGNATURE_VERIFIED; } class ImplWac : public WrtSignatureValidator::Impl { - public: +public: WrtSignatureValidator::Result check(SignatureData &data, const std::string &widgetContentPath); @@ -490,13 +500,13 @@ WrtSignatureValidator::Result ImplWac::check( // First step - sort certificate if (!collection.sort()) { - LogWarning("Certificates do not form valid chain."); + WrtLogW("Certificates do not form valid chain."); return WrtSignatureValidator::SIGNATURE_INVALID; } // Check for error if (collection.empty()) { - LogWarning("Certificate list in signature is empty."); + WrtLogW("Certificate list in signature is empty."); return WrtSignatureValidator::SIGNATURE_INVALID; } @@ -512,50 +522,44 @@ WrtSignatureValidator::Result ImplWac::check( // Is Root CA certificate trusted? CertStoreId::Set storeIdSet = createCertificateIdentifier().find(root); - LogDebug("Is root certificate from TIZEN_DEVELOPER domain: " - << storeIdSet.contains(CertStoreId::TIZEN_DEVELOPER)); - LogDebug("Is root certificate from TIZEN_TEST domain: " - << storeIdSet.contains(CertStoreId::TIZEN_TEST)); - LogDebug("Is root certificate from TIZEN_VERIFY domain: " - << storeIdSet.contains(CertStoreId::TIZEN_VERIFY)); - LogDebug("Is root certificate from TIZEN_PUBLIC domain: " - << storeIdSet.contains(CertStoreId::VIS_PUBLIC)); - LogDebug("Is root certificate from TIZEN_PARTNER domain: " - << storeIdSet.contains(CertStoreId::VIS_PARTNER)); - LogDebug("Is root certificate from TIZEN_PLATFORM domain: " - << storeIdSet.contains(CertStoreId::VIS_PLATFORM)); - - LogDebug("Visibility level is public : " - << storeIdSet.contains(CertStoreId::VIS_PUBLIC)); - LogDebug("Visibility level is partner : " - << storeIdSet.contains(CertStoreId::VIS_PARTNER)); - LogDebug("Visibility level is platform : " - << storeIdSet.contains(CertStoreId::VIS_PLATFORM)); + WrtLogD("Is root certificate from TIZEN_DEVELOPER domain: %d", storeIdSet.contains(CertStoreId::TIZEN_DEVELOPER)); + WrtLogD("Is root certificate from TIZEN_TEST domain: %d", storeIdSet.contains(CertStoreId::TIZEN_TEST)); + WrtLogD("Is root certificate from TIZEN_VERIFY domain: %d", storeIdSet.contains(CertStoreId::TIZEN_VERIFY)); + WrtLogD("Is root certificate from TIZEN_PUBLIC domain: %d", storeIdSet.contains(CertStoreId::VIS_PUBLIC)); + WrtLogD("Is root certificate from TIZEN_PARTNER domain: %d", storeIdSet.contains(CertStoreId::VIS_PARTNER)); + WrtLogD("Is root certificate from TIZEN_PLATFORM domain: %d", storeIdSet.contains(CertStoreId::VIS_PLATFORM)); + + WrtLogD("Visibility level is public : %d", storeIdSet.contains(CertStoreId::VIS_PUBLIC)); + WrtLogD("Visibility level is partner : %d", storeIdSet.contains(CertStoreId::VIS_PARTNER)); + WrtLogD("Visibility level is platform : %d", storeIdSet.contains(CertStoreId::VIS_PLATFORM)); if (data.isAuthorSignature()) { if (!storeIdSet.contains(CertStoreId::TIZEN_DEVELOPER)) { - LogWarning("author-signature.xml has got unrecognized Root CA " - "certificate. Signature will be disregarded."); - disregard = true; + WrtLogW("author-signature.xml has got unrecognized Root CA " + "certificate. Signature will be disregarded."); + disregard = true; } - LogDebug("Root CA for author signature is correct."); } else { - LogDebug("signaturefile name = " << data.getSignatureFileName().c_str()); - //Additional Check for certificate registration + if (storeIdSet.contains(CertStoreId::TIZEN_DEVELOPER)) + { + WrtLogW("distributor has author level siganture! Signature will be disregarded."); + return WrtSignatureValidator::SIGNATURE_INVALID; + } + WrtLogD("signaturefile name = %s", data.getSignatureFileName().c_str()); if (data.getSignatureNumber() == 1) { if (storeIdSet.contains(CertStoreId::VIS_PUBLIC) || storeIdSet.contains(CertStoreId::VIS_PARTNER) || storeIdSet.contains(CertStoreId::VIS_PLATFORM)) { - LogDebug("Root CA for signature1.xml is correct."); + WrtLogD("Root CA for signature1.xml is correct."); } else { - LogWarning("signature1.xml has got unrecognized Root CA " + WrtLogW("signature1.xml has got unrecognized Root CA " "certificate. Signature will be disregarded."); disregard = true; } @@ -575,7 +579,7 @@ WrtSignatureValidator::Result ImplWac::check( // If the end certificate is not ROOT CA we should disregard signature // but still signature must be valid... Aaaaaa it's so stupid... if (!(root->isSignedBy(root))) { - LogWarning("Root CA certificate not found. Chain is incomplete."); + WrtLogW("Root CA certificate not found. Chain is incomplete."); // context.allowBrokenChain = true; } @@ -595,26 +599,28 @@ WrtSignatureValidator::Result ImplWac::check( char msg[1024]; t = localtime(&nowTime); + if (!t) + return WrtSignatureValidator::SIGNATURE_INVALID_CERT_TIME; memset(&tc, 0, sizeof(tc)); snprintf(msg, sizeof(msg), "Year: %d, month: %d, day : %d", t->tm_year + 1900, t->tm_mon + 1,t->tm_mday ); - LogDebug("## System's currentTime : " << msg); + WrtLogD("## System's currentTime : %s", msg); fprintf(stderr, "## System's currentTime : %s\n", msg); tb = _ASN1_GetTimeT(notBeforeTime); snprintf(msg, sizeof(msg), "Year: %d, month: %d, day : %d", tb.tm_year + 1900, tb.tm_mon + 1,tb.tm_mday ); - LogDebug("## certificate's notBeforeTime : " << msg); + WrtLogD("## certificate's notBeforeTime : %s", msg); fprintf(stderr, "## certificate's notBeforeTime : %s\n", msg); ta = _ASN1_GetTimeT(notAfterTime); snprintf(msg, sizeof(msg), "Year: %d, month: %d, day : %d", ta.tm_year + 1900, ta.tm_mon + 1,ta.tm_mday ); - LogDebug("## certificate's notAfterTime : " << msg); + WrtLogD("## certificate's notAfterTime : %s", msg); fprintf(stderr, "## certificate's notAfterTime : %s\n", msg); if (storeIdSet.contains(CertStoreId::TIZEN_VERIFY)) { - LogDebug("## TIZEN_VERIFY : check certificate Time : FALSE"); + WrtLogD("## TIZEN_VERIFY : check certificate Time : FALSE"); fprintf(stderr, "## TIZEN_VERIFY : check certificate Time : FALSE\n"); return WrtSignatureValidator::SIGNATURE_INVALID; } @@ -623,16 +629,16 @@ WrtSignatureValidator::Result ImplWac::check( if(year == 0) { - tc.tm_year = tb.tm_year; + tc.tm_year = tb.tm_year; tc.tm_mon = tb.tm_mon + 1; tc.tm_mday = tb.tm_mday; if(tc.tm_mon == 12) { - tc.tm_year = ta.tm_year; + tc.tm_year = ta.tm_year; tc.tm_mon = ta.tm_mon - 1; tc.tm_mday = ta.tm_mday; - + if(tc.tm_mon < 0) { tc.tm_year = ta.tm_year; @@ -641,21 +647,21 @@ WrtSignatureValidator::Result ImplWac::check( if(tc.tm_mday == 0) { - tc.tm_year = tb.tm_year; + tc.tm_year = tb.tm_year; tc.tm_mon = tb.tm_mon; tc.tm_mday = tb.tm_mday +1; } } - } + } } else{ tc.tm_year = tb.tm_year + year; tc.tm_mon = (tb.tm_mon + ta.tm_mon )/2; - tc.tm_mday = (tb.tm_mday + ta.tm_mday)/2; + tc.tm_mday = (tb.tm_mday + ta.tm_mday)/2; } snprintf(msg, sizeof(msg), "Year: %d, month: %d, day : %d", tc.tm_year + 1900, tc.tm_mon + 1,tc.tm_mday ); - LogDebug("## cmp cert with validation time : " << msg); + WrtLogD("## cmp cert with validation time : %s", msg); fprintf(stderr, "## cmp cert with validation time : %s\n", msg); time_t outCurrent = mktime(&tc); @@ -664,7 +670,7 @@ WrtSignatureValidator::Result ImplWac::check( context.validationTime = outCurrent; //return WrtSignatureValidator::SIGNATURE_INVALID; - } + } #endif @@ -681,49 +687,53 @@ WrtSignatureValidator::Result ImplWac::check( if (notAfter < nowTime) { context.validationTime = notAfter - TIMET_DAY; - LogWarning("Author certificate is expired. notAfter..."); + WrtLogW("Author certificate is expired. notAfter..."); } */ if (notBefore > nowTime) { - LogWarning("Author certificate is expired. notBefore time is greater than system-time."); + WrtLogW("Author certificate is expired. notBefore time is greater than system-time."); t = localtime(&nowTime); - LogDebug("System's current Year : " << t->tm_year + 1900); - LogDebug("System's current month : " << t->tm_mon + 1); - LogDebug("System's current day : " << t->tm_mday); + WrtLogD("System's current Year : %d", (t->tm_year + 1900)); + WrtLogD("System's current month : %d", (t->tm_mon + 1)); + WrtLogD("System's current day : %d", (t->tm_mday)); t = localtime(¬Before); - LogDebug("Author certificate's notBefore Year : " << t->tm_year + 1900); - LogDebug("Author certificate's notBefore month : " << t->tm_mon + 1); - LogDebug("Author certificate's notBefore day : " << t->tm_mday); + WrtLogD("Author certificate's notBefore Year : %d", (t->tm_year + 1900)); + WrtLogD("Author certificate's notBefore month : %d", (t->tm_mon + 1)); + WrtLogD("Author certificate's notBefore day : %d", (t->tm_mday)); context.validationTime = notBefore + TIMET_DAY; t = localtime(&context.validationTime); - LogDebug("Modified current Year : " << t->tm_year + 1900); - LogDebug("Modified current notBefore month : " << t->tm_mon + 1); - LogDebug("Modified current notBefore day : " << t->tm_mday); + WrtLogD("Modified current Year : %d", (t->tm_year + 1900)); + WrtLogD("Modified current notBefore month : %d", (t->tm_mon + 1)); + WrtLogD("Modified current notBefore day : %d", (t->tm_mday)); } } #endif - if (XmlSec::NO_ERROR != XmlSecSingleton::Instance().validate(&context)) { - LogWarning("Installation break - invalid package!"); - return WrtSignatureValidator::SIGNATURE_INVALID; - } - data.setReference(context.referenceSet); + if (!data.isAuthorSignature()) + { + if (XmlSec::NO_ERROR != XmlSecSingleton::Instance().validate(&context)) { + WrtLogW("Installation break - invalid package!"); + return WrtSignatureValidator::SIGNATURE_INVALID; + } - if (!checkObjectReferences(data)) { - return WrtSignatureValidator::SIGNATURE_INVALID; - } + data.setReference(context.referenceSet); - ReferenceValidator fileValidator(widgetContentPath); - if (ReferenceValidator::NO_ERROR != fileValidator.checkReferences(data)) { - LogWarning("Invalid package - file references broken"); - return WrtSignatureValidator::SIGNATURE_INVALID; - } + if (!checkObjectReferences(data)) { + return WrtSignatureValidator::SIGNATURE_INVALID; + } + + ReferenceValidator fileValidator(widgetContentPath); + if (ReferenceValidator::NO_ERROR != fileValidator.checkReferences(data)) { + WrtLogW("Invalid package - file references broken"); + return WrtSignatureValidator::SIGNATURE_INVALID; + } + } #ifdef TIZEN_FEATURE_CERT_SVC_OCSP_CRL // It is good time to do OCSP check @@ -735,7 +745,7 @@ WrtSignatureValidator::Result ImplWac::check( coll.load(sortedCertificateList); if (!coll.sort()) { - LogDebug("Collection does not contain chain!"); + WrtLogD("Collection does not contain chain!"); return WrtSignatureValidator::SIGNATURE_INVALID; } @@ -757,7 +767,7 @@ WrtSignatureValidator::Result ImplWac::check( #endif if (disregard) { - LogWarning("Signature is disregard. RootCA is not a member of Tizen."); + WrtLogW("Signature is disregard. RootCA is not a member of Tizen."); return WrtSignatureValidator::SIGNATURE_DISREGARD; } return WrtSignatureValidator::SIGNATURE_VERIFIED; @@ -778,7 +788,8 @@ WrtSignatureValidator::WrtSignatureValidator( m_impl = new ImplWac(ocspEnable,crlEnable,complianceMode); } -WrtSignatureValidator::~WrtSignatureValidator() { +WrtSignatureValidator::~WrtSignatureValidator() +{ delete m_impl; } diff --git a/vcore/src/vcore/WrtSignatureValidator.h b/vcore/src/vcore/WrtSignatureValidator.h index 5ff8752..04a8434 100644 --- a/vcore/src/vcore/WrtSignatureValidator.h +++ b/vcore/src/vcore/WrtSignatureValidator.h @@ -24,14 +24,13 @@ #include <string> -#include <dpl/noncopyable.h> - #include <vcore/SignatureData.h> namespace ValidationCore { -class WrtSignatureValidator : public DPL::Noncopyable { +class WrtSignatureValidator { public: + class Impl; enum AppType @@ -46,9 +45,22 @@ public: SIGNATURE_INVALID, SIGNATURE_VERIFIED, SIGNATURE_DISREGARD, // no ocsp response or ocsp return unknown status - SIGNATURE_REVOKED + SIGNATURE_REVOKED, + SIGNATURE_INVALID_CERT_CHAIN, //5, from here, new error enum + SIGNATURE_INVALID_DISTRIBUTOR_CERT, + SIGNATURE_INVALID_SDK_DEFAULT_AUTHOR_CERT, + SIGNATURE_IN_DISTRIBUTOR_CASE_AUTHOR_CERT, + SIGNATURE_INVALID_CERT_TIME, + SIGNATURE_NO_DEVICE_PROFILE, + SIGNATURE_INVALID_DEVICE_UNIQUE_ID, + SIGNATURE_INVALID_NO_HASH_FILE, + SIGNATURE_INVALID_HASH_SIGNATURE }; + WrtSignatureValidator() = delete; + WrtSignatureValidator(const WrtSignatureValidator &) = delete; + const WrtSignatureValidator &operator=(const WrtSignatureValidator &) = delete; + explicit WrtSignatureValidator( AppType appType, bool ocspEnable, @@ -63,6 +75,7 @@ public: private: Impl *m_impl; + }; } // namespace ValidationCore diff --git a/vcore/src/vcore/XmlsecAdapter.cpp b/vcore/src/vcore/XmlsecAdapter.cpp index c1d4529..93fc498 100644 --- a/vcore/src/vcore/XmlsecAdapter.cpp +++ b/vcore/src/vcore/XmlsecAdapter.cpp @@ -39,7 +39,7 @@ #include <xmlsec/errors.h> #include <dpl/assert.h> -#include <dpl/log/log.h> +#include <dpl/log/wrt_log.h> #include <vcore/XmlsecAdapter.h> @@ -78,7 +78,7 @@ void* XmlSec::fileOpenCallback(const char *filename) { std::string path = s_prefixPath + filename; - // LogDebug("Xmlsec opening: " << path); + // WrtLogD("Xmlsec opening: %s", path); return new FileWrapper(xmlFileOpen(path.c_str()),false); } @@ -100,7 +100,7 @@ int XmlSec::fileReadCallback(void *context, int XmlSec::fileCloseCallback(void *context) { - //LogDebug("Xmlsec closing: "); + //WrtLogD("Xmlsec closing: "); FileWrapper *fw = static_cast<FileWrapper*>(context); int output = 0; if (!(fw->released)) { @@ -126,21 +126,21 @@ void XmlSec::fileExtractPrefix(XmlSecContext *context) } } -void LogDebugPrint(const char* file, int line, const char* func, - const char* errorObject, const char* errorSubject, +void LogDebugPrint(const char* file, int line, const char* func, + const char* errorObject, const char* errorSubject, int reason, const char* msg) { char total[1024]; - snprintf(total, sizeof(total), "[%s(%d)] : [%s] : [%s] : [%s]", func, line, errorObject, errorSubject, msg); + snprintf(total, sizeof(total), "[%s:%d][%s] : [%s] : [%s] : [%s]", file, line, func, errorObject, errorSubject, msg); if(reason != 256) { fprintf(stderr, "## [validate error]: %s\n", total); - LogError(" " << total); + WrtLogE(" %s", total); } else { - LogDebug(" " << total); + WrtLogD(" %s", total); } } @@ -158,13 +158,13 @@ XmlSec::XmlSec() : #endif if (xmlSecInit() < 0) { - LogError("Xmlsec initialization failed."); + WrtLogE("Xmlsec initialization failed."); ThrowMsg(Exception::InternalError, "Xmlsec initialization failed."); } if (xmlSecCheckVersion() != 1) { xmlSecShutdown(); - LogError("Loaded xmlsec library version is not compatible."); + WrtLogE("Loaded xmlsec library version is not compatible."); ThrowMsg(Exception::InternalError, "Loaded xmlsec library version is not compatible."); } @@ -172,7 +172,7 @@ XmlSec::XmlSec() : #ifdef XMLSEC_CRYPTO_DYNAMIC_LOADING if (xmlSecCryptoDLLoadLibrary(BAD_CAST XMLSEC_CRYPTO) < 0) { xmlSecShutdown(); - LogError( + WrtLogE( "Error: unable to load default xmlsec-crypto library. Make sure " "that you have it installed and check shared libraries path " "(LD_LIBRARY_PATH) envornment variable."); @@ -183,14 +183,14 @@ XmlSec::XmlSec() : if (xmlSecCryptoAppInit(NULL) < 0) { xmlSecShutdown(); - LogError("Crypto initialization failed."); + WrtLogE("Crypto initialization failed."); ThrowMsg(Exception::InternalError, "Crypto initialization failed."); } if (xmlSecCryptoInit() < 0) { xmlSecCryptoAppShutdown(); xmlSecShutdown(); - LogError("Xmlsec-crypto initialization failed."); + WrtLogE("Xmlsec-crypto initialization failed."); ThrowMsg(Exception::InternalError, "Xmlsec-crypto initialization failed."); } @@ -238,7 +238,7 @@ XmlSec::Result XmlSec::validateFile(XmlSecContext *context, int size, res = -1; fileExtractPrefix(context); - LogDebug("Prefix path: " << s_prefixPath); + WrtLogD("Prefix path: %s", s_prefixPath.c_str()); xmlSecIOCleanupCallbacks(); @@ -251,7 +251,7 @@ XmlSec::Result XmlSec::validateFile(XmlSecContext *context, /* load file */ doc = xmlParseFile(context->signatureFile.c_str()); if ((doc == NULL) || (xmlDocGetRootElement(doc) == NULL)) { - LogWarning("Unable to parse file " << context->signatureFile); + WrtLogW("Unable to parse file %s", (context->signatureFile).c_str()); goto done; } @@ -259,14 +259,14 @@ XmlSec::Result XmlSec::validateFile(XmlSecContext *context, node = xmlSecFindNode(xmlDocGetRootElement( doc), xmlSecNodeSignature, xmlSecDSigNs); if (node == NULL) { - LogWarning("Start node not found in " << context->signatureFile); + WrtLogW("Start node not found in %s", (context->signatureFile).c_str()); goto done; } /* create signature context */ dsigCtx = xmlSecDSigCtxCreate(mngr); if (dsigCtx == NULL) { - LogError("Failed to create signature context."); + WrtLogE("Failed to create signature context."); goto done; } @@ -276,14 +276,14 @@ XmlSec::Result XmlSec::validateFile(XmlSecContext *context, } if (context->validationTime) { - LogDebug("Setting validation time."); + WrtLogD("Setting validation time."); dsigCtx->keyInfoReadCtx.certsVerificationTime = context->validationTime; } if( m_noHash == true || m_partialHash == true ) { - LogDebug("SignatureEx start >> "); + WrtLogD("SignatureEx start >> "); if( m_pList == NULL ) { - LogWarning("## [validate]: uriList does not exist" ); + WrtLogW("## [validate]: uriList does not exist" ); fprintf(stderr, "## [validate]: uriList does not exist\n"); res = xmlSecDSigCtxVerifyEx(dsigCtx, node, 1, NULL); } else { @@ -292,7 +292,7 @@ XmlSec::Result XmlSec::validateFile(XmlSecContext *context, if(m_pList == NULL) { - LogWarning("## [validate]: uriList does not exist" ); + WrtLogW("## [validate]: uriList does not exist" ); fprintf(stderr, "## [validate]: uriList does not exist\n"); res = -1; goto done; @@ -300,7 +300,7 @@ XmlSec::Result XmlSec::validateFile(XmlSecContext *context, n = m_pList->size(); - char* pList[n]; + char* pList[n + 1]; std::list<std::string>::const_iterator itr = m_pList->begin(); std::string tmpString; char* uri = NULL; @@ -327,17 +327,17 @@ XmlSec::Result XmlSec::validateFile(XmlSecContext *context, } if(res < 0) { - LogError("SignatureEx verify error."); + WrtLogE("SignatureEx verify error."); fprintf(stderr, "## [validate error]: SignatureEx verify error\n"); res = -1; goto done; } } else { - LogDebug("Signature start >> "); + WrtLogD("Signature start >> "); /* Verify signature */ if (xmlSecDSigCtxVerify(dsigCtx, node) < 0) { - LogError("Signature verify error."); + WrtLogE("Signature verify error."); fprintf(stderr, "## [validate error]: Signature verify error\n"); res = -1; goto done; @@ -346,25 +346,24 @@ XmlSec::Result XmlSec::validateFile(XmlSecContext *context, if (dsigCtx->keyInfoReadCtx.flags2 & XMLSEC_KEYINFO_ERROR_FLAGS_BROKEN_CHAIN) { - LogWarning("XMLSEC_KEYINFO_FLAGS_ALLOW_BROKEN_CHAIN was set to true!"); - LogWarning("Signature contains broken chain!"); + WrtLogW("XMLSEC_KEYINFO_FLAGS_ALLOW_BROKEN_CHAIN was set to true!"); + WrtLogW("Signature contains broken chain!"); context->errorBrokenChain = true; } /* print verification result to stdout */ if (dsigCtx->status == xmlSecDSigStatusSucceeded) { - LogDebug("Signature is OK"); + WrtLogD("Signature is OK"); res = 0; } else { - LogDebug("Signature is INVALID"); + WrtLogD("Signature is INVALID"); res = -1; goto done; } if (dsigCtx->c14nMethod && dsigCtx->c14nMethod->id && dsigCtx->c14nMethod->id->name) { - // LogInfo("Canonicalization method: " << - // reinterpret_cast<const char *>(dsigCtx->c14nMethod->id->name)); + // WrtLogI("Canonicalization method: %s", (reinterpret_cast<const char *>(dsigCtx->c14nMethod->id->name)).c_str()); } size = xmlSecPtrListGetSize(&(dsigCtx->signedInfoReferences)); @@ -380,12 +379,9 @@ XmlSec::Result XmlSec::validateFile(XmlSecContext *context, reinterpret_cast<const char *>(dsigRefCtx->digestMethod->id ->name); std::string strDigest(pDigest); - /*LogInfo("reference digest method: " << - reinterpret_cast<const char *>(dsigRefCtx->digestMethod - ->id - ->name));*/ + /*WrtLogI("reference digest method: %s" (reinterpret_cast<const char *>(dsigRefCtx->digestMethod->id->name)).c_str());*/ if (strDigest == DIGEST_MD5) { - LogWarning("MD5 digest method used! Please use sha"); + WrtLogW("MD5 digest method used! Please use sha"); res = -1; break; } @@ -422,7 +418,7 @@ void XmlSec::loadDERCertificateMemory(XmlSecContext *context, int size = i2d_X509(context->certificatePtr->getX509(), &derCertificate); if (!derCertificate) { - LogError("Failed during x509 conversion to der format."); + WrtLogE("Failed during x509 conversion to der format."); ThrowMsg(Exception::InternalError, "Failed during x509 conversion to der format."); } @@ -433,7 +429,7 @@ void XmlSec::loadDERCertificateMemory(XmlSecContext *context, xmlSecKeyDataFormatDer, xmlSecKeyDataTypeTrusted) < 0) { OPENSSL_free(derCertificate); - LogError("Failed to load der certificate from memory."); + WrtLogE("Failed to load der certificate from memory."); ThrowMsg(Exception::InternalError, "Failed to load der certificate from memory."); } @@ -448,7 +444,7 @@ void XmlSec::loadPEMCertificateFile(XmlSecContext *context, context->certificatePath.c_str(), xmlSecKeyDataFormatPem, xmlSecKeyDataTypeTrusted) < 0) { - LogError("Failed to load PEM certificate from file."); + WrtLogE("Failed to load PEM certificate from file."); ThrowMsg(Exception::InternalError, "Failed to load PEM certificate from file."); } @@ -463,19 +459,19 @@ XmlSec::Result XmlSec::validate(XmlSecContext *context) xmlSecErrorsSetCallback(LogDebugPrint); if (!m_initialized) { - LogError("XmlSec is not initialized."); + WrtLogE("XmlSec is not initialized."); ThrowMsg(Exception::InternalError, "XmlSec is not initialized"); } AutoPtr<xmlSecKeysMngr> mngr(xmlSecKeysMngrCreate()); if (!mngr.get()) { - LogError("Failed to create keys manager."); + WrtLogE("Failed to create keys manager."); ThrowMsg(Exception::InternalError, "Failed to create keys manager."); } if (xmlSecCryptoAppDefaultKeysMngrInit(mngr.get()) < 0) { - LogError("Failed to initialize keys manager."); + WrtLogE("Failed to initialize keys manager."); ThrowMsg(Exception::InternalError, "Failed to initialize keys manager."); } context->referenceSet.clear(); diff --git a/vcore/src/vcore/XmlsecAdapter.h b/vcore/src/vcore/XmlsecAdapter.h index 3deba63..3c8d94f 100644 --- a/vcore/src/vcore/XmlsecAdapter.h +++ b/vcore/src/vcore/XmlsecAdapter.h @@ -32,7 +32,7 @@ #include <vcore/SignatureData.h> namespace ValidationCore { -class XmlSec : public DPL::Noncopyable +class XmlSec : public VcoreDPL::Noncopyable { public: @@ -97,7 +97,7 @@ class XmlSec : public DPL::Noncopyable class Exception { public: - DECLARE_EXCEPTION_TYPE(DPL::Exception, Base) + DECLARE_EXCEPTION_TYPE(VcoreDPL::Exception, Base) DECLARE_EXCEPTION_TYPE(Base, InternalError) }; @@ -137,7 +137,7 @@ class XmlSec : public DPL::Noncopyable static void fileExtractPrefix(XmlSecContext *context); }; -typedef DPL::Singleton<XmlSec> XmlSecSingleton; +typedef VcoreDPL::Singleton<XmlSec> XmlSecSingleton; } // namespace ValidationCore diff --git a/vcore/src/vcore/api.cpp b/vcore/src/vcore/api.cpp index 34ee76b..cb6797f 100644 --- a/vcore/src/vcore/api.cpp +++ b/vcore/src/vcore/api.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -45,15 +45,12 @@ #include <openssl/evp.h> #include <openssl/bio.h> -#include <dlog.h> - #include <dpl/foreach.h> -#include <dpl/log/log.h> +#include <dpl/log/wrt_log.h> #include <cert-svc/cinstance.h> #include <cert-svc/ccert.h> #include <cert-svc/cpkcs12.h> -#include <cert-svc/cpkcs12.h> #include <cert-svc/cprimitives.h> #include <vcore/Base64.h> @@ -61,7 +58,7 @@ #include <vcore/CertificateCollection.h> #include <vcore/pkcs12.h> -#ifdef TIZEN_FEATURE_CERT_SVC_OCSP_CRL +#ifdef TIZEN_FEATURE_CERT_SVC_OCSP_CRL #include <cert-svc/ccrl.h> #include <cert-svc/cocsp.h> #include <vcore/OCSP.h> @@ -72,7 +69,15 @@ #include <libxml/parser.h> #include <libxml/tree.h> +#define START_CERT "-----BEGIN CERTIFICATE-----" +#define END_CERT "-----END CERTIFICATE-----" +#define START_TRUSTED "-----BEGIN TRUSTED CERTIFICATE-----" +#define END_TRUSTED "-----END TRUSTED CERTIFICATE-----" + +#ifndef LOG_TAG #define LOG_TAG "CERT_SVC" +#endif + using namespace ValidationCore; namespace { @@ -243,15 +248,14 @@ public: } auto certPtr = iter->second; - - DPL::String result; - switch(field) { + std::string result; + switch (field) { case CERTSVC_SUBJECT: result = certPtr->getOneLine(); break; case CERTSVC_ISSUER: result = certPtr->getOneLine(Certificate::FIELD_ISSUER); - break; + break; case CERTSVC_SUBJECT_COMMON_NAME: result = certPtr->getCommonName(); break; @@ -283,12 +287,12 @@ public: result = certPtr->getOrganizationalUnitName(Certificate::FIELD_ISSUER); break; case CERTSVC_VERSION: - { - std::stringstream stream; - stream << (certPtr->getVersion()+1); - result = DPL::FromUTF8String(stream.str()); - break; - } + { + std::stringstream stream; + stream << (certPtr->getVersion()+1); + result = stream.str(); + break; + } case CERTSVC_SERIAL_NUMBER: result = certPtr->getSerialNumberString(); break; @@ -311,9 +315,8 @@ public: buffer->privateInstance = cert.privateInstance; return CERTSVC_SUCCESS; } - std::string output = DPL::ToUTF8String(result); - char *cstring = new char[output.size()+1]; + char *cstring = new char[result.size()+1]; if (cstring == NULL) { buffer->privateHandler = NULL; buffer->privateLength = 0; @@ -321,10 +324,10 @@ public: return CERTSVC_BAD_ALLOC; } - strncpy(cstring, output.c_str(), output.size()+1); + strncpy(cstring, result.c_str(), result.size()+1); buffer->privateHandler = cstring; - buffer->privateLength = output.size(); + buffer->privateLength = result.size(); buffer->privateInstance = cert.privateInstance; m_allocatedStringSet.insert(cstring); @@ -466,7 +469,7 @@ public: fieldId = SUBJECT_COMMONNAME; break; default: - LogError("Not implemented!"); + WrtLogE("Not implemented!"); return CERTSVC_WRONG_ARGUMENT; } @@ -474,16 +477,16 @@ public: cert_svc_cert_context_final); if (ctx.get() == NULL) { - LogWarning("Error in cert_svc_cert_context_init."); + WrtLogW("Error in cert_svc_cert_context_init."); return CERTSVC_FAIL; } - LogDebug("Match string: " << value); + WrtLogD("Match string: %s", value); result = cert_svc_search_certificate(ctx.get(), fieldId, const_cast<char*>(value)); - LogDebug("Search finished!"); + WrtLogD("Search finished!"); if (CERT_SVC_ERR_NO_ERROR != result) { - LogWarning("Error during certificate search"); + WrtLogW("Error during certificate search"); return CERTSVC_FAIL; } @@ -498,7 +501,7 @@ public: ScopedCertCtx ctx2(cert_svc_cert_context_init(), cert_svc_cert_context_final); if (ctx2.get() == NULL) { - LogWarning("Error in cert_svc_cert_context_init."); + WrtLogW("Error in cert_svc_cert_context_init."); return CERTSVC_FAIL; } @@ -506,7 +509,7 @@ public: if (CERT_SVC_ERR_NO_ERROR != cert_svc_load_file_to_context(ctx2.get(), fileList->filename)) { - LogWarning("Error in cert_svc_load_file_to_context"); + WrtLogW("Error in cert_svc_load_file_to_context"); return CERTSVC_FAIL; } int certId = addCert(CertificatePtr(new Certificate(*(ctx2.get()->certBuf)))); @@ -980,34 +983,34 @@ public: int getVisibility(CertSvcCertificate certificate, int* visibility) { int ret = CERTSVC_FAIL; - xmlChar *xmlPathCertificateSet = (xmlChar*) "CertificateSet"; - xmlChar *xmlPathCertificateDomain = (xmlChar*) "CertificateDomain";// name=\"tizen-platform\""; + //xmlChar *xmlPathCertificateSet = (xmlChar*) "CertificateSet"; /*unused variable*/ + //xmlChar *xmlPathCertificateDomain = (xmlChar*) "CertificateDomain";// name=\"tizen-platform\""; /*unused variable*/ xmlChar *xmlPathDomainPlatform = (xmlChar*) "tizen-platform"; xmlChar *xmlPathDomainPublic = (xmlChar*) "tizen-public"; xmlChar *xmlPathDomainPartner = (xmlChar*) "tizen-partner"; xmlChar *xmlPathDomainDeveloper = (xmlChar*) "tizen-developer"; - xmlChar *xmlPathFingerPrintSHA1 = (xmlChar*) "FingerprintSHA1"; + //xmlChar *xmlPathFingerPrintSHA1 = (xmlChar*) "FingerprintSHA1"; /*unused variable*/ - CertificatePtr certPtr = m_certificateMap[0]; - if(certPtr == NULL) - { - LOGE("Invalid Parameter. certificate is not initialized"); + auto iter = m_certificateMap.find(certificate.privateHandler); + if (iter == m_certificateMap.end()) { return CERTSVC_FAIL; - } + } + CertificatePtr certPtr = iter->second; + std::string fingerprint = Certificate::FingerprintToColonHex(certPtr->getFingerprint(Certificate::FINGERPRINT_SHA1)); /* load file */ - xmlDocPtr doc = xmlParseFile(tzplatform_mkpath(TZ_SYS_SHARE, "ca-certificates/fingerprint/fingerprint_list.xml")); + xmlDocPtr doc = xmlParseFile(FINGERPRINT_LIST_PATH); if ((doc == NULL) || (xmlDocGetRootElement(doc) == NULL)) { - LOGE("Failed to prase fingerprint_list.xml\n"); + WrtLogE("Failed to prase fingerprint_list.xml"); return CERTSVC_IO_ERROR; } xmlNodePtr curPtr = xmlFirstElementChild(xmlDocGetRootElement(doc)); if(curPtr == NULL) { - LOGE("Can not find root"); + WrtLogE("Can not find root"); ret = CERTSVC_IO_ERROR; goto out; } @@ -1017,7 +1020,7 @@ public: xmlAttr* attr = curPtr->properties; if(!attr->children || !attr->children->content) { - LOGE("Failed to get fingerprints from list"); + WrtLogE("Failed to get fingerprints from list"); ret = CERTSVC_FAIL; goto out; } @@ -1026,18 +1029,18 @@ public: xmlNodePtr FpPtr = xmlFirstElementChild(curPtr); if(FpPtr == NULL) { - LOGE("Could not find fingerprint"); + WrtLogE("Could not find fingerprint"); ret = CERTSVC_FAIL; goto out; } - LOGD("Retrieve level : %s", strLevel); + WrtLogD("Retrieve level : %s", strLevel); while(FpPtr) { xmlChar *content = xmlNodeGetContent(FpPtr); if(xmlStrcmp(content, (xmlChar*)fingerprint.c_str()) == 0) { - LOGD("fingerprint : %s are %s", content, strLevel); + WrtLogD("fingerprint : %s are %s", content, strLevel); if(!xmlStrcmp(strLevel, xmlPathDomainPlatform)) { *visibility = CERTSVC_VISIBILITY_PLATFORM; @@ -1092,6 +1095,31 @@ out: return c_certsvc_pkcs12_import(path.privateHandler, pass.privateHandler, pfxIdString.privateHandler); } + inline int pkcsNameIsUniqueInStore( + CertStoreType storeType, + CertSvcString pfxIdString, + int *is_unique) + { + int result = c_certsvc_pkcs12_alias_exists_in_store(storeType, pfxIdString.privateHandler, is_unique); + return result; + } + + inline int getCertDetailFromStore(CertStoreType storeType, + CertSvcString gname, + char** certBuffer, + size_t* certSize) + { + return c_certsvc_pkcs12_get_certificate_buffer_from_store(storeType, gname.privateHandler, certBuffer, certSize); + } + + inline int pkcsDeleteCertFromStore( + CertStoreType storeType, + CertSvcString gname + ) + { + return c_certsvc_pkcs12_delete_certificate_from_store(storeType, gname.privateHandler); + } + inline int getPkcsIdList( CertSvcInstance &instance, CertSvcStringList *handler) @@ -1175,6 +1203,180 @@ out: return c_certsvc_pkcs12_delete(pfxIdString.privateHandler); } + inline int pkcsImportToStore( + CertStoreType storeType, + CertSvcString path, + CertSvcString pass, + CertSvcString pfxIdString) + { + return c_certsvc_pkcs12_import_from_file_to_store(storeType, path.privateHandler, pass.privateHandler, pfxIdString.privateHandler); + } + + inline int pkcsGetAliasNameForCertInStore(CertStoreType storeType, + CertSvcString gname, + char **alias) + { + return c_certsvc_pkcs12_get_certificate_alias_from_store(storeType, gname.privateHandler, alias); + } + + inline int pkcsSetCertStatusToStore(CertStoreType storeType, + int is_root_app, + CertSvcString gname, + CertStatus status) + { + return c_certsvc_pkcs12_set_certificate_status_to_store(storeType, is_root_app, gname.privateHandler, status); + } + + inline int pkcsGetCertStatusFromStore( + CertStoreType storeType, + CertSvcString gname, + int *status) + { + return c_certsvc_pkcs12_get_certificate_status_from_store(storeType, gname.privateHandler, status); + } + + inline int getCertFromStore(CertSvcInstance instance, + CertStoreType storeType, + char *gname, + CertSvcCertificate *certificate) + { + return certsvc_get_certificate(instance, storeType, gname, certificate); + } + + inline int freePkcsIdListFromStore( + CertSvcStoreCertList** certList) + { + return c_certsvc_pkcs12_free_aliases_loaded_from_store(certList); + } + + inline int getPkcsIdListFromStore( + CertStoreType storeType, + int is_root_app, + CertSvcStoreCertList** certList, + int* length) + { + return c_certsvc_pkcs12_get_certificate_list_from_store(storeType, is_root_app, certList, length); + } + + inline int getPkcsIdEndUserListFromStore( + CertStoreType storeType, + CertSvcStoreCertList** certList, + int* length) + { + return c_certsvc_pkcs12_get_end_user_certificate_list_from_store(storeType, certList, length); + } + + inline int getPkcsIdRootListFromStore( + CertStoreType storeType, + CertSvcStoreCertList** certList, + int* length) + { + return c_certsvc_pkcs12_get_root_certificate_list_from_store(storeType, certList, length); + } + + inline int getPkcsPrivateKeyFromStore( + CertStoreType storeType, + CertSvcString gname, + char **certBuffer, + size_t *certSize) + { + return c_certsvc_pkcs12_private_key_load_from_store(storeType, gname.privateHandler, certBuffer, certSize); + } + + inline int getPkcsCertificateListFromStore( + CertSvcInstance &instance, + CertStoreType storeType, + CertSvcString &pfxIdString, + CertSvcCertificateList *handler) + { + char **certs; + gsize i, ncerts; + std::vector<CertificatePtr> certPtrVector; + std::vector<int> listId; + char *certBuffer = NULL; + size_t certLength = 0; + CertSvcString Alias; + char* header = NULL; + char* trailer = NULL; + const char* headEnd = NULL; + const char* tailEnd = NULL; + int length = 0; + int result; + + result = c_certsvc_pkcs12_load_certificates_from_store(storeType, pfxIdString.privateHandler, &certs, &ncerts); + if (result != CERTSVC_SUCCESS) { + WrtLogE("Unable to load certificates from store."); + return result; + } + + for (i = 0; i < ncerts; i++) { + Alias.privateHandler = certs[i]; + Alias.privateLength = strlen(certs[i]); + result = certsvc_pkcs12_get_certificate_info_from_store(instance, storeType, Alias, &certBuffer, &certLength); + if (result != CERTSVC_SUCCESS || !certBuffer) { + WrtLogE("Failed to get certificate buffer."); + return CERTSVC_FAIL; + } + + header = strstr(certBuffer, START_CERT); + headEnd = START_CERT; + if (!header) { + // START_CERT not found. let's find START_TRUSTED. + header = strstr(certBuffer, START_TRUSTED); + headEnd = START_TRUSTED; + } + + if (header) { + // START_something found. let's find END_CERT first. + trailer = strstr(header, END_CERT); + tailEnd = END_CERT; + } + + if (!trailer) { + // END_CERT not found. let's find END_TRUSTED. + trailer = strstr(header, END_TRUSTED); + tailEnd = END_TRUSTED; + } + + if (!trailer) { + WrtLogE("Failed the get the certificate."); + return CERTSVC_FAIL; + } + + length = ((1 + strlen(header)) - (strlen(headEnd) + strlen(tailEnd) + 1)); + std::string tmpBuffer(certBuffer); + tmpBuffer = tmpBuffer.substr(strlen(headEnd),length); + std::string binary(tmpBuffer.c_str(), length); + Certificate::FormType formType = Certificate::FORM_BASE64; + certPtrVector.push_back(CertificatePtr(new Certificate(binary, formType))); + free(certBuffer); + certBuffer = NULL; + } + + if (ncerts > 0) + c_certsvc_pkcs12_free_certificates(certs); + + FOREACH(it, certPtrVector) { + listId.push_back(addCert(*it)); + } + + int position = m_idListCounter++; + m_idListMap[position] = listId; + + handler->privateInstance = instance; + handler->privateHandler = position; + + return result; + } + + inline bool checkValidStoreType(CertStoreType storeType) + { + if (storeType >= VPN_STORE && storeType <= ALL_STORE) + return true; + else + return false; + } + private: int m_certificateCounter; std::map<int, CertificatePtr> m_certificateMap; @@ -1186,7 +1388,7 @@ private: std::map<int, std::vector<std::string> > m_stringListMap; std::set<char *> m_allocatedStringSet; - + #ifdef TIZEN_FEATURE_CERT_SVC_OCSP_CRL CertSvcCrlCacheWrite m_crlWrite; CertSvcCrlCacheRead m_crlRead; @@ -1205,7 +1407,6 @@ int certsvc_instance_new(CertSvcInstance *instance) { if (init) { SSL_library_init(); // required by message verification OpenSSL_add_all_digests(); - g_type_init(); // required by libsoup/ocsp init = 0; } try { @@ -1488,14 +1689,14 @@ int certsvc_pkcs12_dup_evp_pkey( &size); if (result != CERTSVC_SUCCESS) { - LogError("Error in certsvc_pkcs12_private_key_dup"); + WrtLogE("Error in certsvc_pkcs12_private_key_dup"); return result; } BIO *b = BIO_new(BIO_s_mem()); if ((int)size != BIO_write(b, buffer, size)) { - LogError("Error in BIO_write"); + WrtLogE("Error in BIO_write"); BIO_free_all(b); certsvc_pkcs12_private_key_free(buffer); return CERTSVC_FAIL; @@ -1511,8 +1712,7 @@ int certsvc_pkcs12_dup_evp_pkey( return CERTSVC_SUCCESS; } - LogError("Result is null. Openssl REASON code is: " - << ERR_GET_REASON(ERR_peek_last_error())); + WrtLogE("Result is null. Openssl REASON code is: %d", ERR_GET_REASON(ERR_peek_last_error())); return CERTSVC_FAIL; } @@ -1691,7 +1891,7 @@ int certsvc_certificate_get_visibility(CertSvcCertificate certificate, int* visi return impl(certificate.privateInstance)->getVisibility(certificate, visibility); } catch (...) { - LOGE("exception occur"); + WrtLogE("exception occur"); } return CERTSVC_FAIL; } @@ -1717,6 +1917,368 @@ int certsvc_pkcs12_import_from_file(CertSvcInstance instance, return CERTSVC_FAIL; } +int certsvc_get_certificate(CertSvcInstance instance, + CertStoreType storeType, + char *gname, + CertSvcCertificate *certificate) +{ + int result = CERTSVC_SUCCESS; + char* certBuffer = NULL; + std::string fileName; + size_t length = 0; + FILE* fp_write = NULL; + BIO* pBio = NULL; + X509* x509Struct = NULL; + + try { + result = c_certsvc_pkcs12_get_certificate_buffer_from_store(storeType, gname, &certBuffer, &length); + if (result != CERTSVC_SUCCESS) { + WrtLogE("Failed to get certificate buffer from store."); + return result; + } + + pBio = BIO_new(BIO_s_mem()); + if (pBio == NULL) { + WrtLogE("Failed to allocate memory."); + result = CERTSVC_BAD_ALLOC; + } + + length = BIO_write(pBio, (const void*) certBuffer, length); + if (length < 1) { + WrtLogE("Failed to load cert into bio."); + result = CERTSVC_BAD_ALLOC; + } + + x509Struct = PEM_read_bio_X509(pBio, NULL, 0, NULL); + if (x509Struct != NULL) { + CertificatePtr cert(new Certificate(x509Struct)); + certificate->privateInstance = instance; + certificate->privateHandler = impl(instance)->addCert(cert); + if (certBuffer!=NULL) free(certBuffer); + } + else { + fileName.append(CERTSVC_PKCS12_STORAGE_DIR); + fileName.append(gname); + if (!(fp_write = fopen(fileName.c_str(), "w"))) { + WrtLogE("Failed to open the file for writing, [%s].", fileName.c_str()); + result = CERTSVC_FAIL; + goto error; + } + + if (fwrite(certBuffer, sizeof(char), (size_t)length, fp_write) != (size_t)length) { + WrtLogE("Fail to write certificate."); + result = CERTSVC_FAIL; + goto error; + } + + fclose(fp_write); + result = certsvc_certificate_new_from_file(instance, fileName.c_str(), certificate); + if (result != CERTSVC_SUCCESS) { + WrtLogE("Failed to construct certificate from buffer."); + goto error; + } + unlink(fileName.c_str()); + } + result = CERTSVC_SUCCESS; + } catch (std::bad_alloc &) { + return CERTSVC_BAD_ALLOC; + } catch (...) {} + +error: + if (x509Struct) X509_free(x509Struct); + if (pBio) BIO_free(pBio); + return result; +} + +int certsvc_pkcs12_check_alias_exists_in_store(CertSvcInstance instance, + CertStoreType storeType, + CertSvcString pfxIdString, + int *is_unique) +{ + if (pfxIdString.privateHandler == NULL || pfxIdString.privateLength<=0) { + WrtLogE("Invalid input parameter."); + return CERTSVC_WRONG_ARGUMENT; + } + + try { + if (!impl(instance)->checkValidStoreType(storeType)) { + WrtLogE("Invalid input parameter."); + return CERTSVC_INVALID_STORE_TYPE; + } + + return impl(instance)->pkcsNameIsUniqueInStore(storeType, pfxIdString, is_unique); + } catch (...) {} + return CERTSVC_FAIL; +} + +int certsvc_pkcs12_free_certificate_list_loaded_from_store(CertSvcInstance instance, + CertSvcStoreCertList** certList) +{ + if (*certList == NULL) { + WrtLogE("Invalid input parameter."); + return CERTSVC_WRONG_ARGUMENT; + } + + try { + return impl(instance)->freePkcsIdListFromStore(certList); + } catch (...) {} + return CERTSVC_FAIL; +} + +int certsvc_pkcs12_get_certificate_list_from_store(CertSvcInstance instance, + CertStoreType storeType, + int is_root_app, + CertSvcStoreCertList** certList, + int* length) +{ + if (*certList != NULL) { + WrtLogE("Invalid input parameter."); + return CERTSVC_WRONG_ARGUMENT; + } + + try { + if (!impl(instance)->checkValidStoreType(storeType)) { + WrtLogE("Invalid input parameter."); + return CERTSVC_INVALID_STORE_TYPE; + } + + return impl(instance)->getPkcsIdListFromStore(storeType, is_root_app, certList, length); + } catch (...) {} + + return CERTSVC_FAIL; +} + +int certsvc_pkcs12_get_end_user_certificate_list_from_store(CertSvcInstance instance, + CertStoreType storeType, + CertSvcStoreCertList** certList, + int* length) +{ + if (*certList != NULL) { + WrtLogE("Invalid input parameter."); + return CERTSVC_WRONG_ARGUMENT; + } + + try { + if (!impl(instance)->checkValidStoreType(storeType)) { + WrtLogE("Invalid input parameter."); + return CERTSVC_INVALID_STORE_TYPE; + } + + return impl(instance)->getPkcsIdEndUserListFromStore(storeType, certList, length); + } catch (...) {} + return CERTSVC_FAIL; +} + +int certsvc_pkcs12_get_root_certificate_list_from_store(CertSvcInstance instance, + CertStoreType storeType, + CertSvcStoreCertList** certList, + int* length) +{ + if (*certList != NULL) { + WrtLogE("Invalid input parameter."); + return CERTSVC_WRONG_ARGUMENT; + } + + try { + if (!impl(instance)->checkValidStoreType(storeType)) { + WrtLogE("Invalid input parameter."); + return CERTSVC_INVALID_STORE_TYPE; + } + + return impl(instance)->getPkcsIdRootListFromStore(storeType, certList, length); + } catch (...) {} + return CERTSVC_FAIL; +} + +int certsvc_pkcs12_get_certificate_info_from_store(CertSvcInstance instance, + CertStoreType storeType, + CertSvcString gname, + char** certBuffer, + size_t* certSize) +{ + if (*certBuffer != NULL) { + WrtLogE("Invalid input parameter."); + return CERTSVC_WRONG_ARGUMENT; + } + + try { + if (!impl(instance)->checkValidStoreType(storeType)) { + WrtLogE("Invalid input parameter."); + return CERTSVC_INVALID_STORE_TYPE; + } + + return impl(instance)->getCertDetailFromStore(storeType, gname, certBuffer, certSize); + } catch (...) {} + return CERTSVC_FAIL; +} + +int certsvc_pkcs12_delete_certificate_from_store(CertSvcInstance instance, + CertStoreType storeType, + CertSvcString gname) +{ + try { + if (!impl(instance)->checkValidStoreType(storeType)) { + WrtLogE("Invalid input parameter."); + return CERTSVC_INVALID_STORE_TYPE; + } + return impl(instance)->pkcsDeleteCertFromStore(storeType, gname); + } catch (...) {} + return CERTSVC_FAIL; +} + +int certsvc_pkcs12_import_from_file_to_store(CertSvcInstance instance, + CertStoreType storeType, + CertSvcString path, + CertSvcString password, + CertSvcString pfxIdString) +{ + try { + if (path.privateHandler != NULL) { + if (!impl(instance)->checkValidStoreType(storeType)) { + WrtLogE("Invalid input parameter."); + return CERTSVC_INVALID_STORE_TYPE; + } + return impl(instance)->pkcsImportToStore(storeType, path, password, pfxIdString); + } + else + return CERTSVC_FAIL; + } catch (...) {} + return CERTSVC_FAIL; +} + +int certsvc_pkcs12_get_alias_name_for_certificate_in_store(CertSvcInstance instance, + CertStoreType storeType, + CertSvcString gname, + char **alias) +{ + if (gname.privateHandler == NULL || gname.privateLength<=0) { + WrtLogE("Invalid input parameter."); + return CERTSVC_WRONG_ARGUMENT; + } + + try { + if (!impl(instance)->checkValidStoreType(storeType)) { + WrtLogE("Invalid input parameter."); + return CERTSVC_INVALID_STORE_TYPE; + } + return impl(instance)->pkcsGetAliasNameForCertInStore(storeType, gname, alias); + } catch (...) {} + return CERTSVC_FAIL; +} + +int certsvc_pkcs12_set_certificate_status_to_store(CertSvcInstance instance, + CertStoreType storeType, + int is_root_app, + CertSvcString gname, + CertStatus status) +{ + try { + if (!impl(instance)->checkValidStoreType(storeType)) { + WrtLogE("Invalid input parameter."); + return CERTSVC_INVALID_STORE_TYPE; + } + return impl(instance)->pkcsSetCertStatusToStore(storeType, is_root_app, gname, status); + } catch (...) {} + return CERTSVC_FAIL; +} + +int certsvc_pkcs12_get_certificate_status_from_store( + CertSvcInstance instance, + CertStoreType storeType, + CertSvcString gname, + int *status) +{ + try { + if (!impl(instance)->checkValidStoreType(storeType)) { + WrtLogE("Invalid input parameter."); + return CERTSVC_INVALID_STORE_TYPE; + } + return impl(instance)->pkcsGetCertStatusFromStore(storeType, gname, status); + } catch (...) {} + return CERTSVC_FAIL; +} + +int certsvc_pkcs12_get_certificate_from_store(CertSvcInstance instance, + CertStoreType storeType, + char *gname, + CertSvcCertificate *certificate) +{ + try { + if (!impl(instance)->checkValidStoreType(storeType)) { + WrtLogE("Invalid input parameter."); + return CERTSVC_INVALID_STORE_TYPE; + } + return impl(instance)->getCertFromStore(instance, storeType, gname, certificate); + } catch (...) {} + return CERTSVC_FAIL; +} + +int certsvc_pkcs12_load_certificate_list_from_store( + CertSvcInstance instance, + CertStoreType storeType, + CertSvcString pfxIdString, + CertSvcCertificateList *certificateList) +{ + try { + if (!impl(instance)->checkValidStoreType(storeType)) { + WrtLogE("Invalid input parameter."); + return CERTSVC_INVALID_STORE_TYPE; + } + return impl(instance)->getPkcsCertificateListFromStore(instance, storeType, pfxIdString, certificateList); + } catch (...) {} + return CERTSVC_FAIL; +} + +int certsvc_pkcs12_private_key_dup_from_store( + CertSvcInstance instance, + CertStoreType storeType, + CertSvcString gname, + char **certBuffer, + size_t *certSize) +{ + try { + if (!impl(instance)->checkValidStoreType(storeType)) { + WrtLogE("Invalid input parameter."); + return CERTSVC_INVALID_STORE_TYPE; + } + return impl(instance)->getPkcsPrivateKeyFromStore(storeType, gname, certBuffer, certSize); + } catch (...) {} + return CERTSVC_FAIL; +} + +int certsvc_pkcs12_dup_evp_pkey_from_store( + CertSvcInstance instance, + CertStoreType storeType, + CertSvcString gname, + EVP_PKEY** pkey) +{ + char *buffer = NULL; + size_t size; + + int result = certsvc_pkcs12_private_key_dup_from_store(instance, storeType, gname, &buffer, &size); + if (result != CERTSVC_SUCCESS) { + WrtLogE("Error in certsvc_pkcs12_private_key_dup"); + return result; + } + + BIO *b = BIO_new(BIO_s_mem()); + if ((int)size != BIO_write(b, buffer, size)) { + WrtLogE("Error in BIO_write"); + BIO_free_all(b); + certsvc_pkcs12_private_key_free(buffer); + return CERTSVC_FAIL; + } + + certsvc_pkcs12_private_key_free(buffer); + *pkey = PEM_read_bio_PrivateKey(b, NULL, NULL, NULL); + BIO_free_all(b); + if (*pkey) + return CERTSVC_SUCCESS; + + WrtLogE("Result is null. Openssl REASON code is: %d", ERR_GET_REASON(ERR_peek_last_error())); + return CERTSVC_FAIL; +} + int certsvc_pkcs12_get_id_list( CertSvcInstance instance, CertSvcStringList *pfxIdStringList) @@ -1771,7 +2333,7 @@ int certsvc_pkcs12_private_key_dup( void certsvc_pkcs12_private_key_free( char *buffer) { - delete[] buffer; + free(buffer); } int certsvc_pkcs12_delete( @@ -1783,3 +2345,4 @@ int certsvc_pkcs12_delete( } catch (...) {} return CERTSVC_FAIL; } + diff --git a/vcore/src/vcore/cert-svc-client.c b/vcore/src/vcore/cert-svc-client.c new file mode 100644 index 0000000..1935518 --- /dev/null +++ b/vcore/src/vcore/cert-svc-client.c @@ -0,0 +1,582 @@ +/** + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file cert-svc-client.c + * @author Madhan A K (madhan.ak@samsung.com) + * Kyungwook Tak (k.tak@samsung.com) + * @version 1.0 + * @brief cert-svc client interface for cert-server. + */ + +#include <sys/stat.h> +#include <sys/un.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <errno.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> + +#include <cert-service-debug.h> + +#include <cert-svc-client.h> + +void initialize_res_data(VcoreResponseData *pData) +{ + memset(pData->dataBlock, 0, VCORE_MAX_RECV_DATA_SIZE); + memset(pData->common_name, 0, VCORE_MAX_FILENAME_SIZE * 2 + 1); + pData->dataBlockLen = 0; + pData->certStatus = 0; + pData->result = 0; + pData->certList = NULL; + pData->certCount = 0; + pData->certBlockList = NULL; + pData->certBlockCount = 0; +} + +void initialize_req_data(VcoreRequestData *pData) +{ + memset(pData->gname, 0, VCORE_MAX_FILENAME_SIZE+1); + memset(pData->common_name, 0, VCORE_MAX_FILENAME_SIZE+1); + memset(pData->private_key_gname, 0, VCORE_MAX_FILENAME_SIZE+1); + memset(pData->associated_gname, 0, VCORE_MAX_FILENAME_SIZE+1); + memset(pData->dataBlock, 0, VCORE_MAX_SEND_DATA_SIZE); + pData->certStatus = 0; + pData->storeType = -1; + pData->reqType = -1; + pData->dataBlockLen = -1; + pData->is_root_app = -1; +} + +int _recv_fixed_lenghth(int sockfd, char *buff, int length) +{ + int offset = 0; + int remaining = length; + int read_len = 0; + while(remaining > 0) { + read_len = recv(sockfd, buff + offset, remaining, 0); + if(read_len <= 0) + return offset; + remaining -= read_len; + offset += read_len; + } + return offset; +} + +VcoreRequestData* set_request_data( + int reqType, + CertStoreType storeType, + int is_root_app, + const char *pGroupName, + const char *common_name, + const char *private_key_gname, + const char *associated_gname, + const char *pData, + size_t dataLen, + CertType certType, + int certStatus) +{ + VcoreRequestData* pReqData = (VcoreRequestData*)malloc(sizeof(VcoreRequestData)); + if (!pReqData) { + LOGE("Failed to malloc VcoreRequestData"); + return NULL; + } + initialize_req_data(pReqData); + + pReqData->reqType = reqType; + pReqData->storeType = (CertStoreType) storeType; + pReqData->dataBlockLen = dataLen; + pReqData->certType = certType; + pReqData->certStatus = certStatus; + pReqData->is_root_app = is_root_app; + + if (pGroupName) { + if (strlen(pGroupName) > VCORE_MAX_FILENAME_SIZE) { + LOGE("The data name is too long"); + free(pReqData); + return NULL; + } + strncpy(pReqData->gname, pGroupName, VCORE_MAX_FILENAME_SIZE); + pReqData->gname[strlen(pGroupName)] = '\0'; + } + + if (common_name) { + if (strlen(common_name) > VCORE_MAX_FILENAME_SIZE) { + LOGE("The length of the path specified is too long"); + free(pReqData); + return NULL; + } + strncpy(pReqData->common_name, common_name, VCORE_MAX_FILENAME_SIZE); + pReqData->common_name[strlen(common_name)] = '\0'; + } + + if (private_key_gname) { + if (strlen(private_key_gname) > VCORE_MAX_FILENAME_SIZE) { + LOGE("The private key gname is too long"); + free(pReqData); + return NULL; + } + strncpy(pReqData->private_key_gname, private_key_gname, VCORE_MAX_FILENAME_SIZE); + pReqData->private_key_gname[strlen(private_key_gname)] = '\0'; + } + + if (associated_gname) { + if (strlen(associated_gname) > VCORE_MAX_FILENAME_SIZE) { + LOGE("The associated gname is too long"); + free(pReqData); + return NULL; + } + strncpy(pReqData->associated_gname, associated_gname, VCORE_MAX_FILENAME_SIZE); + pReqData->associated_gname[strlen(associated_gname)] = '\0'; + } + + if (dataLen != 0 && pData != NULL) { + if (dataLen > VCORE_MAX_SEND_DATA_SIZE) { + LOGE("The data length is too long [%d]", dataLen); + free(pReqData); + return NULL; + } + memcpy(pReqData->dataBlock, pData, dataLen); + } + return pReqData; +} + + +VcoreResponseData cert_svc_client_comm(VcoreRequestData* pClientData) { + + int sockfd = 0; + int clientLen = 0; + int tempSockLen = 0; + int read_len = 0; + int i = 0; + struct sockaddr_un clientaddr; + VcoreResponseData recvData; + initialize_res_data(&recvData); + + if ((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { + LOGE("Error in function socket().."); + recvData.result = VCORE_SOCKET_ERROR; + goto Error_exit; + } + + tempSockLen = strlen(VCORE_SOCK_PATH); + bzero(&clientaddr, sizeof(clientaddr)); + clientaddr.sun_family = AF_UNIX; + strncpy(clientaddr.sun_path, VCORE_SOCK_PATH, tempSockLen); + clientaddr.sun_path[tempSockLen] = '\0'; + clientLen = sizeof(clientaddr); + + struct timeval timeout; + timeout.tv_sec = 10; + timeout.tv_usec = 0; + + if (setsockopt (sockfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout)) < 0) { + LOGE("Error in Set SO_RCVTIMEO Socket Option"); + recvData.result = VCORE_SOCKET_ERROR; + goto Error_close_exit; + } + + if (setsockopt (sockfd, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, sizeof(timeout)) < 0) { + LOGE("Error in Set SO_SNDTIMEO Socket Option"); + recvData.result = VCORE_SOCKET_ERROR; + goto Error_close_exit; + } + + if (connect(sockfd, (struct sockaddr*)&clientaddr, clientLen) < 0) { + LOGE("Error in function connect().."); + recvData.result = VCORE_SOCKET_ERROR; + goto Error_close_exit; + } + + if (write(sockfd, (char*)pClientData, sizeof(VcoreRequestData)) < 0) { + LOGE("Error in function write().."); + recvData.result = VCORE_SOCKET_ERROR; + goto Error_close_exit; + } + + read_len = _recv_fixed_lenghth(sockfd, (char*)&recvData, sizeof(recvData)); + if (read_len < 0) { + LOGE("Error in function read().."); + recvData.result = VCORE_SOCKET_ERROR; + goto Error_close_exit; + } + + if(recvData.certCount > 0) { + recvData.certList = (VcoreCertResponseData *) malloc(recvData.certCount * sizeof(VcoreCertResponseData)); + if (!recvData.certList) { + LOGE("Failed to allocate memory"); + recvData.result = VCORE_SOCKET_ERROR; + goto Error_close_exit; + } + memset(recvData.certList, 0x00, recvData.certCount * sizeof(VcoreCertResponseData)); + for(i=0; i<recvData.certCount; i++) { + read_len = _recv_fixed_lenghth(sockfd, (char*)(recvData.certList + i), sizeof(VcoreCertResponseData)); + if (read_len < 0) { + LOGE("Error in function read().."); + recvData.result = VCORE_SOCKET_ERROR; + goto Error_close_exit; + } + } + } + + if(recvData.certBlockCount > 0) { + recvData.certBlockList = (ResponseCertBlock *) malloc(recvData.certBlockCount * sizeof(ResponseCertBlock)); + if (!recvData.certBlockList) { + LOGE("Failed to allocate memory"); + recvData.result = VCORE_SOCKET_ERROR; + goto Error_close_exit; + } + memset(recvData.certBlockList, 0x00, recvData.certBlockCount * sizeof(ResponseCertBlock)); + for(i=0; i<recvData.certBlockCount; i++) { + read_len = _recv_fixed_lenghth(sockfd, (char*)(recvData.certBlockList + i), sizeof(ResponseCertBlock)); + if (read_len < 0) { + LOGE("Error in function read().."); + recvData.result = VCORE_SOCKET_ERROR; + goto Error_close_exit; + } + } + } + +Error_close_exit: + close(sockfd); + if (recvData.result == VCORE_SOCKET_ERROR) { + free(recvData.certList); + recvData.certList = NULL; + recvData.certCount = 0; + + free(recvData.certBlockList); + recvData.certBlockList = NULL; + recvData.certBlockCount = 0; + } + +Error_exit: + return recvData; +} + +int vcore_client_install_certificate_to_store( + CertStoreType storeType, + const char *gname, + const char *common_name, + const char *private_key_gname, + const char *associated_gname, + const char *certData, + size_t certSize, + CertType certType) +{ + VcoreRequestData* pSendData = NULL; + VcoreResponseData recvData; + initialize_res_data(&recvData); + + if (!gname && !certData) { + LOGE("Invalid input argument."); + return CERTSVC_WRONG_ARGUMENT; + } + + pSendData = set_request_data( + CERTSVC_INSTALL_CERTIFICATE, + storeType, + DISABLED, + gname, + common_name, + private_key_gname, + associated_gname, + certData, + certSize, + certType, 0); + if (pSendData == NULL) { + LOGE("Failed to set request data"); + return CERTSVC_WRONG_ARGUMENT; + } + + recvData = cert_svc_client_comm(pSendData); + free(pSendData); + return recvData.result; +} + +int vcore_client_set_certificate_status_to_store(CertStoreType storeType, int is_root_app, const char* gname, CertStatus status) { + + VcoreRequestData* pSendData = NULL; + VcoreResponseData recvData; + initialize_res_data(&recvData); + + if (gname == NULL) { + LOGE("Invalid input parameter."); + return CERTSVC_WRONG_ARGUMENT; + } + + pSendData = set_request_data(CERTSVC_SET_CERTIFICATE_STATUS, storeType, is_root_app, gname, NULL, NULL, NULL, NULL, 0, 0, status); + if (pSendData == NULL) { + LOGE("Failed to set request data"); + return CERTSVC_WRONG_ARGUMENT; + } + + recvData = cert_svc_client_comm(pSendData); + free(pSendData); + + return recvData.result; +} + +int vcore_client_get_certificate_status_from_store(CertStoreType storeType, const char* gname, int *status) { + + VcoreRequestData* pSendData = NULL; + VcoreResponseData recvData; + initialize_res_data(&recvData); + + if (gname == NULL) { + LOGE("Invalid input parameter."); + return CERTSVC_WRONG_ARGUMENT; + } + + pSendData = set_request_data(CERTSVC_GET_CERTIFICATE_STATUS, storeType, DISABLED, gname, NULL, NULL, NULL, NULL, 0, 0, 0); + if (pSendData == NULL) { + LOGE("Failed to set request data"); + return CERTSVC_WRONG_ARGUMENT; + } + + recvData = cert_svc_client_comm(pSendData); + free(pSendData); + *status = recvData.certStatus; + return recvData.result; +} + +int vcore_client_check_alias_exist_in_store(CertStoreType storeType, const char* alias, int *status) { + + VcoreRequestData* pSendData = NULL; + VcoreResponseData recvData; + initialize_res_data(&recvData); + + if (alias == NULL) { + LOGE("Invalid input parameter."); + return CERTSVC_WRONG_ARGUMENT; + } + + pSendData = set_request_data(CERTSVC_CHECK_ALIAS_EXISTS, storeType, DISABLED,alias, NULL, NULL, NULL, NULL, 0, 0, 0); + if (pSendData == NULL) { + LOGE("Failed to set request data"); + return CERTSVC_WRONG_ARGUMENT; + } + + recvData = cert_svc_client_comm(pSendData); + free(pSendData); + *status = recvData.certStatus; + return recvData.result; +} + +int vcore_client_get_certificate_from_store(CertStoreType storeType, const char* gname, char** certData, size_t* certSize, CertType certType) { + + char* outData = NULL; + VcoreRequestData* pSendData = NULL; + VcoreResponseData recvData; + + if (!gname || !certData || !certSize) { + LOGE("Invalid input argument."); + return CERTSVC_WRONG_ARGUMENT; + } + + initialize_res_data(&recvData); + + if (storeType == SYSTEM_STORE) /* for extracting certificate from system store */ + pSendData = set_request_data(CERTSVC_EXTRACT_SYSTEM_CERT, storeType, DISABLED, gname, NULL, NULL, NULL, NULL, 0, certType, 0); + else /* for extracting certificate from other stores */ + pSendData = set_request_data(CERTSVC_EXTRACT_CERT, storeType, DISABLED, gname, NULL, NULL, NULL, NULL, 0, certType, 0); + + if (pSendData == NULL) { + LOGE("Failed to set request data."); + return CERTSVC_WRONG_ARGUMENT; + } + + recvData = cert_svc_client_comm(pSendData); + if (recvData.result < 0) { + LOGE("An error occurred from server side err[%d]", recvData.result); + free(pSendData); + return recvData.result; + } + free(pSendData); + + if (recvData.dataBlockLen > 0 && recvData.dataBlockLen <= VCORE_MAX_RECV_DATA_SIZE) { + outData = (char*)malloc(recvData.dataBlockLen + 1); + memset(outData, 0x00, recvData.dataBlockLen +1); + memcpy(outData, recvData.dataBlock, recvData.dataBlockLen); + *certData = outData; + *certSize = recvData.dataBlockLen; + } + else { + LOGE("revcData length is wrong : %d", recvData.dataBlockLen); + return CERTSVC_WRONG_ARGUMENT; + } + + return recvData.result; +} + +int vcore_client_delete_certificate_from_store(CertStoreType storeType, const char* gname) { + + VcoreRequestData* pSendData = NULL; + VcoreResponseData recvData; + initialize_res_data(&recvData); + + if (gname == NULL) { + LOGE("Invalid input parameter."); + return CERTSVC_WRONG_ARGUMENT; + } + + pSendData = set_request_data(CERTSVC_DELETE_CERT, storeType, DISABLED, gname, NULL, NULL, NULL, NULL, 0, 0, 0); + if (pSendData == NULL) { + LOGE("Failed to set request data"); + return CERTSVC_WRONG_ARGUMENT; + } + + recvData = cert_svc_client_comm(pSendData); + free(pSendData); + return recvData.result; +} + +int _vcore_client_get_certificate_list_from_store(int reqType, CertStoreType storeType, int is_root_app, + CertSvcStoreCertList** certList, int* length) +{ + VcoreRequestData* pSendData = NULL; + VcoreResponseData recvData; + CertSvcStoreCertList* curr = NULL; + CertSvcStoreCertList* prev = NULL; + VcoreCertResponseData* cert = NULL; + int tmplen = 0; + int i=0; + initialize_res_data(&recvData); + + + pSendData = set_request_data(reqType, storeType, is_root_app, NULL, NULL, NULL, NULL, NULL, 0, 0, 0); + if (pSendData == NULL) { + LOGE("Failed to set request data"); + return CERTSVC_WRONG_ARGUMENT; + } + + recvData = cert_svc_client_comm(pSendData); + + if(recvData.certCount > 0) { + for(i=0; i<recvData.certCount; i++) { + cert = recvData.certList + i ; + curr = (CertSvcStoreCertList*) malloc(sizeof(CertSvcStoreCertList)); + memset(curr, 0x00, sizeof(CertSvcStoreCertList)); + + tmplen = strlen(cert->gname); + curr->gname = (char*) malloc (sizeof(char) * (tmplen+ 1)); + memset(curr->gname, 0x00, tmplen + 1); + memcpy(curr->gname, cert->gname, tmplen); + + tmplen = strlen(cert->title); + curr->title = (char*) malloc (sizeof(char) * (tmplen+ 1)); + memset(curr->title, 0x00, tmplen + 1); + memcpy(curr->title, cert->title, tmplen); + + curr->status = cert->status; + curr->storeType = cert->storeType; + + if(prev == NULL) { + *certList = curr; + }else { + prev->next = curr; + } + prev = curr; + } + } + + *length = recvData.certCount; + + LOGI("get_certificate_list_from_store: result=%d", recvData.result); + if(recvData.certList != NULL) + free(recvData.certList); + free(pSendData); + return recvData.result; +} + +int vcore_client_get_certificate_list_from_store(CertStoreType storeType, int is_root_app, + CertSvcStoreCertList** certList, int* length) +{ + return _vcore_client_get_certificate_list_from_store(CERTSVC_GET_CERTIFICATE_LIST, storeType, is_root_app, + certList, length); +} + +int vcore_client_get_root_certificate_list_from_store(CertStoreType storeType, + CertSvcStoreCertList** certList, int* length) +{ + return _vcore_client_get_certificate_list_from_store(CERTSVC_GET_ROOT_CERTIFICATE_LIST, storeType, 0, + certList, length); +} + +int vcore_client_get_end_user_certificate_list_from_store(CertStoreType storeType, + CertSvcStoreCertList** certList, int* length) +{ + return _vcore_client_get_certificate_list_from_store(CERTSVC_GET_USER_CERTIFICATE_LIST, storeType, 0, + certList, length); +} + +int vcore_client_get_certificate_alias_from_store(CertStoreType storeType, const char *gname, char **alias) +{ + VcoreRequestData* pSendData = NULL; + VcoreResponseData recvData; + initialize_res_data(&recvData); + + if (gname == NULL) { + LOGE("Invalid input parameter."); + return CERTSVC_WRONG_ARGUMENT; + } + + pSendData = set_request_data(CERTSVC_GET_CERTIFICATE_ALIAS, storeType, DISABLED, gname, NULL, NULL, NULL, NULL, 0, 0, 0); + if (pSendData == NULL) { + LOGE("Failed to set request data"); + return CERTSVC_WRONG_ARGUMENT; + } + + recvData = cert_svc_client_comm(pSendData); + + *alias = strndup(recvData.common_name, sizeof(recvData.common_name)); + free(pSendData); + return recvData.result; +} + +int vcore_client_load_certificates_from_store(CertStoreType storeType, const char *gname, char ***certs, int *ncerts) +{ + VcoreRequestData* pSendData = NULL; + VcoreResponseData recvData; + ResponseCertBlock* cert = NULL; + int i=0; + initialize_res_data(&recvData); + + pSendData = set_request_data(CERTSVC_LOAD_CERTIFICATES, storeType, DISABLED, gname, NULL, NULL, NULL, NULL, 0, 0, 0); + if (pSendData == NULL) { + LOGE("Failed to set request data"); + return CERTSVC_WRONG_ARGUMENT; + } + + recvData = cert_svc_client_comm(pSendData); + + *ncerts = recvData.certBlockCount; + *certs = (char**)malloc((recvData.certBlockCount+1) * sizeof(char *)); + (*certs)[recvData.certBlockCount] = NULL; + LOGD("vcore_client_load_certificates_from_store. result=%d, ncerts=%d", recvData.result, *ncerts); + if(recvData.certBlockCount > 0) { + for(i=0; i<recvData.certBlockCount; i++) { + cert = recvData.certBlockList + i ; + (*certs)[i] = strndup(cert->dataBlock, cert->dataBlockLen); + LOGD("vcore_client_load_certificates_from_store. cert=%s", (*certs)[i]); + } + } + + if(recvData.certBlockList != NULL) + free(recvData.certBlockList); + free(pSendData); + return recvData.result; + +} diff --git a/vcore/src/vcore/cert-svc-client.h b/vcore/src/vcore/cert-svc-client.h new file mode 100644 index 0000000..9c5b595 --- /dev/null +++ b/vcore/src/vcore/cert-svc-client.h @@ -0,0 +1,116 @@ +/** + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file cert-svc-client.h + * @author Madhan A K (madhan.ak@samsung.com) + * @version 1.0 + * @brief cert-svc client interface for cert-svc server present in secure-storage module. + */ + +#ifndef CERT_SVC_CLIENT_H_ +#define CERT_SVC_CLIENT_H_ + +#include <cert-svc/cerror.h> +#include <cert-svc/ccert.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define VCORE_MAX_FILENAME_SIZE 128 +#define VCORE_MAX_RECV_DATA_SIZE 8192 //4096, internal buffer = 4KB*2. /*Note:system store cert size is bigger than 4KB*/ +#define VCORE_MAX_SEND_DATA_SIZE 8192 //4096, internal buffer = 4KB*2. +#define VCORE_MAX_GROUP_ID_SIZE 32 +#define VCORE_MAX_APPID_SIZE 32 +#define VCORE_MAX_PASSWORD_SIZE 32 +#define VCORE_SOCKET_ERROR (-0x01C10000) // TIZEN_ERROR_CONNECTION /*Connection error*/ +#define VCORE_SOCK_PATH "/tmp/CertSocket" +#define VCORE_PKEY_TEMP_PATH "/tmp/tmpData" + +typedef enum { + CERTSVC_EXTRACT_CERT, + CERTSVC_EXTRACT_SYSTEM_CERT, + CERTSVC_DELETE_CERT, + CERTSVC_INSTALL_CERTIFICATE, + CERTSVC_GET_CERTIFICATE_STATUS, + CERTSVC_SET_CERTIFICATE_STATUS, + CERTSVC_CHECK_ALIAS_EXISTS, + CERTSVC_GET_CERTIFICATE_LIST, + CERTSVC_GET_CERTIFICATE_ALIAS, + CERTSVC_GET_USER_CERTIFICATE_LIST, + CERTSVC_GET_ROOT_CERTIFICATE_LIST, + CERTSVC_LOAD_CERTIFICATES, +} VcoreRequestType; + +typedef struct { + VcoreRequestType reqType; + CertStoreType storeType; + char gname[VCORE_MAX_FILENAME_SIZE * 2 + 1]; /* for gname */ + char common_name[VCORE_MAX_FILENAME_SIZE * 2 + 1]; /* for common_name */ + char private_key_gname[VCORE_MAX_FILENAME_SIZE * 2 + 1]; /* for private_key_gname */ + char associated_gname[VCORE_MAX_FILENAME_SIZE * 2 + 1]; /* for associated_gname */ + char dataBlock[VCORE_MAX_SEND_DATA_SIZE]; /* for cert & key buffer */ + size_t dataBlockLen; + int certStatus; + int is_root_app; + CertType certType; +} VcoreRequestData; + +typedef struct { + char gname[VCORE_MAX_FILENAME_SIZE * 2 + 1]; + char title[VCORE_MAX_FILENAME_SIZE * 2 + 1]; + int status; + CertStoreType storeType; +} VcoreCertResponseData; + + +typedef struct { + char dataBlock[VCORE_MAX_RECV_DATA_SIZE]; + size_t dataBlockLen; +} ResponseCertBlock; + +typedef struct { + char dataBlock[VCORE_MAX_RECV_DATA_SIZE]; + size_t dataBlockLen; + int certStatus; + char common_name[VCORE_MAX_FILENAME_SIZE* 2 + 1]; /*for common_name*/ + int result; + int certCount; + VcoreCertResponseData* certList; + int certBlockCount; + ResponseCertBlock* certBlockList; // array +} VcoreResponseData; + + + +int vcore_client_set_certificate_status_to_store(CertStoreType storeType, int is_root_app, const char* gname, CertStatus status); +int vcore_client_get_certificate_status_from_store(CertStoreType storeType, const char* gname, int *status); +int vcore_client_check_alias_exist_in_store(CertStoreType storeType, const char* alias, int *status); +int vcore_client_install_certificate_to_store(CertStoreType storeType, const char *gname, const char *common_name, const char *private_key_gname, const char *associated_gname, const char *dataBlock, size_t dataBlockLen, CertType certType); +int vcore_client_get_certificate_from_store(CertStoreType storeType, const char* gname, char** certData, size_t* certSize, CertType certType); +int vcore_client_delete_certificate_from_store(CertStoreType storeType, const char* gname); +VcoreResponseData cert_svc_client_comm(VcoreRequestData* client_data); +int vcore_client_get_certificate_list_from_store(CertStoreType storeType, int is_root_app, CertSvcStoreCertList** certList, int* length); +int vcore_client_get_root_certificate_list_from_store(CertStoreType storeType, CertSvcStoreCertList** certList, int* length); +int vcore_client_get_end_user_certificate_list_from_store(CertStoreType storeType, CertSvcStoreCertList** certList, int* length); +int vcore_client_get_certificate_alias_from_store(CertStoreType storeType, const char *gname, char **alias); +int vcore_client_load_certificates_from_store(CertStoreType storeType, const char *gname, char ***certs, int *ncerts); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/vcore/src/vcore/exception.cpp b/vcore/src/vcore/exception.cpp new file mode 100644 index 0000000..20d359f --- /dev/null +++ b/vcore/src/vcore/exception.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file exception.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation of exception system + */ +#include <vcore/exception.h> + +#include <dpl/log/vcore_log.h> + +#include <stddef.h> +#include <cstdio> + +namespace ValidationCore { +Exception* Exception::m_lastException = NULL; +unsigned int Exception::m_exceptionCount = 0; +void (*Exception::m_terminateHandler)() = NULL; + +void LogUnhandledException(const std::string &str) +{ + // Logging to dlog + VcoreLogD("%s", str.c_str()); +} + +void LogUnhandledException(const std::string &str, + const char *filename, + int line, + const char *function) +{ + // Logging to dlog + VcoreLogE("[%s:%d][%s]%s", filename, line, function, str.c_str()); +} +} // namespace ValidationCore diff --git a/vcore/src/vcore/exception.h b/vcore/src/vcore/exception.h new file mode 100644 index 0000000..dae719e --- /dev/null +++ b/vcore/src/vcore/exception.h @@ -0,0 +1,390 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file exception.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief Header file for base exception + */ +#ifndef ValidationCore_EXCEPTION_H +#define ValidationCore_EXCEPTION_H + +#include <string> +#include <cstring> +#include <cstdio> +#include <exception> +#include <cstdlib> +#include <sstream> + +namespace ValidationCore { +void LogUnhandledException(const std::string &str); +void LogUnhandledException(const std::string &str, + const char *filename, + int line, + const char *function); +} + +namespace ValidationCore { +class Exception { +private: + static unsigned int m_exceptionCount; + static Exception* m_lastException; + static void (*m_terminateHandler)(); + + static void AddRef(Exception* exception) + { + if (!m_exceptionCount) { + m_terminateHandler = std::set_terminate(&TerminateHandler); + } + + ++m_exceptionCount; + m_lastException = exception; + } + + static void UnRef(Exception* e) + { + if (m_lastException == e) { + m_lastException = NULL; + } + + --m_exceptionCount; + + if (!m_exceptionCount) { + std::set_terminate(m_terminateHandler); + m_terminateHandler = NULL; + } + } + + static void TerminateHandler() + { + if (m_lastException != NULL) { + DisplayKnownException(*m_lastException); + abort(); + } else { + DisplayUnknownException(); + abort(); + } + } + + Exception *m_reason; + std::string m_path; + std::string m_function; + int m_line; + +protected: + std::string m_message; + std::string m_className; + +public: + static std::string KnownExceptionToString(const Exception &e) + { + std::ostringstream message; + message << + "\033[1;5;31m\n=== Unhandled DPL exception occurred ===\033[m\n\n"; + message << "\033[1;33mException trace:\033[m\n\n"; + message << e.DumpToString(); + message << "\033[1;31m\n=== Will now abort ===\033[m\n"; + + return message.str(); + } + + static std::string UnknownExceptionToString() + { + std::ostringstream message; + message << + "\033[1;5;31m\n=== Unhandled non-DPL exception occurred ===\033[m\n\n"; + message << "\033[1;31m\n=== Will now abort ===\033[m\n"; + + return message.str(); + } + + static void DisplayKnownException(const Exception& e) + { + LogUnhandledException(KnownExceptionToString(e).c_str()); + } + + static void DisplayUnknownException() + { + LogUnhandledException(UnknownExceptionToString().c_str()); + } + + Exception(const Exception &other) + { + // Deep copy + if (other.m_reason != NULL) { + m_reason = new Exception(*other.m_reason); + } else { + m_reason = NULL; + } + + m_message = other.m_message; + m_path = other.m_path; + m_function = other.m_function; + m_line = other.m_line; + + m_className = other.m_className; + + AddRef(this); + } + + const Exception &operator =(const Exception &other) + { + if (this == &other) { + return *this; + } + + // Deep copy + if (other.m_reason != NULL) { + m_reason = new Exception(*other.m_reason); + } else { + m_reason = NULL; + } + + m_message = other.m_message; + m_path = other.m_path; + m_function = other.m_function; + m_line = other.m_line; + + m_className = other.m_className; + + AddRef(this); + + return *this; + } + + Exception(const char *path, + const char *function, + int line, + const std::string &message) : + m_reason(NULL), + m_path(path), + m_function(function), + m_line(line), + m_message(message) + { + AddRef(this); + } + + Exception(const char *path, + const char *function, + int line, + const Exception &reason, + const std::string &message) : + m_reason(new Exception(reason)), + m_path(path), + m_function(function), + m_line(line), + m_message(message) + { + AddRef(this); + } + + virtual ~Exception() throw() + { + if (m_reason != NULL) { + delete m_reason; + m_reason = NULL; + } + + UnRef(this); + } + + void Dump() const + { + // Show reason first + if (m_reason != NULL) { + m_reason->Dump(); + } + + // Afterward, dump exception + const char *file = strchr(m_path.c_str(), '/'); + + if (file == NULL) { + file = m_path.c_str(); + } else { + ++file; + } + + printf("\033[0;36m[%s:%i]\033[m %s() \033[4;35m%s\033[m: %s\033[m\n", + file, m_line, + m_function.c_str(), + m_className.c_str(), + m_message.empty() ? "<EMPTY>" : m_message.c_str()); + } + + std::string DumpToString() const + { + std::string ret; + if (m_reason != NULL) { + ret = m_reason->DumpToString(); + } + + const char *file = strchr(m_path.c_str(), '/'); + + if (file == NULL) { + file = m_path.c_str(); + } else { + ++file; + } + + char buf[1024]; + snprintf(buf, + sizeof(buf), + "\033[0;36m[%s:%i]\033[m %s() \033[4;35m%s\033[m: %s\033[m\n", + file, + m_line, + m_function.c_str(), + m_className.c_str(), + m_message.empty() ? "<EMPTY>" : m_message.c_str()); + + buf[sizeof(buf) - 1] = '\n'; + ret += buf; + + return ret; + } + + Exception *GetReason() const + { + return m_reason; + } + + std::string GetPath() const + { + return m_path; + } + + std::string GetFunction() const + { + return m_function; + } + + int GetLine() const + { + return m_line; + } + + std::string GetMessage() const + { + return m_message; + } + + std::string GetClassName() const + { + return m_className; + } +}; +} // namespace ValidationCore + +#define VcoreTry try + +#define VcoreThrow(ClassName) \ + throw ClassName(__FILE__, __FUNCTION__, __LINE__) + +#define VcoreThrowMsg(ClassName, Message) \ + do \ + { \ + std::ostringstream dplLoggingStream; \ + dplLoggingStream << Message; \ + throw ClassName(__FILE__, __FUNCTION__, __LINE__, dplLoggingStream.str()); \ + } while (0) + +#define VcoreReThrow(ClassName) \ + throw ClassName(__FILE__, __FUNCTION__, __LINE__, _rethrown_exception) + +#define VcoreReThrowMsg(ClassName, Message) \ + throw ClassName(__FILE__, \ + __FUNCTION__, \ + __LINE__, \ + _rethrown_exception, \ + Message) + +#define VcoreCatch(ClassName) \ + catch (const ClassName &_rethrown_exception) + +#define VCORE_DECLARE_EXCEPTION_TYPE(BaseClass, Class) \ + class Class : public BaseClass { \ + public: \ + Class(const char *path, \ + const char *function, \ + int line, \ + const std::string & message = std::string()) \ + : BaseClass(path, function, line, message) { \ + \ + BaseClass::m_className = #Class; \ + } \ + \ + Class(const char *path, \ + const char *function, \ + int line, \ + const ValidationCore::Exception & reason, \ + const std::string & message = std::string()) \ + : BaseClass(path, function, line, reason, message) { \ + BaseClass::m_className = #Class; \ + } \ + }; + +#define VCORE_UNHANDLED_EXCEPTION_HANDLER_BEGIN try + +#define VCORE_UNHANDLED_EXCEPTION_HANDLER_END \ + catch (const ValidationCore::Exception &exception) \ + { \ + std::ostringstream msg; \ + msg << ValidationCore::Exception::KnownExceptionToString(exception); \ + ValidationCore::LogUnhandledException(msg.str(), \ + __FILE__, \ + __LINE__, \ + __FUNCTION__); \ + abort(); \ + } \ + catch (std::exception& e) \ + { \ + std::ostringstream msg; \ + msg << e.what(); \ + msg << "\n"; \ + msg << ValidationCore::Exception::UnknownExceptionToString(); \ + ValidationCore::LogUnhandledException(msg.str(), \ + __FILE__, \ + __LINE__, \ + __FUNCTION__); \ + abort(); \ + } \ + catch (...) \ + { \ + std::ostringstream msg; \ + msg << ValidationCore::Exception::UnknownExceptionToString(); \ + ValidationCore::LogUnhandledException(msg.str(), \ + __FILE__, \ + __LINE__, \ + __FUNCTION__); \ + abort(); \ + } + +namespace ValidationCore { +namespace CommonException { +/** + * Internal exception definitions + * + * These should normally not happen. + * Usually, exception trace with internal error includes + * important messages. + */ +VCORE_DECLARE_EXCEPTION_TYPE(Exception, InternalError) ///< Unexpected error from + // underlying libraries or + // kernel +} +} + +#endif // ValidationCore_EXCEPTION_H diff --git a/vcore/src/vcore/pkcs12.c b/vcore/src/vcore/pkcs12.c deleted file mode 100755 index 1239dda..0000000 --- a/vcore/src/vcore/pkcs12.c +++ /dev/null @@ -1,946 +0,0 @@ -/** - * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/* - * @file pkcs12.h - * @author Jacek Migacz (j.migacz@samsung.com) - * @version 1.0 - * @brief PKCS#12 container manipulation routines. - */ -#define _GNU_SOURCE -#define _CERT_SVC_VERIFY_PKCS12 - -#include <cert-service.h> -#include "cert-service-util.h" -#include "pkcs12.h" -#include <cert-svc/cerror.h> -#include <unistd.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <errno.h> -#include <string.h> -#include <openssl/err.h> -#include <openssl/pkcs12.h> -#include <openssl/sha.h> -#include <openssl/x509.h> -#include <openssl/pem.h> -#include <ss_manager.h> -#include <dlfcn.h> -#include <cert-service-debug.h> -#include <tzplatform_config.h> -#include <tizen.h> - -#define SYSCALL(call) while(((call) == -1) && (errno == EINTR)) - -#define CERTSVC_PKCS12_STORAGE_DIR tzplatform_mkpath(TZ_SYS_SHARE, "cert-svc/pkcs12") -#define CERTSVC_PKCS12_STORAGE_FILE "storage" -#define CERTSVC_PKCS12_STORAGE_PATH tzplatform_mkpath3(TZ_SYS_SHARE,"cert-svc/pkcs12", CERTSVC_PKCS12_STORAGE_FILE) -#define MAX_PASSWORD_SIZE 32 -#define MAX_SEND_DATA_SIZE 4096 // internal buffer = 4KB - -typedef enum -{ - SSA_PARAM_ERROR = TIZEN_ERROR_SYSTEM_CLASS | 0x01, /** < Invalid parameters */ - SSA_AUTHENTICATION_ERROR = TIZEN_ERROR_SYSTEM_CLASS | 0x02, /** < Authentication error */ - SSA_TZ_ERROR = TIZEN_ERROR_SYSTEM_CLASS | 0x03, /** < Trust zone error */ - SSA_SOCKET_ERROR = TIZEN_ERROR_CONNECTION, /** < Connection error */ - SSA_PERMISSION_ERROR = TIZEN_ERROR_PERMISSION_DENIED, /** < Permission denied */ - SSA_SECURITY_SERVER_ERROR = TIZEN_ERROR_SYSTEM_CLASS | 0x04,/** < Security server error */ - SSA_CIPHER_ERROR = TIZEN_ERROR_SYSTEM_CLASS | 0x05, /** < Encryption / Decryption error */ - SSA_IO_ERROR = TIZEN_ERROR_IO_ERROR, /** < I/O error */ - SSA_OUT_OF_MEMORY = TIZEN_ERROR_OUT_OF_MEMORY, /** < Out of memory */ - SSA_UNKNOWN_ERROR = TIZEN_ERROR_UNKNOWN, /** < Unknown error */ -} ssa_error_e; - -static const char CERTSVC_PKCS12_STORAGE_KEY_PKEY[] = "pkey"; -static const char CERTSVC_PKCS12_STORAGE_KEY_CERTS[] = "certs"; -static const gchar CERTSVC_PKCS12_STORAGE_SEPARATOR = ';'; -static const char CERTSVC_PKCS12_UNIX_GROUP[] = "secure-storage::pkcs12"; - -static gboolean keyfile_check(const char *pathname) { - int result; - if(access(pathname, F_OK | R_OK | W_OK) == 0) - return TRUE; - SYSCALL(result = creat(pathname, S_IRUSR | S_IWUSR)); - if (result != -1) { - close(result); - return TRUE; - } else { - return FALSE; - } -} - -static GKeyFile *keyfile_load(const char *pathname) { - GKeyFile *keyfile; - GError *error; - - if(!keyfile_check(pathname)) - return NULL; - keyfile = g_key_file_new(); - error = NULL; - if(!g_key_file_load_from_file(keyfile, pathname, G_KEY_FILE_KEEP_COMMENTS, &error)) { - g_key_file_free(keyfile); - return NULL; - } - return keyfile; -} - -static int generate_random_filepath(char **filepath) { - int generator; - int64_t random; - SHA_CTX ctx; - unsigned char d[SHA_DIGEST_LENGTH]; - int result; - - if(!filepath) - return CERTSVC_WRONG_ARGUMENT; - - SYSCALL(generator = open("/dev/urandom", O_RDONLY)); - if(generator == -1) - return CERTSVC_FAIL; - SYSCALL(result = read(generator, &random, sizeof(random))); - if(result == -1) { - SYSCALL(close(generator)); - return CERTSVC_FAIL; - } - SYSCALL(result = close(generator)); - if(result == -1) - return CERTSVC_FAIL; - - SHA1_Init(&ctx); - SHA1_Update(&ctx, &random, sizeof(random)); - SHA1_Final(d, &ctx); - - result = asprintf(filepath, "%s/" \ - "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" \ - "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", - CERTSVC_PKCS12_STORAGE_DIR, - d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7], d[8], d[9], - d[10], d[11], d[12], d[13], d[14], d[15], d[16], d[17], d[18], d[19]); - return (result != -1) ? CERTSVC_SUCCESS : CERTSVC_BAD_ALLOC; -} - -static int unique_filename(char **filepath, gboolean with_secure_storage) { - const unsigned attempts = 0xFFU; - unsigned trial; - int result; - ssm_file_info_t sfi; - gboolean exists; - char* data = NULL; - char* tempfilepath = NULL; - - trial = 0U; - try_again: - ++trial; - result = generate_random_filepath(&tempfilepath); - if(result != CERTSVC_SUCCESS) - return result; - if(with_secure_storage) - exists = (access(*tempfilepath, F_OK) == 0 || ssm_getinfo(*filepath, &sfi, SSM_FLAG_DATA, CERTSVC_PKCS12_UNIX_GROUP) == 0); - else - exists = (access(*tempfilepath, F_OK) == 0); - - if(!exists) { - *filepath = tempfilepath; - } - else { - if(data){ - free(data); - data = NULL; - } - free(tempfilepath); - if(trial + 1 > attempts) - return CERTSVC_FAIL; - else - goto try_again; - } - return CERTSVC_SUCCESS; -} - -static char *bare_filename(char *filepath) { - char *needle; - if(!filepath) - return NULL; - needle = strrchr(filepath, '/'); - if(!needle) - return NULL; - return *(++needle) ? needle : NULL; -} - -int c_certsvc_pkcs12_alias_exists(const gchar *alias, gboolean *exists) { - GKeyFile *keyfile; - - if(exists == NULL) - return CERTSVC_WRONG_ARGUMENT; - keyfile = keyfile_load(CERTSVC_PKCS12_STORAGE_PATH); - if(!keyfile) - return CERTSVC_IO_ERROR; - *exists = g_key_file_has_group(keyfile, alias); - g_key_file_free(keyfile); - return CERTSVC_SUCCESS; -} - -int c_certsvc_pkcs12_import(const char *path, const char *password, const gchar *alias) { - int exists; - FILE *stream; - PKCS12 *container; - EVP_PKEY *key; - X509 *cert; - STACK_OF(X509) *certv; - int nicerts; - char *unique; - int result = 0; - struct stat st; - int wr_res; - void* dlHandle = NULL; - GKeyFile *keyfile; - gchar *bare; - gchar *pkvalue; - gchar **cvaluev; - gsize i, n; - gchar *data; - gsize length; - static int initFlag = 0; - const char appInfo[] = "certsvcp12"; - int readLen = 0; - char fileBuffer[4096] = {0,}; - - certv = NULL; - pkvalue = NULL; - if(!alias || strlen(alias) < 1) - return CERTSVC_WRONG_ARGUMENT; - result = c_certsvc_pkcs12_alias_exists(alias, &exists); - if(result != CERTSVC_SUCCESS) - return result; - if(exists == TRUE) - return CERTSVC_DUPLICATED_ALIAS; - - keyfile = keyfile_load(CERTSVC_PKCS12_STORAGE_PATH); - if(!keyfile) - return CERTSVC_IO_ERROR; - if(stat(CERTSVC_PKCS12_STORAGE_PATH, &st) == -1) { - if(mkdir(CERTSVC_PKCS12_STORAGE_PATH, S_IRWXU | S_IRWXG | S_IRWXO) == -1) { - result = CERTSVC_FAIL; - goto free_keyfile; - } - } - - if((stream = fopen(path, "rb")) == NULL) { - result = CERTSVC_IO_ERROR; - goto free_keyfile; - } - container = d2i_PKCS12_fp(stream, NULL); - fclose(stream); - if(container == NULL) { - result = CERTSVC_FAIL; - goto free_keyfile; - } - -#ifdef TIZEN_FEATURE_OSP_DISABLE - LOGD("TIZEN_FEAT_OSP_DISABLE is 1"); -#endif - -#ifndef TIZEN_FEATURE_OSP_DISABLE - LOGD("TIZEN_FEAT_OSP_DISABLE is 0"); -#endif - -#ifndef TIZEN_FEATURE_OSP_DISABLE - dlHandle = dlopen("/usr/lib/osp/libosp-appfw.so", RTLD_LAZY); - if (!dlHandle) - { - LOGD("Failed to open so with reason : %s", dlerror()); - goto free_keyfile; - } -#endif - result = PKCS12_parse(container, password, &key, &cert, &certv); - PKCS12_free(container); - if (result == 0) - { - LOGD("Failed to parse PKCS12"); - result = CERTSVC_FAIL; - goto free_keyfile; - } - -#define _CERT_SVC_VERIFY_PKCS12 -#ifdef _CERT_SVC_VERIFY_PKCS12 - - if (certv == NULL) - { - char* pSubject = NULL; - char* pIssuerName = NULL; - int isSelfSigned = 0; - - pSubject = X509_NAME_oneline(cert->cert_info->subject, NULL, 0); - if (!pSubject) - { - LOGD("Failed to get subject name"); - result = CERTSVC_FAIL; - goto free_keyfile; - } - - pIssuerName = X509_NAME_oneline(cert->cert_info->issuer, NULL, 0); - if (!pIssuerName) - { - LOGD("Failed to get issuer name"); - free(pSubject); - result = CERTSVC_FAIL; - goto free_keyfile; - } - - if (strcmp((const char*)pSubject, (const char*)pIssuerName) == 0) - { - //self signed.. - //isSelfSigned = 1; - - EVP_PKEY* pKey = X509_get_pubkey(cert); - if (!pKey) - { - LOGD("Failed to get public key"); - result = CERTSVC_FAIL; - free(pSubject); - free(pIssuerName); - goto free_keyfile; - } - - if (X509_verify(cert, pKey) <= 0) - { - LOGD("P12 verification failed"); - result = CERTSVC_FAIL; - EVP_PKEY_free(pKey); - free(pSubject); - free(pIssuerName); - goto free_keyfile; - } - LOGD("P12 verification Success"); - EVP_PKEY_free(pKey); - } - else - { - //isSelfSigned = 0; - int res = 0; - X509_STORE_CTX *cert_ctx = NULL; - X509_STORE *cert_store = NULL; - - cert_store = X509_STORE_new(); - if (!cert_store) - { - LOGD("Memory allocation failed"); - free(pSubject); - free(pIssuerName); - result = CERTSVC_FAIL; - goto free_keyfile; - } - - res = X509_STORE_load_locations(cert_store, NULL, tzplatform_mkpath(TZ_SYS_ETC, "ssl/certs/")); - if (res != 1) - { - LOGD("P12 load certificate store failed"); - free(pSubject); - free(pIssuerName); - X509_STORE_free(cert_store); - result = CERTSVC_FAIL; - goto free_keyfile; - } - - res = X509_STORE_set_default_paths(cert_store); - if (res != 1) - { - LOGD("P12 load certificate store path failed"); - free(pSubject); - free(pIssuerName); - X509_STORE_free(cert_store); - result = CERTSVC_FAIL; - goto free_keyfile; - } - - // initialize store and store context - cert_ctx = X509_STORE_CTX_new(); - if (cert_ctx == NULL) - { - LOGD("Memory allocation failed"); - free(pSubject); - free(pIssuerName); - X509_STORE_free(cert_store); - result = CERTSVC_FAIL; - goto free_keyfile; - } - - // construct store context - if (!X509_STORE_CTX_init(cert_ctx, cert_store, cert, NULL)) - { - LOGD("Memory allocation failed"); - free(pSubject); - free(pIssuerName); - X509_STORE_free(cert_store); - X509_STORE_CTX_free(cert_ctx); - result = CERTSVC_FAIL; - goto free_keyfile; - } - - res = X509_verify_cert(cert_ctx); - if (res != 1) - { - LOGD("P12 verification failed"); - free(pSubject); - free(pIssuerName); - X509_STORE_free(cert_store); - X509_STORE_CTX_free(cert_ctx); - result = CERTSVC_FAIL; - goto free_keyfile; - } - X509_STORE_free(cert_store); - X509_STORE_CTX_free(cert_ctx); - LOGD("P12 verification Success"); - } - free(pSubject); - free(pIssuerName); - } - else if (certv != NULL) - { - // Cert Chain - int res = 0; - X509_STORE_CTX *cert_ctx = NULL; - X509_STORE *cert_store = NULL; - - cert_store = X509_STORE_new(); - if (!cert_store) - { - LOGD("Memory allocation failed"); - result = CERTSVC_FAIL; - goto free_keyfile; - } - - res = X509_STORE_load_locations(cert_store, NULL, tzplatform_mkpath(TZ_SYS_SHARE, "cert-svc/certs/ssl/")); - if (res != 1) - { - LOGD("P12 load certificate store failed"); - result = CERTSVC_FAIL; - X509_STORE_free(cert_store); - goto free_keyfile; - } - - res = X509_STORE_set_default_paths(cert_store); - if (res != 1) - { - LOGD("P12 load certificate path failed"); - result = CERTSVC_FAIL; - X509_STORE_free(cert_store); - goto free_keyfile; - } - - // initialize store and store context - cert_ctx = X509_STORE_CTX_new(); - if (cert_ctx == NULL) - { - LOGD("Memory allocation failed"); - result = CERTSVC_FAIL; - X509_STORE_free(cert_store); - goto free_keyfile; - } - - // construct store context - if (!X509_STORE_CTX_init(cert_ctx, cert_store, cert, NULL)) - { - LOGD("Memory allocation failed"); - result = CERTSVC_FAIL; - X509_STORE_free(cert_store); - X509_STORE_CTX_free(cert_ctx); - goto free_keyfile; - } - - X509_STORE_CTX_trusted_stack(cert_ctx, certv); - - res = X509_verify_cert(cert_ctx); - if (res != 1) - { - LOGD("P12 verification failed"); - result = CERTSVC_FAIL; - X509_STORE_free(cert_store); - X509_STORE_CTX_free(cert_ctx); - goto free_keyfile; - } - - LOGD("P12 verification Success"); - X509_STORE_free(cert_store); - X509_STORE_CTX_free(cert_ctx); - } -#endif //_CERT_SVC_VERIFY_PKCS12 - nicerts = certv ? sk_X509_num(certv) : 0; - cvaluev = (gchar **)calloc(1 + nicerts, sizeof(gchar *)); - n = 0; - - result = unique_filename(&unique, TRUE); - if(result != CERTSVC_SUCCESS) - goto clean_cert_chain_and_pkey; - if((stream = fopen(unique, "w+")) == NULL) { - free(unique); - result = CERTSVC_IO_ERROR; - goto clean_cert_chain_and_pkey; - } - result = PEM_write_PrivateKey(stream, key, NULL, NULL, 0, NULL, NULL); - if(result == 0) { - result = CERTSVC_FAIL; - fclose(stream); - free(unique); - goto clean_cert_chain_and_pkey; - } - - fseek(stream, 0, SEEK_SET); - - readLen = fread(fileBuffer, sizeof(char), 4096, stream); - fclose(stream); - if(readLen <= 0){ - free(unique); - result = CERTSVC_FAIL; - SLOGE("failed to read key file"); - goto clean_cert_chain_and_pkey; - } - wr_res = ssm_write_file(unique, SSM_FLAG_DATA, CERTSVC_PKCS12_UNIX_GROUP); - if(wr_res != 0) { - free(unique); - result = CERTSVC_FAIL; - goto clean_cert_chain_and_pkey; - } - unlink(unique); - - bare = bare_filename(unique); - if(bare) { - pkvalue = g_strdup(bare); - g_key_file_set_string(keyfile, alias, CERTSVC_PKCS12_STORAGE_KEY_PKEY, pkvalue); - } - free(unique); - result = unique_filename(&unique, FALSE); - if(result != CERTSVC_SUCCESS) - goto clean_cert_chain_and_pkey; - if((stream = fopen(unique, "w")) == NULL) { - free(unique); - result = CERTSVC_IO_ERROR; - goto clean_cert_chain_and_pkey; - } - result = PEM_write_X509(stream, cert); - fclose(stream); - if(result == 0) { - result = CERTSVC_FAIL; - goto clean_cert_chain_and_pkey; - } - bare = bare_filename(unique); - if(bare) - cvaluev[n++] = g_strdup(bare); - free(unique); - for(i = 0; i < (unsigned int)nicerts; i++) { - result = unique_filename(&unique, FALSE); - if(result != CERTSVC_SUCCESS) - goto clean_cert_chain_and_pkey; - if((stream = fopen(unique, "w")) == NULL) { - free(unique); - result = CERTSVC_IO_ERROR; - goto clean_cert_chain_and_pkey; - } - result = PEM_write_X509_AUX(stream, sk_X509_value(certv, i)); - fclose(stream); - if(result == 0) { - result = CERTSVC_FAIL; - goto clean_cert_chain_and_pkey; - } - bare = bare_filename(unique); - if(bare) - cvaluev[n++] = g_strdup(bare); - free(unique); - } - g_key_file_set_list_separator(keyfile, CERTSVC_PKCS12_STORAGE_SEPARATOR); - g_key_file_set_string_list(keyfile, alias, CERTSVC_PKCS12_STORAGE_KEY_CERTS, (const gchar * const *)cvaluev, n); - data = g_key_file_to_data(keyfile, &length, NULL); - if(data == NULL) { - result = CERTSVC_BAD_ALLOC; - goto clean_cert_chain_and_pkey; - } - if(!g_file_set_contents(CERTSVC_PKCS12_STORAGE_PATH, data, length, NULL)) { - result = CERTSVC_IO_ERROR; - goto free_data; - } - result = CERTSVC_SUCCESS; - - SECURE_LOGD("( %s, %s)", path, password); -#ifndef TIZEN_FEATURE_OSP_DISABLE - - typedef int (*InsertPkcs12FuncPointer)(const char*, const char*); - typedef void (*InitAppInfoPointer)(const char*, const char*); - - InsertPkcs12FuncPointer pInsertPkcs12FuncPointer = NULL; - InitAppInfoPointer pInit = NULL; - - - pInsertPkcs12FuncPointer = (InsertPkcs12FuncPointer)dlsym(dlHandle, "InsertPkcs12Content"); - if (dlerror() != NULL) - { - LOGD("Failed to find InsertPkcs12Content symbol : %s", dlerror()); - result = CERTSVC_FAIL; - goto free_data; - } - - if(initFlag == 0) - { - pInit = (InitAppInfoPointer)dlsym(dlHandle, "InitWebAppInfo"); - if (dlerror() != NULL) - { - LOGD("Failed to find InitWebAppInfo symbol : %s", dlerror()); - result = CERTSVC_FAIL; - goto free_data; - } - - pInit(appInfo, NULL); - initFlag = 1; - } - - int errCode = pInsertPkcs12FuncPointer(path, password); - if (errCode != 0) - { - LOGD("dlHandle is not able to call function"); - c_certsvc_pkcs12_delete(alias); - result = CERTSVC_FAIL; - goto free_data; - } -#endif - free_data: - g_free(data); - - clean_cert_chain_and_pkey: - EVP_PKEY_free(key); - X509_free(cert); - sk_X509_free(certv); - free(pkvalue); - for(i = 0; i < n; i++) { - g_free(cvaluev[i]); - } - free(cvaluev); - free_keyfile: - g_key_file_free(keyfile); -#ifndef TIZEN_FEATURE_OSP_DISABLE - if(dlHandle){ - dlclose(dlHandle); - } -#endif - return result; -} - -int c_certsvc_pkcs12_aliases_load(gchar ***aliases, gsize *naliases) { - GKeyFile *keyfile; - - keyfile = keyfile_load(CERTSVC_PKCS12_STORAGE_PATH); - if(!keyfile) - return CERTSVC_IO_ERROR; - *aliases = g_key_file_get_groups(keyfile, naliases); - g_key_file_free(keyfile); - return CERTSVC_SUCCESS; -} - -void c_certsvc_pkcs12_aliases_free(gchar **aliases) { - g_strfreev(aliases); -} - -int c_certsvc_pkcs12_has_password(const char *filepath, gboolean *passworded) { - FILE *stream; - EVP_PKEY *pkey; - X509 *cert; - PKCS12 *container; - int result; - - if(passworded == NULL) - return CERTSVC_WRONG_ARGUMENT; - if((stream = fopen(filepath, "rb")) == NULL) - return CERTSVC_IO_ERROR; - container = d2i_PKCS12_fp(stream, NULL); - fclose(stream); - if(container == NULL) - return CERTSVC_FAIL; - result = PKCS12_parse(container, NULL, &pkey, &cert, NULL); - PKCS12_free(container); - if(result == 1) { - EVP_PKEY_free(pkey); - X509_free(cert); - *passworded = FALSE; - return CERTSVC_SUCCESS; - } - else { - if(ERR_GET_REASON(ERR_peek_last_error()) == PKCS12_R_MAC_VERIFY_FAILURE) { - *passworded = TRUE; - return CERTSVC_SUCCESS; - } - else - return CERTSVC_FAIL; - } -} - -int c_certsvc_pkcs12_load_certificates(const gchar *alias, gchar ***certs, gsize *ncerts) { - GKeyFile *keyfile; - gchar **barev; - gsize i; - keyfile = keyfile_load(CERTSVC_PKCS12_STORAGE_PATH); - if(!keyfile) - return CERTSVC_IO_ERROR; - g_key_file_set_list_separator(keyfile, CERTSVC_PKCS12_STORAGE_SEPARATOR); - barev = g_key_file_get_string_list(keyfile, alias, CERTSVC_PKCS12_STORAGE_KEY_CERTS, ncerts, NULL); - if(barev == NULL) { - *ncerts = 0; - goto free_keyfile; - } - *certs = g_malloc((*ncerts + 1) * sizeof(gchar *)); - for(i = 0; i < *ncerts; i++) - (*certs)[i] = g_strdup_printf("%s/%s", CERTSVC_PKCS12_STORAGE_DIR, barev[i]); - (*certs)[*ncerts] = NULL; - g_strfreev(barev); -free_keyfile: - g_key_file_free(keyfile); - return CERTSVC_SUCCESS; -} - -void c_certsvc_pkcs12_free_certificates(gchar **certs) { - gsize i = 0; - if(certs == NULL) - return; - while(certs[i]) - g_free(certs[i++]); - g_free(certs); -} - -int c_certsvc_pkcs12_private_key_load(const gchar *alias, char **buffer, gsize *count) { - GKeyFile *keyfile; - gchar *pkey; - GError *error; - ssm_file_info_t sfi; - char *spkp; - int result; - - if(!buffer) - return CERTSVC_WRONG_ARGUMENT; - keyfile = keyfile_load(CERTSVC_PKCS12_STORAGE_PATH); - if(!keyfile) - return CERTSVC_IO_ERROR; - error = NULL; - result = CERTSVC_SUCCESS; - pkey = g_key_file_get_string(keyfile, alias, CERTSVC_PKCS12_STORAGE_KEY_PKEY, &error); - if(error && error->code == G_KEY_FILE_ERROR_KEY_NOT_FOUND) { - *count = 0; - result = CERTSVC_SUCCESS; - } - else if(error) - result = CERTSVC_FAIL; - else { - if(asprintf(&spkp, "%s/%s", CERTSVC_PKCS12_STORAGE_DIR, pkey) == -1) { - spkp = NULL; - result = CERTSVC_BAD_ALLOC; - } - else if(ssm_getinfo(spkp, &sfi, SSM_FLAG_DATA, CERTSVC_PKCS12_UNIX_GROUP) == 0) { - if((*buffer = malloc(sfi.originSize))) { - if(ssm_read(spkp, *buffer, sfi.originSize, count, SSM_FLAG_DATA, CERTSVC_PKCS12_UNIX_GROUP) != 0) { - c_certsvc_pkcs12_private_key_free(*buffer); - result = CERTSVC_FAIL; - } - } - else - result = CERTSVC_BAD_ALLOC; - } - free(spkp); - g_free(pkey); - } - g_key_file_free(keyfile); - return result; -} - -void c_certsvc_pkcs12_private_key_free(char *buffer) { - free(buffer); -} - -static void _delete_from_osp_cert_mgr(const char* path); - -static void -_delete_from_osp_cert_mgr(const char* path) -{ - - typedef int (*RemoveUserCertificatePointer)(unsigned char*, int); - typedef void (*InitAppInfoPointer)(const char*, const char*); - - static int initFlag = 0; - - unsigned char* pCertBuffer = NULL; - int certBufferLen = 0; - const char appInfo[] = "certsvcp12"; - - RemoveUserCertificatePointer pRemoveUserCertificatePointer = NULL; - InitAppInfoPointer pInit = NULL; - void* dlHandle = dlopen("/usr/lib/osp/libosp-appfw.so", RTLD_LAZY); - if (!dlHandle) - { - LOGD("Failed to open so with reason : %s", dlerror()); - goto end_of_func; - } - - pRemoveUserCertificatePointer = (RemoveUserCertificatePointer)dlsym(dlHandle, "RemoveUserCertificate"); - if (dlerror() != NULL) - { - LOGD("Failed to find RemoveUserCertificate symbol : %s", dlerror()); - goto end_of_func; - } - - if(initFlag == 0) - { - pInit = (InitAppInfoPointer)dlsym(dlHandle, "InitWebAppInfo"); - if (dlerror() != NULL) - { - LOGD("Failed to find InitWebAppInfo symbol : %s", dlerror()); - goto end_of_func; - } - - pInit(appInfo, NULL); - initFlag = 1; - } - - int result = certsvc_load_file_to_buffer(path, &pCertBuffer, &certBufferLen); - if (result != 0 ) - { - LOGD("certsvc_load_file_to_buffer Failed."); - goto end_of_func; - } - int errCode = pRemoveUserCertificatePointer(pCertBuffer, certBufferLen); - if (errCode != 0) - { - LOGD("dlHandle is not able to call function"); - goto end_of_func; - } - -end_of_func: - - if(dlHandle){ - dlclose(dlHandle); - } - return; -} - - -int certsvc_load_file_to_buffer(const char* filePath, unsigned char** certBuf, int* length) -{ - int ret = CERT_SVC_ERR_NO_ERROR; - FILE* fp_in = NULL; - unsigned long int fileSize = 0; - - /* get file size */ - if((ret = cert_svc_get_file_size(filePath, &fileSize)) != CERT_SVC_ERR_NO_ERROR) { - SECURE_SLOGE("[ERR][%s] Fail to get file size, [%s]\n", __func__, filePath); - return CERT_SVC_ERR_FILE_IO; - } - /* open file and write to buffer */ - if(!(fp_in = fopen(filePath, "rb"))) { - SECURE_SLOGE("[ERR][%s] Fail to open file, [%s]\n", __func__, filePath); - return CERT_SVC_ERR_FILE_IO; - } - - if(!(*certBuf = (unsigned char*)malloc(sizeof(unsigned char) * (unsigned int)(fileSize + 1)))) { - SLOGE("[ERR][%s] Fail to allocate memory.\n", __func__); - ret = CERT_SVC_ERR_MEMORY_ALLOCATION; - goto err; - } - memset(*certBuf, 0x00, (fileSize + 1)); - if(fread(*certBuf, sizeof(unsigned char), fileSize, fp_in) != fileSize) { - SECURE_SLOGE("[ERR][%s] Fail to read file, [%s]\n", __func__, filePath); - ret = CERT_SVC_ERR_FILE_IO; - goto err; - } - - *length = fileSize; - -err: - if(fp_in != NULL) - fclose(fp_in); - return ret; -} - -int c_certsvc_pkcs12_delete(const gchar *alias) { - gchar **certs; - gsize ncerts; - char *pkey; - char *spkp; - int result; - GKeyFile *keyfile; - gchar *data; - gsize i, length; - - data = NULL; - result = c_certsvc_pkcs12_load_certificates(alias, &certs, &ncerts); - if(result != CERTSVC_SUCCESS) - goto load_certificates_failed; - keyfile = keyfile_load(CERTSVC_PKCS12_STORAGE_PATH); - if(!keyfile) { - result = CERTSVC_IO_ERROR; - goto keyfile_load_failed; - } - pkey = g_key_file_get_string(keyfile, alias, CERTSVC_PKCS12_STORAGE_KEY_PKEY, NULL); - if(g_key_file_remove_group(keyfile, alias, NULL)) { - data = g_key_file_to_data(keyfile, &length, NULL); - if(data == NULL) { - result = CERTSVC_BAD_ALLOC; - goto keyfile_free; - } - if(!g_file_set_contents(CERTSVC_PKCS12_STORAGE_PATH, data, length, NULL)) { - result = CERTSVC_IO_ERROR; - goto data_free; - } - } - - _delete_from_osp_cert_mgr(certs[0]); - for(i = 0; i < ncerts; i++) - { - unlink(certs[i]); - } - if(pkey != NULL) { - if(asprintf(&spkp, "%s/%s", CERTSVC_PKCS12_STORAGE_DIR, pkey) == -1) { - result = CERTSVC_BAD_ALLOC; - goto data_free; - } - ssm_delete_file(spkp, SSM_FLAG_DATA, CERTSVC_PKCS12_UNIX_GROUP); - free(spkp); - } - data_free: - g_free(data); - keyfile_free: - g_key_file_free(keyfile); - keyfile_load_failed: - if(ncerts != 0) - c_certsvc_pkcs12_free_certificates(certs); - load_certificates_failed: - return result; -} - - -int cert_svc_get_file_size(const char* filepath, unsigned long int* length) -{ - int ret = CERT_SVC_ERR_NO_ERROR; - FILE* fp_in = NULL; - - if(!(fp_in = fopen(filepath, "r"))) { - SECURE_SLOGE("[ERR][%s] Fail to open file, [%s]\n", __func__, filepath); - ret = CERT_SVC_ERR_FILE_IO; - goto err; - } - - fseek(fp_in, 0L, SEEK_END); - (*length) = ftell(fp_in); - -err: - if(fp_in != NULL) - fclose(fp_in); - - return ret; -} diff --git a/vcore/src/vcore/pkcs12.cpp b/vcore/src/vcore/pkcs12.cpp new file mode 100644 index 0000000..027af07 --- /dev/null +++ b/vcore/src/vcore/pkcs12.cpp @@ -0,0 +1,1465 @@ +/** + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file pkcs12.h + * @author Jacek Migacz (j.migacz@samsung.com) + * @version 1.0 + * @brief PKCS#12 container manipulation routines. + */ +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <string.h> +#include <dirent.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <openssl/err.h> +#include <openssl/pkcs12.h> +#include <openssl/sha.h> +#include <openssl/x509.h> +#include <openssl/pem.h> +#include <db-util.h> + +#include <ss_manager.h> + +#include <cert-service.h> +#include <cert-service-util.h> +#include <cert-service-debug.h> +#include <cert-svc/cerror.h> +#include <cert-svc-client.h> + +#include <vcore/utils.h> +#include <pkcs12.h> + +#define SYSCALL(call) while(((call) == -1) && (errno == EINTR)) + +#define START_CERT "-----BEGIN CERTIFICATE-----" +#define END_CERT "-----END CERTIFICATE-----" +#define START_TRUSTED "-----BEGIN TRUSTED CERTIFICATE-----" +#define END_TRUSTED "-----END TRUSTED CERTIFICATE-----" +#define START_KEY "-----BEGIN PRIVATE KEY-----" +#define END_KEY "-----END PRIVATE KEY-----" + +#define CERTSVC_PKCS12_STORAGE_FILE "storage" + +#define CERTSVC_PKCS12_STORAGE_PATH CERTSVC_PKCS12_STORAGE_DIR "/" CERTSVC_PKCS12_STORAGE_FILE + +#define MAX_BUFFER_SIZE 16; +#define _CERT_SVC_VERIFY_PKCS12 + +static const char CERTSVC_PKCS12_STORAGE_KEY_PKEY[] = "pkey"; +static const char CERTSVC_PKCS12_STORAGE_KEY_CERTS[] = "certs"; +static const gchar CERTSVC_PKCS12_STORAGE_SEPARATOR = ';'; +static const char CERTSVC_PKCS12_UNIX_GROUP[] = "secure-storage::pkcs12"; + +sqlite3 *cert_store_db = NULL; + +static gboolean keyfile_check(const char *pathname) { + int result; + if(access(pathname, F_OK | R_OK | W_OK) == 0) + return TRUE; + SYSCALL(result = creat(pathname, S_IRUSR | S_IWUSR)); + if (result != -1) { + result = close(result); + if(result == -1) + SLOGD("Failed to close, errno : %d", errno); + return TRUE; + } else { + return FALSE; + } +} + +static GKeyFile *keyfile_load(const char *pathname) { + GKeyFile *keyfile; + GError *error; + + if(!keyfile_check(pathname)) + return NULL; + keyfile = g_key_file_new(); + error = NULL; + if(!g_key_file_load_from_file(keyfile, pathname, G_KEY_FILE_KEEP_COMMENTS, &error)) { + g_key_file_free(keyfile); + return NULL; + } + return keyfile; +} + +static int generate_random_filepath(char **filepath) { + int generator; + int64_t random; + SHA_CTX ctx; + unsigned char d[SHA_DIGEST_LENGTH]; + int result; + + if(!filepath) + return CERTSVC_WRONG_ARGUMENT; + + SYSCALL(generator = open("/dev/urandom", O_RDONLY)); + if(generator == -1) + return CERTSVC_FAIL; + SYSCALL(result = read(generator, &random, sizeof(random))); + if(result == -1) { + SYSCALL(close(generator)); + return CERTSVC_FAIL; + } + SYSCALL(result = close(generator)); + if(result == -1) + return CERTSVC_FAIL; + + SHA1_Init(&ctx); + SHA1_Update(&ctx, &random, sizeof(random)); + SHA1_Final(d, &ctx); + + result = asprintf(filepath, "%s/" \ + "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" \ + "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + CERTSVC_PKCS12_STORAGE_DIR, + d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7], d[8], d[9], + d[10], d[11], d[12], d[13], d[14], d[15], d[16], d[17], d[18], d[19]); + return (result != -1) ? CERTSVC_SUCCESS : CERTSVC_BAD_ALLOC; +} + +static int unique_filename(char **filepath, gboolean with_secure_storage) { + unsigned trial = 0x00U; + int result; + ssm_file_info_t sfi; + int exists = 1; + + for (; trial < 0xFFU; ++trial) { + result = generate_random_filepath(filepath); + if(result != CERTSVC_SUCCESS) + return result; + + exists = (access(*filepath, F_OK) == 0); + + if (with_secure_storage) + exists |= (ssm_getinfo(*filepath, &sfi, SSM_FLAG_DATA, CERTSVC_PKCS12_UNIX_GROUP) == 0); + + /* find unique filename */ + if(!exists) + return CERTSVC_SUCCESS; + + free(*filepath); + } + + return CERTSVC_FAIL; +} + +static char *bare_filename(char *filepath) { + char *needle; + if(!filepath) + return NULL; + needle = strrchr(filepath, '/'); + if(!needle) + return NULL; + return *(++needle) ? needle : NULL; +} + +int read_from_file(const char *fileName, char **certBuffer, int *length) { + + int result = CERTSVC_SUCCESS; + FILE *fp_out = NULL; + int certLength = 0; + struct stat st; + + if (stat(fileName, &st) == -1) { + SLOGE("Certificate does not exist in disable folder."); + result = CERTSVC_FAIL; + goto err; + } + + if (!(fp_out = fopen(fileName, "rb"))) { + SLOGE("Fail to open file for reading, [%s].", fileName); + result = CERTSVC_FAIL; + goto err; + } + + fseek(fp_out, 0L, SEEK_END); + certLength = ftell(fp_out); + if (certLength < 1) { + SLOGE("Fail to get certificate length."); + result = CERT_SVC_ERR_FILE_IO; + goto err; + } + + *certBuffer = (char*)malloc(sizeof(char) * ((int)certLength + 1)); + if (*certBuffer == NULL) { + SLOGE("Fail to allocate memory"); + result = CERTSVC_BAD_ALLOC; + goto err; + } + + memset(*certBuffer, 0x00, certLength+1); + rewind (fp_out); + if (fread(*certBuffer, sizeof(char), (size_t)certLength, fp_out) != (size_t)certLength) { + SLOGE("Fail to read file, [%s]", fileName); + result = CERTSVC_IO_ERROR; + goto err; + } + *length = certLength; + +err: + if (fp_out != NULL) { + fclose(fp_out); + fp_out = NULL; + } + return result; +} + +int open_db(sqlite3 **db_handle, const char *db_path) { + + int result = -1; + sqlite3 *handle; + + if (access(db_path, F_OK) == 0) { + result = db_util_open(db_path, &handle, 0); + if (result != SQLITE_OK) { + SLOGE("connect to db [%s] failed!", db_path); + return CERTSVC_FAIL; + } + *db_handle = handle; + return CERTSVC_SUCCESS; + } + SLOGD("%s DB does not exists. Create one!!", db_path); + + result = db_util_open(db_path, &handle, 0); + if (result != SQLITE_OK) { + SLOGE("connect to db [%s] failed!", db_path); + return CERTSVC_FAIL; + } + *db_handle = handle; + return CERTSVC_SUCCESS; +} + +int initialize_db() { + + int result = CERTSVC_SUCCESS; + if (cert_store_db == NULL) { + result = open_db(&cert_store_db, CERTSVC_SYSTEM_STORE_DB); + if (result != CERTSVC_SUCCESS) + SLOGE("Certsvc store DB creation failed"); + } + return result; +} + +int execute_select_query(char *query, sqlite3_stmt **stmt) { + + int result = CERTSVC_SUCCESS; + sqlite3_stmt *stmts = NULL; + + if (cert_store_db != NULL) { + sqlite3_close(cert_store_db); + cert_store_db = NULL; + } + + result = initialize_db(); + if (result != CERTSVC_SUCCESS) { + SLOGE("Failed to initialise database."); + result = CERTSVC_IO_ERROR; + goto error; + } + + result = sqlite3_prepare_v2(cert_store_db, query, strlen(query), &stmts, NULL); + if (result != SQLITE_OK) { + SLOGE("sqlite3_prepare_v2 failed [%s].", query); + result = CERTSVC_FAIL; + goto error; + } + + *stmt = stmts; + result = CERTSVC_SUCCESS; + +error: + return result; +} + +int c_certsvc_pkcs12_set_certificate_status_to_store(CertStoreType storeType, int is_root_app, char* gname, CertStatus status) { + + return vcore_client_set_certificate_status_to_store(storeType, is_root_app, gname, status); +} + +int c_certsvc_pkcs12_get_certificate_buffer_from_store(CertStoreType storeType, char* gname, char** certBuffer, size_t* certSize) { + + return vcore_client_get_certificate_from_store(storeType, gname, certBuffer, certSize, PEM_CRT); +} + +int c_certsvc_pkcs12_get_certificate_status_from_store(CertStoreType storeType, const gchar *gname, int *status) { + + return vcore_client_get_certificate_status_from_store(storeType, gname, status); +} + +int c_certsvc_pkcs12_alias_exists_in_store(CertStoreType storeType, const gchar *alias, gboolean *exists) { + + return vcore_client_check_alias_exist_in_store(storeType, alias, exists); +} + +int c_certsvc_pkcs12_private_key_load_from_store(CertStoreType storeType, const gchar *gname, char **certBuffer, size_t *certSize) { + + return vcore_client_get_certificate_from_store(storeType, gname, certBuffer, certSize, (CertType)P12_PKEY); +} + +int c_certsvc_pkcs12_delete_certificate_from_store(CertStoreType storeType, const char* gname) { + + int result = CERTSVC_SUCCESS; + + result = vcore_client_delete_certificate_from_store(storeType, gname); + if(result == CERTSVC_SUCCESS) + SLOG(LOG_INFO, "MDM_LOG_USER", "Object=certificate, AccessType=Uninstall, Result=Succeed"); + else + SLOG(LOG_INFO, "MDM_LOG_USER", "Object=certificate, AccessType=Uninstall, Result=Failed"); + + return result; +} + +int c_certsvc_pkcs12_get_certificate_alias_from_store(CertStoreType storeType, const gchar *gname, char **alias) { + + return vcore_client_get_certificate_alias_from_store(storeType, gname, alias); +} + +int c_certsvc_pkcs12_load_certificates_from_store(CertStoreType storeType, const gchar *gname, gchar ***certs, gsize *ncerts) { + return vcore_client_load_certificates_from_store(storeType, gname, (char ***)certs, (int *)ncerts); +} + +int c_certsvc_pkcs12_free_aliases_loaded_from_store(CertSvcStoreCertList** certList) { + int result = CERTSVC_SUCCESS; + CertSvcStoreCertList* tmpNode = NULL; + + while (*certList!=NULL) { + tmpNode = *certList; + if(tmpNode->title != NULL) { free(tmpNode->title); } + if(tmpNode->gname != NULL) { free(tmpNode->gname); } + (*certList) = (*certList)->next; + free(tmpNode); + } + + if (cert_store_db != NULL) { + sqlite3_close(cert_store_db); + cert_store_db = NULL; + } + certList = NULL; + return result; +} + +int c_certsvc_pkcs12_get_root_certificate_list_from_store(CertStoreType storeType, CertSvcStoreCertList** certList, int* length) { + return vcore_client_get_root_certificate_list_from_store(storeType, certList, length); +} + +int c_certsvc_pkcs12_get_end_user_certificate_list_from_store(CertStoreType storeType, CertSvcStoreCertList** certList, int* length) { + return vcore_client_get_end_user_certificate_list_from_store(storeType, certList, length); +} + +int c_certsvc_pkcs12_get_certificate_list_from_store(CertStoreType storeType, int is_root_app, CertSvcStoreCertList** certList, int* length) { + return vcore_client_get_certificate_list_from_store(storeType, is_root_app, certList, length); +} + +int install_pem_file_format_to_store(CertStoreType storeType, const char* certBuffer, int certLength, \ + const gchar *alias, const char* path, char *private_key_gname, gchar *associated_gname, CertType decideCert) { + + int result = CERTSVC_SUCCESS; + int readCount = 0; + char* fileName = NULL; + char* commonName = NULL; + char *unique = NULL; + BIO* pBio = NULL; + X509* x509Struct = NULL; + struct stat dirST; + + if (!certBuffer || !certLength) { + SLOGE("Invalid argument. certBuffer is input cert."); + return CERTSVC_WRONG_ARGUMENT; + } + + if (decideCert == PEM_CRT) { + result = unique_filename(&unique, FALSE); + if (result != CERTSVC_SUCCESS) { + SLOGE("Fail to generate unique filename."); + return result; + } + } + else + unique = (char*)path; + + if (unique == NULL) { + SLOGE("Failed to get unique file name."); + return result; + } + + /* Get common name from buffer or from file */ + if (stat(path, &dirST) != -1) { + result = get_common_name(path, NULL, &commonName); + if (result != CERTSVC_SUCCESS) { + pBio = BIO_new(BIO_s_mem()); + if (pBio == NULL) { + SLOGE("Failed to allocate memory."); + result = CERTSVC_BAD_ALLOC; + goto error; + } + + readCount = BIO_write(pBio, (const void*) certBuffer, certLength); + if (readCount < 1) { + SLOGE("Failed to load cert into bio."); + result = CERTSVC_BAD_ALLOC; + goto error; + } + + x509Struct = PEM_read_bio_X509(pBio, NULL, 0, NULL); + if (x509Struct == NULL) { + SLOGE("Failed to create x509 structure."); + result = CERTSVC_IO_ERROR; + goto error; + } + + result = get_common_name(NULL, x509Struct, &commonName); + if (result != CERTSVC_SUCCESS) { + SLOGE("CommonName is NULL"); + result = CERTSVC_FAIL; + goto error; + } + } + } + + /* storing the certificate to key-manager */ + fileName = bare_filename(unique); + if ((decideCert == P12_END_USER) && (private_key_gname != NULL)) + result = vcore_client_install_certificate_to_store(storeType, fileName, alias, private_key_gname, fileName, certBuffer, certLength, decideCert); + else if ((decideCert == P12_TRUSTED) || (decideCert == P12_INTERMEDIATE)) + result = vcore_client_install_certificate_to_store(storeType, fileName, commonName, NULL, associated_gname, certBuffer, certLength, decideCert); + else + result = vcore_client_install_certificate_to_store(storeType, fileName, commonName, NULL, fileName, certBuffer, certLength, decideCert); + + if (result != CERTSVC_SUCCESS) { + SLOGE("Failed to intall certificate. result[%d]", result); + result = CERTSVC_FAIL; + goto error; + } + + SLOGD("Success to add certificate in store."); + +error: + if (commonName) + free(commonName); + return result; +} + +int install_crt_file( + const char *path, + CertStoreType storeType, + const gchar *alias, + char *private_key_gname, + gchar *associated_gname, + CertType decideCert) +{ + int result = CERTSVC_SUCCESS; + int fileSize = 0; + int certLength = 0; + const char* header = NULL; + const char* trailer = NULL; + char* fileContent = NULL; + const char* tmpBuffer = NULL; + char* certBuffer = NULL; + const char* tailEnd = NULL; + + if (read_from_file(path, &fileContent, &fileSize)!=CERTSVC_SUCCESS) + { + SLOGE("Failed to read the file. [%s]",path); + result = CERTSVC_IO_ERROR; + goto error; + } + + tmpBuffer = fileContent; + if (decideCert == PEM_CRT) + header = strstr(tmpBuffer, START_CERT); + else if (decideCert == P12_END_USER) + header = strstr(tmpBuffer, START_CERT); + else if ((decideCert == P12_TRUSTED)||(decideCert == P12_INTERMEDIATE)) + header = strstr(tmpBuffer, START_TRUSTED); + else { + SLOGE("Invalid cert."); + result = CERTSVC_IO_ERROR; + goto error; + } + + if (header != NULL) { + /* Supports installation of only one certificate present in a CRT file */ + if (decideCert == PEM_CRT) { + trailer = strstr(header, END_CERT); + tailEnd = END_CERT; + } + else if (decideCert == P12_END_USER) { + trailer = strstr(header, END_CERT); + tailEnd = END_CERT; + } + else if ((decideCert == P12_TRUSTED)||(decideCert == P12_INTERMEDIATE)) { + trailer = strstr(header, END_TRUSTED); + tailEnd = END_TRUSTED; + } + else { + SLOGE("Invalid certificate passed."); + result = CERTSVC_IO_ERROR; + goto error; + } + + if (trailer != NULL) { + tmpBuffer = trailer; + certLength = ((int)(trailer - header) + strlen(tailEnd)); + certBuffer = (char*) malloc(sizeof(char) * (certLength+2)); + if (certBuffer == NULL) { + result = CERTSVC_BAD_ALLOC; + SLOGE("Fail to allocate memory."); + goto error; + } + + memset(certBuffer, 0x00, certLength+2); + memcpy(certBuffer, header, certLength); + certBuffer[certLength] = '\0'; + + result = install_pem_file_format_to_store(storeType, certBuffer, certLength, alias, \ + path, private_key_gname, associated_gname, decideCert); + if (result != CERTSVC_SUCCESS) { + result = CERTSVC_FAIL; + SLOGE("Fail to install certificate[%s]", path); + } + } + } + else { + SLOGE("Invalid file type passed."); + result = CERT_SVC_ERR_INVALID_CERTIFICATE; + } + +error: + if (certBuffer) + free(certBuffer); + if (fileContent) + free(fileContent); + return result; +} + +int handle_crt_pem_file_installation(CertStoreType storeType, const char *path, const gchar *alias) { + + int result = CERTSVC_SUCCESS; + + if ((strstr(path, ".crt")) != NULL || (strstr(path, ".pem")) != NULL) { + SLOGD("certificate extention is .crt/.pem file"); + + /* Installs CRT and PEM files. We will passing NULL for private_key_gname and associated_gname parameter in + * install_crt_file(). Which means that there is no private key involved in the certificate which we are + * installing and there are no other certificates related with the current certificate which is installed */ + result = install_crt_file(path, storeType, alias, NULL, NULL, PEM_CRT); + if (result != CERTSVC_SUCCESS) { + SLOGE("Failed to install the certificate."); + result = CERTSVC_FAIL; + goto error; + } + } + else { + SLOGE("Invalid certificate passed."); + result = CERTSVC_FAIL; + goto error; + } + SLOGD("Success to install the certificate."); + +error: + return result; +} + +int verify_cert_details(X509** cert, STACK_OF(X509) **certv) { + + int result = CERTSVC_SUCCESS; + char* pSubject = NULL; + char* pIssuerName = NULL; + X509_STORE_CTX *cert_ctx = NULL; + X509_STORE *cert_store = NULL; + int res = 0; + +#ifdef _CERT_SVC_VERIFY_PKCS12 + if (*certv == NULL) { + pSubject = X509_NAME_oneline((*cert)->cert_info->subject, NULL, 0); + if (!pSubject) { + SLOGE("Failed to get subject name"); + result = CERTSVC_FAIL; + goto free_memory; + } + + pIssuerName = X509_NAME_oneline((*cert)->cert_info->issuer, NULL, 0); + if (!pIssuerName) { + SLOGE("Failed to get issuer name"); + result = CERTSVC_FAIL; + goto free_memory; + } + + if (strcmp((const char*)pSubject, (const char*)pIssuerName) == 0) { + /*self signed.. */ + EVP_PKEY* pKey = NULL; + pKey = X509_get_pubkey(*cert); + if (!pKey) { + SLOGE("Failed to get public key"); + result = CERTSVC_FAIL; + goto free_memory; + } + + if (X509_verify(*cert, pKey) <= 0) { + SLOGE("P12 verification failed"); + EVP_PKEY_free(pKey); + result = CERTSVC_FAIL; + goto free_memory; + } + SLOGD("P12 verification Success"); + EVP_PKEY_free(pKey); + } + else { + cert_store = X509_STORE_new(); + if (!cert_store) { + SLOGE("Memory allocation failed"); + result = CERTSVC_FAIL; + goto free_memory; + } + + res = X509_STORE_load_locations(cert_store, NULL, "/opt/etc/ssl/certs/"); + if (res != 1) { + SLOGE("P12 load certificate store failed"); + X509_STORE_free(cert_store); + result = CERTSVC_FAIL; + goto free_memory; + } + + res = X509_STORE_set_default_paths(cert_store); + if (res != 1) { + SLOGE("P12 load certificate store path failed"); + X509_STORE_free(cert_store); + result = CERTSVC_FAIL; + goto free_memory; + } + + /* initialise store and store context */ + cert_ctx = X509_STORE_CTX_new(); + if (cert_ctx == NULL) { + SLOGE("Memory allocation failed"); + result = CERTSVC_FAIL; + goto free_memory; + } + + /* construct store context */ + if (!X509_STORE_CTX_init(cert_ctx, cert_store, *cert, NULL)) { + SLOGE("Memory allocation failed"); + result = CERTSVC_FAIL; + goto free_memory; + } + +#ifdef P12_VERIFICATION_NEEDED + res = X509_verify_cert(cert_ctx); + if (res != 1) { + SLOGE("P12 verification failed"); + result = CERTSVC_FAIL; + goto free_memory; + } + SLOGD("P12 verification Success"); +#endif + } + } + else if (*certv != NULL) { + /* Cert Chain */ + cert_store = X509_STORE_new(); + if (!cert_store) { + SLOGE("Memory allocation failed"); + result = CERTSVC_FAIL; + goto free_memory; + } + + res = X509_STORE_load_locations(cert_store, NULL, CERTSVC_SSL_CERTS_DIR); + if (res != 1) { + SLOGE("P12 load certificate store failed"); + result = CERTSVC_FAIL; + goto free_memory; + } + + res = X509_STORE_set_default_paths(cert_store); + if (res != 1) { + SLOGE("P12 load certificate path failed"); + result = CERTSVC_FAIL; + goto free_memory; + } + + /* initialise store and store context */ + cert_ctx = X509_STORE_CTX_new(); + if (cert_ctx == NULL) { + SLOGE("Memory allocation failed"); + result = CERTSVC_FAIL; + goto free_memory; + } + + /* construct store context */ + if (!X509_STORE_CTX_init(cert_ctx, cert_store, *cert, NULL)) { + SLOGE("Memory allocation failed"); + result = CERTSVC_FAIL; + goto free_memory; + } + + X509_STORE_CTX_trusted_stack(cert_ctx, *certv); +#ifdef P12_VERIFICATION_NEEDED + res = X509_verify_cert(cert_ctx); + if (res != 1) { + SLOGE("P12 verification failed"); + result = CERTSVC_FAIL; + goto free_memory; + } + SLOGD("P12 verification Success"); +#endif + } +#endif //_CERT_SVC_VERIFY_PKCS12 + +free_memory: + if (pSubject != NULL) { free(pSubject); } + if (pIssuerName != NULL) { free(pIssuerName); } + if (cert_store != NULL) { X509_STORE_free(cert_store); } + if (cert_ctx) { X509_STORE_CTX_free(cert_ctx); } + return result; +} + +int c_certsvc_pkcs12_import_from_file_to_store(CertStoreType storeTypes, const char *path, const char *password, const gchar *alias) { + + int result = CERTSVC_SUCCESS; + int readLen = 0; + int tmpLen = 0; + int nicerts = 0, i = 0, n = 0, ncerts = 0, wr_res; + CertStoreType storeType = NONE_STORE; + FILE* stream = NULL; + PKCS12* container = NULL; + EVP_PKEY* key = NULL; + X509* cert = NULL; + STACK_OF(X509) *certv = NULL; + gchar* bare = NULL; + gchar* pkvalue = NULL; + gchar** cvaluev = NULL; + gchar **certs = NULL; + char* tmpPkValue = NULL; + char* unique = NULL; + char fileBuffer[4096] = {0,}; + int loopCount = 0; + CertType decideCert = INVALID_DATA; + gboolean exists = FALSE; + + if ((!alias) || (strlen(alias) < 1) || (!path) || (strlen(path) < 1)) { + SLOGE("Invalid input parameter."); + SLOG(LOG_INFO, "MDM_LOG_USER", "Object=certificate, AccessType=Install, Result=Failed"); + return CERTSVC_WRONG_ARGUMENT; + } + + while(1) { + /* Iteration only possible from VPN_STORE till SYSTEM_STORE */ + if (loopCount == (MAX_STORE_ENUMS-1)) break; + + /* User should not install any form of certificates inside SYSTEM_STORE */ + if (((1 << loopCount) & storeTypes) == SYSTEM_STORE) { + SLOGE("Not a valid store type installing certificate, store type passed [%d].", (1 << loopCount)); + SLOG(LOG_INFO, "MDM_LOG_USER", "Object=certificate, AccessType=Install, Result=Failed"); + return CERTSVC_INVALID_STORE_TYPE; + } + + /* Iterating over all the stores */ + if ((1 << loopCount) & storeTypes) { + storeType = NONE_STORE; + storeType = (CertStoreType) (1 << loopCount); + SLOGD("Processing store type : [%s]", (storeType == VPN_STORE)? "VPN" : (storeType == WIFI_STORE)? "WIFI" : "EMAIL"); + + /* check if the alias exists before installing certificate */ + result = c_certsvc_pkcs12_alias_exists_in_store(storeType, alias, &exists); + if (result != CERTSVC_SUCCESS) { + SLOGE("Failure to access database."); + result = CERTSVC_FAIL; + goto error; + } + + if (exists!=CERTSVC_TRUE) { + SLOGE("Alias exist in store [%s].", (storeType == VPN_STORE)? "VPN" : (storeType == WIFI_STORE)? "WIFI" : "EMAIL"); + result = CERTSVC_DUPLICATED_ALIAS; + goto error; + } + + /* Logic for handling crt/pem cert installation */ + /* Check if the input file is a PEM/CRT, since a PFX cert can also be opened without a password */ + if (password == NULL && ((strstr(path, ".pfx") == NULL) || (strstr(path, ".p12")))) { + result = handle_crt_pem_file_installation(storeType, path, alias); + if (result != CERTSVC_SUCCESS) { + SLOGE("Failed to install PEM/CRT file to store."); + result = CERTSVC_FAIL; + } + loopCount++; + continue; + } + + /* Logic for handling .pfx/.p12 cert installation */ + if ((stream = fopen(path, "rb")) == NULL) { + SLOGE("Unable to open the file for reading [%s].", path); + result = CERTSVC_IO_ERROR; + goto error; + } + + if (container == NULL) { + container = d2i_PKCS12_fp(stream, NULL); + fclose(stream); + if (container == NULL) { + SLOGE("Failed to parse the input file passed."); + result = CERTSVC_FAIL; + goto error; + } + } + + /* To ensure when the code re-enters, we should clean up */ + if (key==NULL && cert==NULL && certv==NULL) { + result = PKCS12_parse(container, password, &key, &cert, &certv); + PKCS12_free(container); + if (result == CERTSVC_FAIL) { + SLOGE("Failed to parse the file passed."); + result = CERTSVC_FAIL; + goto error; + } + + result = verify_cert_details(&cert, &certv); + if (result == CERTSVC_FAIL) { + SLOGE("Failed to verify p12 certificate."); + goto error; + } + } + + nicerts = 0; + nicerts = certv ? sk_X509_num(certv) : 0; + if (cvaluev != NULL) { + for (i = 0; i < n; i++) + g_free(cvaluev[i]); + if (cvaluev) free(cvaluev); + cvaluev = NULL; + } + + n = 0; + cvaluev = (gchar **)calloc(1 + nicerts, sizeof(gchar *)); + if (unique != NULL) { free(unique); unique = NULL; } + result = unique_filename(&unique, FALSE); + if (result != CERTSVC_SUCCESS || !unique) { + SLOGE("Unique filename generation failed."); + goto error; + } + + if ((stream = fopen(unique, "w+")) == NULL) { + SLOGE("Unable to open the file for writing [%s].",unique); + result = CERTSVC_IO_ERROR; + goto error; + } + + result = PEM_write_PrivateKey(stream, key, NULL, NULL, 0, NULL, NULL); + if (result == 0) { + SLOGE("Writing the private key contents failed."); + result = CERTSVC_FAIL; + fclose(stream); + goto error; + } + + fseek(stream, 0, SEEK_SET); + memset(fileBuffer, 0, (sizeof(char)*4096)); + readLen=0; + readLen = fread(fileBuffer, sizeof(char), 4096, stream); + fclose(stream); + if (readLen <= 0){ + SLOGE("Failed to read key file"); + result = CERTSVC_FAIL; + goto error; + } + + bare = bare_filename(unique); + if (bare) { + pkvalue = g_strdup(bare); + tmpLen = strlen((const char*)pkvalue); + tmpPkValue = (char*)malloc(sizeof(char) * (tmpLen + 1)); + memset(tmpPkValue, 0x00, tmpLen+1); + memcpy(tmpPkValue, pkvalue, tmpLen); + } + + decideCert = P12_PKEY; + result = vcore_client_install_certificate_to_store(storeType, tmpPkValue, NULL, NULL, NULL, fileBuffer, readLen, decideCert); + if (result != CERTSVC_SUCCESS) { + SLOGD("Failed to store the private key contents."); + result = CERTSVC_FAIL; + goto error; + } + + unlink(unique); + if (unique!=NULL) { free(unique); unique=NULL; } + result = unique_filename(&unique, FALSE); + if (result != CERTSVC_SUCCESS || !unique) { + SLOGE("Unique filename generation failed."); + goto error; + } + + if ((stream = fopen(unique, "w")) == NULL) { + SLOGE("Unable to open the file for writing [%s].", unique); + result = CERTSVC_IO_ERROR; + goto error; + } + + result = PEM_write_X509(stream, cert); + fclose(stream); + if (result == 0) { + SLOGE("Failed to write contents to file."); + result = CERTSVC_FAIL; + goto error; + } + + bare = bare_filename(unique); + if (bare) + cvaluev[n++] = g_strdup(bare); + + wr_res = -1; + decideCert = P12_END_USER; + wr_res = install_crt_file(unique, storeType, alias, tmpPkValue, NULL, decideCert); + if (wr_res != CERTSVC_SUCCESS) { + result = CERTSVC_FAIL; + SLOGE("Failed to install the end user certificate."); + goto error; + } + + unlink(unique); + for (i=nicerts; i>0; i--) { + result = unique_filename(&unique, FALSE); + if (result != CERTSVC_SUCCESS || !unique) { + SLOGE("Unique filename generation failed."); + goto error; + } + + if ((stream = fopen(unique, "w")) == NULL) { + result = CERTSVC_IO_ERROR; + SLOGE("Unable to open the file for writing."); + goto error; + } + + result = PEM_write_X509_AUX(stream, sk_X509_value(certv, i-1)); + fclose(stream); + if (result == 0) { + result = CERTSVC_FAIL; + SLOGE("Unable to extract the certificates."); + goto error; + } + + wr_res = -1; + if (i==nicerts) + decideCert = P12_INTERMEDIATE; + else + decideCert = P12_TRUSTED; + wr_res = install_crt_file(unique, storeType, alias, NULL, cvaluev[0], decideCert); + if (wr_res != CERTSVC_SUCCESS) { + result = CERTSVC_FAIL; + goto error; + } + + unlink(unique); + bare = bare_filename(unique); + if (bare) + cvaluev[n++] = g_strdup(bare); + } + } + loopCount++; + } + +error: + /* if any certificate parsing/installation fails in middle, + * the below logic will delete the chain installed in DB */ + if (result != CERTSVC_SUCCESS) { + SLOG(LOG_INFO, "MDM_LOG_USER", "Object=certificate, AccessType=Install, Result=Failed"); + if (nicerts > 0) { + nicerts = 0; i = 0; + /* cvaluev[0] holds the end user certificate identifier which will be associated + * to chain certs. Pull the cert chain based on end user cert and delete one by one. */ + if (c_certsvc_pkcs12_load_certificates_from_store(storeType, cvaluev[0], &certs, (gsize *)&ncerts) != CERTSVC_SUCCESS) { + SLOGE("Unable to load certificates from store."); + return result; + } + + for (i=0; i<ncerts; i++) { + if (certs[i] != NULL) { + SLOGD("file to delete : %s",certs[i]); + c_certsvc_pkcs12_delete_certificate_from_store(storeType, (char *)certs[i]); + } + } + + if (certs[i] != NULL) { + for (i=0; i<ncerts; i++) + g_free(certs[i]); + } + } + } + else + SLOG(LOG_INFO, "MDM_LOG_USER", "Object=certificate, AccessType=Install, Result=Succeed"); + + if (key != NULL) EVP_PKEY_free(key); + if (cert != NULL) X509_free(cert); + if (certv != NULL) sk_X509_free(certv); + if (pkvalue != NULL) free(pkvalue); + if (tmpPkValue != NULL) free(tmpPkValue); + if (unique != NULL) free(unique); + return result; +} + + +int c_certsvc_pkcs12_alias_exists(const gchar *alias, gboolean *exists) { + GKeyFile *keyfile; + + if(exists == NULL) + return CERTSVC_WRONG_ARGUMENT; + keyfile = keyfile_load(CERTSVC_PKCS12_STORAGE_PATH); + if(!keyfile) + return CERTSVC_IO_ERROR; + *exists = g_key_file_has_group(keyfile, alias); + g_key_file_free(keyfile); + return CERTSVC_SUCCESS; +} + +int c_certsvc_pkcs12_import(const char *path, const char *password, const gchar *alias) { + int exists; + FILE *stream; + PKCS12 *container; + EVP_PKEY *key; + X509 *cert; + STACK_OF(X509) *certv; + int nicerts; + char *unique; + int result = 0; + struct stat st; + int wr_res; + GKeyFile *keyfile; + gchar *bare; + gchar *pkvalue; + gchar **cvaluev; + gsize i, n; + gchar *data; + gsize length; + int readLen = 0; + char fileBuffer[4096] = {0,}; + + certv = NULL; + pkvalue = NULL; + if(!alias || strlen(alias) < 1) + return CERTSVC_WRONG_ARGUMENT; + result = c_certsvc_pkcs12_alias_exists(alias, &exists); + if(result != CERTSVC_SUCCESS) + return result; + if(exists == TRUE) + return CERTSVC_DUPLICATED_ALIAS; + + keyfile = keyfile_load(CERTSVC_PKCS12_STORAGE_PATH); + if(!keyfile) + return CERTSVC_IO_ERROR; + if(stat(CERTSVC_PKCS12_STORAGE_PATH, &st) == -1) { + if(mkdir(CERTSVC_PKCS12_STORAGE_PATH, S_IRWXU | S_IRWXG | S_IRWXO) == -1) { + result = CERTSVC_FAIL; + goto free_keyfile; + } + } + + if((stream = fopen(path, "rb")) == NULL) { + result = CERTSVC_IO_ERROR; + goto free_keyfile; + } + container = d2i_PKCS12_fp(stream, NULL); + fclose(stream); + if(container == NULL) { + result = CERTSVC_FAIL; + goto free_keyfile; + } + + + result = PKCS12_parse(container, password, &key, &cert, &certv); + PKCS12_free(container); + if (result == 0) + { + SLOGD("Failed to parse PKCS12"); + result = CERTSVC_FAIL; + goto free_keyfile; + } + + result = verify_cert_details(&cert, &certv); + if (result == CERTSVC_FAIL) + { + SLOGE("Failed to parse the file passed."); + goto free_keyfile; + } + + nicerts = certv ? sk_X509_num(certv) : 0; + cvaluev = (gchar **)calloc(1 + nicerts, sizeof(gchar *)); + n = 0; + + result = unique_filename(&unique, TRUE); + if(result != CERTSVC_SUCCESS) + goto clean_cert_chain_and_pkey; + if((stream = fopen(unique, "w+")) == NULL) { + free(unique); + result = CERTSVC_IO_ERROR; + goto clean_cert_chain_and_pkey; + } + result = PEM_write_PrivateKey(stream, key, NULL, NULL, 0, NULL, NULL); + if(result == 0) { + result = CERTSVC_FAIL; + fclose(stream); + free(unique); + goto clean_cert_chain_and_pkey; + } + + fseek(stream, 0, SEEK_SET); + + readLen = fread(fileBuffer, sizeof(char), 4096, stream); + fclose(stream); + if(readLen <= 0){ + free(unique); + result = CERTSVC_FAIL; + SLOGE("failed to read key file"); + goto clean_cert_chain_and_pkey; + } + + wr_res = ssm_write_file(unique, SSM_FLAG_DATA, CERTSVC_PKCS12_UNIX_GROUP); + if(wr_res <= 0) { + free(unique); + result = CERTSVC_FAIL; + SLOGE("ssm_write_file failed : %d", wr_res); + goto clean_cert_chain_and_pkey; + } + unlink(unique); + + bare = bare_filename(unique); + if(bare) { + pkvalue = g_strdup(bare); + g_key_file_set_string(keyfile, alias, CERTSVC_PKCS12_STORAGE_KEY_PKEY, pkvalue); + } + free(unique); + result = unique_filename(&unique, TRUE); + if(result != CERTSVC_SUCCESS) + goto clean_cert_chain_and_pkey; + if((stream = fopen(unique, "w")) == NULL) { + free(unique); + result = CERTSVC_IO_ERROR; + goto clean_cert_chain_and_pkey; + } + result = PEM_write_X509(stream, cert); + fclose(stream); + if(result == 0) { + result = CERTSVC_FAIL; + goto clean_cert_chain_and_pkey; + } + bare = bare_filename(unique); + if(bare) + cvaluev[n++] = g_strdup(bare); + free(unique); + for(i = 0; i < (unsigned int)nicerts; i++) { + result = unique_filename(&unique, TRUE); + if(result != CERTSVC_SUCCESS) + goto clean_cert_chain_and_pkey; + if((stream = fopen(unique, "w")) == NULL) { + free(unique); + result = CERTSVC_IO_ERROR; + goto clean_cert_chain_and_pkey; + } + result = PEM_write_X509_AUX(stream, sk_X509_value(certv, i)); + fclose(stream); + if(result == 0) { + result = CERTSVC_FAIL; + goto clean_cert_chain_and_pkey; + } + bare = bare_filename(unique); + if(bare) + cvaluev[n++] = g_strdup(bare); + free(unique); + } + g_key_file_set_list_separator(keyfile, CERTSVC_PKCS12_STORAGE_SEPARATOR); + g_key_file_set_string_list(keyfile, alias, CERTSVC_PKCS12_STORAGE_KEY_CERTS, (const gchar * const *)cvaluev, n); + data = g_key_file_to_data(keyfile, &length, NULL); + if(data == NULL) { + result = CERTSVC_BAD_ALLOC; + goto clean_cert_chain_and_pkey; + } + if(!g_file_set_contents(CERTSVC_PKCS12_STORAGE_PATH, data, length, NULL)) { + result = CERTSVC_IO_ERROR; + goto free_data; + } + result = CERTSVC_SUCCESS; + + SLOGD("( %s, %s)", path, password); + + free_data: + g_free(data); + + clean_cert_chain_and_pkey: + EVP_PKEY_free(key); + X509_free(cert); + sk_X509_free(certv); + free(pkvalue); + for(i = 0; i < n; i++) { + g_free(cvaluev[i]); + } + free(cvaluev); + free_keyfile: + g_key_file_free(keyfile); + return result; +} + +int c_certsvc_pkcs12_aliases_load(gchar ***aliases, gsize *naliases) { + GKeyFile *keyfile; + + keyfile = keyfile_load(CERTSVC_PKCS12_STORAGE_PATH); + if(!keyfile) + return CERTSVC_IO_ERROR; + *aliases = g_key_file_get_groups(keyfile, naliases); + g_key_file_free(keyfile); + return CERTSVC_SUCCESS; +} + +void c_certsvc_pkcs12_aliases_free(gchar **aliases) { + g_strfreev(aliases); +} + +int c_certsvc_pkcs12_has_password(const char *filepath, gboolean *passworded) { + FILE *stream; + EVP_PKEY *pkey; + X509 *cert; + PKCS12 *container; + int result; + + if(passworded == NULL) + return CERTSVC_WRONG_ARGUMENT; + if((stream = fopen(filepath, "rb")) == NULL) + return CERTSVC_IO_ERROR; + container = d2i_PKCS12_fp(stream, NULL); + fclose(stream); + if(container == NULL) + return CERTSVC_FAIL; + result = PKCS12_parse(container, NULL, &pkey, &cert, NULL); + PKCS12_free(container); + if(result == 1) { + EVP_PKEY_free(pkey); + X509_free(cert); + *passworded = FALSE; + return CERTSVC_SUCCESS; + } + else { + if(ERR_GET_REASON(ERR_peek_last_error()) == PKCS12_R_MAC_VERIFY_FAILURE) { + *passworded = TRUE; + return CERTSVC_SUCCESS; + } + else + return CERTSVC_FAIL; + } +} + +int c_certsvc_pkcs12_load_certificates(const gchar *alias, gchar ***certs, gsize *ncerts) { + GKeyFile *keyfile; + gchar **barev; + gsize i; + keyfile = keyfile_load(CERTSVC_PKCS12_STORAGE_PATH); + if(!keyfile) + return CERTSVC_IO_ERROR; + g_key_file_set_list_separator(keyfile, CERTSVC_PKCS12_STORAGE_SEPARATOR); + barev = g_key_file_get_string_list(keyfile, alias, CERTSVC_PKCS12_STORAGE_KEY_CERTS, ncerts, NULL); + if(barev == NULL) { + *ncerts = 0; + goto free_keyfile; + } + *certs = (gchar **)g_malloc((*ncerts + 1) * sizeof(gchar *)); + for(i = 0; i < *ncerts; i++) + (*certs)[i] = g_strdup_printf("%s/%s", CERTSVC_PKCS12_STORAGE_DIR, barev[i]); + (*certs)[*ncerts] = NULL; + g_strfreev(barev); +free_keyfile: + g_key_file_free(keyfile); + return CERTSVC_SUCCESS; +} + +void c_certsvc_pkcs12_free_certificates(gchar **certs) { + gsize i = 0; + if(certs == NULL) + return; + while(certs[i]) + g_free(certs[i++]); + g_free(certs); +} + +int c_certsvc_pkcs12_private_key_load(const gchar *alias, char **buffer, gsize *count) { + GKeyFile *keyfile; + gchar *pkey; + GError *error; + char *spkp; + int result; + ssm_file_info_t sfi; + + if(!buffer) + return CERTSVC_WRONG_ARGUMENT; + keyfile = keyfile_load(CERTSVC_PKCS12_STORAGE_PATH); + if(!keyfile) + return CERTSVC_IO_ERROR; + error = NULL; + + result = CERTSVC_SUCCESS; + + pkey = g_key_file_get_string(keyfile, alias, CERTSVC_PKCS12_STORAGE_KEY_PKEY, &error); + g_key_file_free(keyfile); + + if(error && error->code == G_KEY_FILE_ERROR_KEY_NOT_FOUND) { + *count = 0; + return CERTSVC_SUCCESS; + } + + if(error) + return CERTSVC_FAIL; + + if(asprintf(&spkp, "%s/%s", CERTSVC_PKCS12_STORAGE_DIR, pkey) == -1) { + spkp = NULL; + result = CERTSVC_BAD_ALLOC; + goto out; + } + + if(ssm_getinfo(spkp, &sfi, SSM_FLAG_DATA, CERTSVC_PKCS12_UNIX_GROUP) != 0) { + //result = CERTSVC_FAIL; + goto out; + } + + if((*buffer = (char *)malloc(sfi.originSize))) { + result = CERTSVC_BAD_ALLOC; + goto out; + } + + if(ssm_read(spkp, *buffer, sfi.originSize, count, SSM_FLAG_DATA, CERTSVC_PKCS12_UNIX_GROUP) != 0) { + c_certsvc_pkcs12_private_key_free(*buffer); + result = CERTSVC_FAIL; + } + +out: + free(spkp); + g_free(pkey); + + return result; +} + +void c_certsvc_pkcs12_private_key_free(char *buffer) { + free(buffer); +} + +int certsvc_load_file_to_buffer(const char* filePath, unsigned char** certBuf, int* length) +{ + int ret = CERT_SVC_ERR_NO_ERROR; + FILE* fp_in = NULL; + unsigned long int fileSize = 0; + + /* get file size */ + if((ret = cert_svc_get_file_size(filePath, &fileSize)) != CERT_SVC_ERR_NO_ERROR) { + SLOGE("[ERR][%s] Fail to get file size, [%s]", __func__, filePath); + return CERT_SVC_ERR_FILE_IO; + } + /* open file and write to buffer */ + if(!(fp_in = fopen(filePath, "rb"))) { + SLOGE("[ERR][%s] Fail to open file, [%s]", __func__, filePath); + return CERT_SVC_ERR_FILE_IO; + } + + if(!(*certBuf = (unsigned char*)malloc(sizeof(unsigned char) * (unsigned int)(fileSize + 1)))) { + SLOGE("[ERR][%s] Fail to allocate memory.", __func__); + ret = CERT_SVC_ERR_MEMORY_ALLOCATION; + goto err; + } + memset(*certBuf, 0x00, (fileSize + 1)); + if(fread(*certBuf, sizeof(unsigned char), fileSize, fp_in) != fileSize) { + SLOGE("[ERR][%s] Fail to read file, [%s]", __func__, filePath); + ret = CERT_SVC_ERR_FILE_IO; + goto err; + } + + *length = fileSize; + +err: + if(fp_in != NULL) + fclose(fp_in); + return ret; +} + +int c_certsvc_pkcs12_delete(const gchar *alias) { + gchar **certs; + gsize ncerts; + char *pkey = NULL; + char *spkp = NULL; + int result; + GKeyFile *keyfile = NULL; + gchar *data; + gsize i, length; + + data = NULL; + result = c_certsvc_pkcs12_load_certificates(alias, &certs, &ncerts); + if(result != CERTSVC_SUCCESS) + goto load_certificates_failed; + keyfile = keyfile_load(CERTSVC_PKCS12_STORAGE_PATH); + if(!keyfile) { + result = CERTSVC_IO_ERROR; + goto keyfile_load_failed; + } + pkey = g_key_file_get_string(keyfile, alias, CERTSVC_PKCS12_STORAGE_KEY_PKEY, NULL); + if(g_key_file_remove_group(keyfile, alias, NULL)) { + data = g_key_file_to_data(keyfile, &length, NULL); + if(data == NULL) { + result = CERTSVC_BAD_ALLOC; + goto keyfile_free; + } + if(!g_file_set_contents(CERTSVC_PKCS12_STORAGE_PATH, data, length, NULL)) { + result = CERTSVC_IO_ERROR; + goto data_free; + } + } + + for(i = 0; i < ncerts; i++) + { + unlink(certs[i]); + } + if(pkey != NULL) { + if(asprintf(&spkp, "%s/%s", CERTSVC_PKCS12_STORAGE_DIR, pkey) == -1) { + result = CERTSVC_BAD_ALLOC; + goto data_free; + } + ssm_delete_file(spkp, SSM_FLAG_DATA, CERTSVC_PKCS12_UNIX_GROUP); + free(spkp); + } + data_free: + g_free(data); + keyfile_free: + g_key_file_free(keyfile); + keyfile_load_failed: + if(ncerts != 0) + c_certsvc_pkcs12_free_certificates(certs); + load_certificates_failed: + return result; +} + + +int cert_svc_get_file_size(const char* filepath, unsigned long int* length) +{ + int ret = CERT_SVC_ERR_NO_ERROR; + FILE* fp_in = NULL; + + if(!(fp_in = fopen(filepath, "r"))) { + SLOGE("[ERR][%s] Fail to open file, [%s]", __func__, filepath); + ret = CERT_SVC_ERR_FILE_IO; + goto err; + } + + fseek(fp_in, 0L, SEEK_END); + (*length) = ftell(fp_in); + +err: + if(fp_in != NULL) + fclose(fp_in); + + return ret; +} diff --git a/vcore/src/vcore/pkcs12.h b/vcore/src/vcore/pkcs12.h index c7ae668..1b6c8ab 100644 --- a/vcore/src/vcore/pkcs12.h +++ b/vcore/src/vcore/pkcs12.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,23 +23,261 @@ #define _PKCS12_H_ #include <glib.h> +#include <cert-svc/ccert.h> #ifdef __cplusplus extern "C" { #endif +/** + * Checks if the alias exist in the user store or not. + * + * @param[in] Alias Logical name for certificate bundle identification (can't be empty). + * @param[out] exists A Boolean value which states if the alias exists or not. + * @return CERTSVC_SUCCESS, CERTSVC_IO_ERROR, CERTSVC_WRONG_ARGUMENT. + */ int c_certsvc_pkcs12_alias_exists(const gchar *alias, gboolean *exists); + +/** + * To import the p12/pfx file to user store. + * + * @param[in] path Path to file. + * @param[in] password Password for opening the file. + * @param[in] alias Logical name for certificate bundle identification (can't be empty). + * @return CERTSVC_SUCCESS, CERTSVC_FAIL, CERTSVC_DUPLICATED_ALIAS, CERTSVC_IO_ERROR, CERTSVC_WRONG_ARGUMENT, CERTSVC_BAD_ALLOC. + */ int c_certsvc_pkcs12_import(const char *path, const char *password, const gchar *alias); + +/** + * To import the p12/pfx/crt/pem file to specified store (WIFI_STORE/VPN_STORE/EMAIL_STORE). + * + * @param[in] storeType Refers to WIFI_STORE / VPN_STORE / EMAIL_STORE / ALL_STORE. + * @param[in] path Path to file. + * @param[in] password Password for opening the file. + * @param[in] alias Logical name for certificate bundle identification (can't be empty). + * @return CERTSVC_SUCCESS, CERTSVC_FAIL, CERTSVC_DUPLICATED_ALIAS, CERTSVC_IO_ERROR, CERTSVC_WRONG_ARGUMENT, CERTSVC_BAD_ALLOC. + */ +int c_certsvc_pkcs12_import_from_file_to_store(CertStoreType storeType, const char *path, const char *password, const gchar *alias); + +/** + * To get the list of certificate information present in a store. User will be getting + * the information in a linked list where every list will contain Alias, Path to certificate, + * Certificate status of all the certificates present in the specified store. + * + * @param[in] storeType Refers to VPN_STORE / WIFI_STORE / EMAIL_STORE / SYSTEM_STORE / ALL_STORE. + * @param[in] is_root_app If set to ENABLED, can get all the certs without any restriction (should be used only by master application). + * If set to DISABLED, only certs which are enabled by master application can only be retrieved. + * @param[out] certList Linked-list having all the information about each certificate present in a store. + * @param[out] length provides the length of the linked list. + * @return CERTSVC_SUCCESS, CERTSVC_FAIL, CERTSVC_IO_ERROR, CERTSVC_WRONG_ARGUMENT, CERTSVC_INVALID_STORE_TYPE. + */ +int c_certsvc_pkcs12_get_certificate_list_from_store(CertStoreType storeType, int is_root_app, CertSvcStoreCertList** certList, int* length); + +/** + * To set the status for a specified certificate in a particular store to enabled / disabled. + * The gname is the key for accessing the certificate. + * + * @param[in] storeType Refers to VPN_STORE / WIFI_STORE / EMAIL_STORE / SYSTEM_STORE / ALL_STORE. + * @param[in] gname Referred as group name, is the key for accessing the certificate. + * @param[in] is_root_app Set as ENABLED/DISABLED. Enabled, if used by master application is changing the status. Disabled, should be used by other applications. + * @param[in] status Allows to set the status of the certificate to enabled / disabled. + * @return CERTSVC_SUCCESS, CERTSVC_FAIL, CERTSVC_IO_ERROR, CERTSVC_WRONG_ARGUMENT, CERTSVC_INVALID_STORE_TYPE. + */ +int c_certsvc_pkcs12_set_certificate_status_to_store(CertStoreType storeType, int is_root_app, char* gname, CertStatus status); + +/** + * To get the status (enabled/disabled) for the specified certificate in a particular store. + * + * @param[in] storeType Refers to VPN_STORE / WIFI_STORE / EMAIL_STORE / SYSTEM_STORE / ALL_STORE. + * @param[in] gname Referred as group name, is the key for accessing the certificate. + * @param[out] status Returns the status of the certificate. It will be set Disable=0, Enable=1, Fail=-1. + * @return CERTSVC_SUCCESS, CERTSVC_FAIL, CERTSVC_ALIAS_DOES_NOT_EXIST, CERTSVC_IO_ERROR + */ +int c_certsvc_pkcs12_get_certificate_status_from_store(CertStoreType storeType, const gchar *gname, int *status); + +/** + * To get the encoded form of the specified certificate from the specified store. + * + * @param[in] storeType Refers to VPN_STORE / WIFI_STORE / EMAIL_STORE / SYSTEM_STORE / ALL_STORE. + * @param[in] gname Referred as group name, is the key for accessing the certificate. + * @param[out] certBuffer Which will be having the encoded value of the certificate requested. + * @param[out] certSize Which will be having the size of the buffer. + * @return CERTSVC_SUCCESS, CERTSVC_FAIL, CERTSVC_IO_ERROR, CERTSVC_WRONG_ARGUMENT, CERTSVC_INVALID_STORE_TYPE. + */ +int c_certsvc_pkcs12_get_certificate_buffer_from_store(CertStoreType storeType, char* gname, char** certBuffer, size_t* certSize); + +/** + * To delete the certificate from the specified store (VPN_STORE, WIFI_STORE, EMAIL_STORE, SYSTEM_STORE, ALL_STORE). + * + * @param[in] storeType Refers to VPN_STORE / WIFI_STORE / EMAIL_STORE / SYSTEM_STORE / ALL_STORE. + * @param[in] gname Referred as group name, is the key for accessing the certificate. + * @return CERTSVC_SUCCESS, CERTSVC_FAIL, CERTSVC_IO_ERROR, CERTSVC_INVALID_STORE_TYPE. + */ +int c_certsvc_pkcs12_delete_certificate_from_store(CertStoreType storeType, const char* gname); + +/** + * To free the certificate list which got generated from + * c_certsvc_pkcs12_get_certificate_list_from_store() function. + * + * @param[in] certList Linked-list having all the information about each certificate present in a store. + * @return CERTSVC_SUCCESS, CERTSVC_FAIL. + */ +int c_certsvc_pkcs12_free_aliases_loaded_from_store(CertSvcStoreCertList** certList); + +/** + * Checks if the alias exist in the user store or not. + * + * @param[in] storeType Refers to VPN_STORE / WIFI_STORE / EMAIL_STORE / SYSTEM_STORE / ALL_STORE. + * @param[in] Alias Logical name for certificate bundle identification (can't be empty). + * @param[out] exists A Boolean value which states if the alias exists or not. + * @return CERTSVC_SUCCESS, CERTSVC_IO_ERROR, CERTSVC_WRONG_ARGUMENT. + */ +int c_certsvc_pkcs12_alias_exists_in_store(CertStoreType storeType, const gchar *alias, gboolean *exists); + +/** + * Function to get the size of the file passed. + * + * @param[in] storeType Refers to VPN_STORE / WIFI_STORE / EMAIL_STORE / SYSTEM_STORE / ALL_STORE. + * @param[in] gname Refers to unique name referring to the certificate. + * @param[out] certs Provides the list of certificates matching the unique name provided. + * @param[out] ncerts Provides the number of certs in certs. + * @return CERTSVC_SUCCESS, CERTSVC_FAIL, CERTSVC_IO_ERROR, CERTSVC_WRONG_ARGUMENT, CERTSVC_INVALID_STORE_TYPE. + */ +int c_certsvc_pkcs12_load_certificates_from_store(CertStoreType storeType, const gchar *gname, gchar ***certs, gsize *ncerts); + +/** + * To load the private key for the specified certificate mapped by an Alias. + * + * @param[in] alias Logical name for certificate bundle identification (can't be empty). + * @param[out] pkey Will hold the private key value of the certificate. + * @param[out] count Will hold the siz of the private key buffer. + * @return CERTSVC_SUCCESS, CERTSVC_FAIL, CERTSVC_IO_ERROR, CERTSVC_WRONG_ARGUMENT, CERTSVC_BAD_ALLOC. + */ +int c_certsvc_pkcs12_private_key_load_from_store(CertStoreType storeType, const gchar *gname, char **pkey, gsize *count); + +/** + * Gets the alias name for the gname passed. + * + * @param[in] instance CertSvcInstance object. + * @param[in] gname Certificate identification of pfx/pkcs file. + * @param[out] alias Alias name for the given gname. + * @return CERTSVC_SUCCESS, CERTSVC_FAIL, CERTSVC_WRONG_ARGUMENT + */ +int c_certsvc_pkcs12_get_certificate_alias_from_store(CertStoreType storeType, const gchar *gname, char **alias); + +/** + * To get the list of only end user certificate information present in a store. User will be getting + * the information in a linked list where every list will contain Alias, Path to certificate, + * Certificate status of all the certificates present in the specified store. + * + * @param[in] storeType Refers to VPN_STORE / WIFI_STORE / EMAIL_STORE / SYSTEM_STORE / ALL_STORE. + * @param[out] certList Linked-list having all the information about each certificate present in a store. + * @param[out] length provides the length of the linked list. + * @return CERTSVC_SUCCESS, CERTSVC_FAIL, CERTSVC_IO_ERROR, CERTSVC_WRONG_ARGUMENT, CERTSVC_INVALID_STORE_TYPE. + */ +int c_certsvc_pkcs12_get_end_user_certificate_list_from_store(CertStoreType storeType, CertSvcStoreCertList** certList, int* length); + +/** + * To get the list of only root/trusted certificate information present in a store. User will be getting + * the information in a linked list where every list will contain Alias, Path to certificate, + * Certificate status of all the certificates present in the specified store. + * + * @param[in] storeType Refers to VPN_STORE / WIFI_STORE / EMAIL_STORE / SYSTEM_STORE / ALL_STORE. + * @param[out] certList Linked-list having all the information about each certificate present in a store. + * @param[out] length provides the length of the linked list. + * @return CERTSVC_SUCCESS, CERTSVC_FAIL, CERTSVC_IO_ERROR, CERTSVC_WRONG_ARGUMENT, CERTSVC_INVALID_STORE_TYPE. + */ +int c_certsvc_pkcs12_get_root_certificate_list_from_store(CertStoreType storeType, CertSvcStoreCertList** certList, int* length); + +/** + * Function to load all the alias list present in the user store. + * + * @param[out] aliases Which holds all the list of aliases present in the store. + * @param[out] naliases Provides the number of aliases present in the store. + * @return CERTSVC_SUCCESS, CERTSVC_FAIL, CERTSVC_IO_ERROR. + */ int c_certsvc_pkcs12_aliases_load(gchar ***aliases, gsize *naliases); + +/** + * To free all the aliases which were loaded previously from + * c_certsvc_pkcs12_aliases_load() function. + * + * @param[in] aliases Which holds all the list of aliases present in the store. + */ void c_certsvc_pkcs12_aliases_free(gchar **aliases); + +/** + * TO check if the p12/pfx file is protected by password or not. + * + * @param[in] filePath Where the file is located. + * @param[out] passworded A boolean value to state if the file is protected by password or not. + * @return CERTSVC_SUCCESS, CERTSVC_FAIL, CERTSVC_IO_ERROR, CERTSVC_WRONG_ARGUMENT. + */ int c_certsvc_pkcs12_has_password(const char *filepath, gboolean *passworded); + +/** + * To load all the certificates matching the given alias. + * + * @param[in] alias Logical name for certificate bundle identification (can't be empty). + * @param[out] certificates The pointer holding all the certificates buffer in memory. + * @param[out] ncertificates Holds the number of certificates returned. + * @return CERTSVC_SUCCESS, CERTSVC_FAIL, CERTSVC_IO_ERROR, CERTSVC_WRONG_ARGUMENT. + */ int c_certsvc_pkcs12_load_certificates(const gchar *alias, gchar ***certificates, gsize *ncertificates); + +/** + * To free the certificates from memory which was loaded by + * c_certsvc_pkcs12_load_certificates() functon. + * + * @param[in] certs A pointer holding all the certificates in memory. + * @return CERTSVC_SUCCESS, CERTSVC_FAIL, CERTSVC_IO_ERROR. + */ void c_certsvc_pkcs12_free_certificates(gchar **certs); + +/** + * To load the private key for the specified certificate mapped by an Alias. + * + * @param[in] alias Logical name for certificate bundle identification (can't be empty). + * @param[out] pkey Will hold the private key value of the certificate. + * @param[out] count Will hold the siz of the private key buffer. + * @return CERTSVC_SUCCESS, CERTSVC_FAIL, CERTSVC_IO_ERROR, CERTSVC_WRONG_ARGUMENT, CERTSVC_BAD_ALLOC. + */ int c_certsvc_pkcs12_private_key_load(const gchar *alias, char **pkey, gsize *count); + +/** + * To free the private key buffer previously loaded by + * c_certsvc_pkcs12_private_key_load() function. + * + * @param[in] buffer Holding the private key values. + */ void c_certsvc_pkcs12_private_key_free(char *buffer); + +/** + * Function to delete the certificate present in the user store. + * + * @param[in] alias Logical name for certificate bundle identification (can't be empty). + * @return CERTSVC_SUCCESS, CERTSVC_FAIL, CERTSVC_IO_ERROR, CERTSVC_WRONG_ARGUMENT, CERTSVC_BAD_ALLOC. + */ int c_certsvc_pkcs12_delete(const gchar *alias); //static void _delete_from_osp_cert_mgr(const char* path); + +/** + * Function to load the file to buffer. + * + * @param[in] filePath Which points to the location where the file is present. + * @param[out] certBuf Which will hold the certificate information. + * @param[out] length Which will hold the file size. + * @return CERTSVC_SUCCESS, CERTSVC_FAIL, CERT_SVC_ERR_FILE_IO, CERT_SVC_ERR_MEMORY_ALLOCATION. + */ int certsvc_load_file_to_buffer(const char* filePath, unsigned char** certBuf, int* length); + +/** + * Function to get the size of the file passed. + * + * @param[in] filepath Which points to the location where the file is present. + * @param[out] length Which will hold the file size. + * @return CERTSVC_SUCCESS, CERTSVC_FAIL, CERTSVC_IO_ERROR, CERTSVC_WRONG_ARGUMENT, CERTSVC_INVALID_STORE_TYPE. + */ int cert_svc_get_file_size(const char* filepath, unsigned long int* length); #ifdef __cplusplus diff --git a/vcore/src/vcore/scoped_gpointer.h b/vcore/src/vcore/scoped_gpointer.h index 78772df..aec26a9 100644 --- a/vcore/src/vcore/scoped_gpointer.h +++ b/vcore/src/vcore/scoped_gpointer.h @@ -45,10 +45,10 @@ struct ScopedGPointerPolicy }; template <typename Class> -class ScopedGPointer : public DPL::ScopedResource<ScopedGPointerPolicy> +class ScopedGPointer : public VcoreDPL::ScopedResource<ScopedGPointerPolicy> { typedef ScopedGPointerPolicy Policy; - typedef DPL::ScopedResource<Policy> BaseType; + typedef VcoreDPL::ScopedResource<Policy> BaseType; public: explicit ScopedGPointer(typename Policy::Type pointer = diff --git a/vcore/src/vcore/utils.c b/vcore/src/vcore/utils.c new file mode 100644 index 0000000..db26653 --- /dev/null +++ b/vcore/src/vcore/utils.c @@ -0,0 +1,156 @@ +#include <cert-service.h> +#include <cert-service-debug.h> +#include <cert-svc/cerror.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "utils.h" + +void _copy_field(const unsigned char *in, unsigned char **out) +{ + size_t in_len = strlen((const char *)(in)); + + *out = (unsigned char *)malloc(sizeof(unsigned char) * (in_len + 1)); + if (!(*out)) { + LOGE("Failed to allocate memory."); + return; + } + + memcpy(*out, in, in_len + 1); +} + +char *get_complete_path(const char *str1, const char *str2) +{ + size_t str1_len = strlen(str1); + char *result = NULL; + int as_result; + + if (str1[str1_len - 1] != '/') + as_result = asprintf(&result, "%s/%s", str1, str2); + else + as_result = asprintf(&result, "%s%s", str1, str2); + + if (as_result < 0) + return NULL; + + return result; +} + + +int get_common_name(const char *path, struct x509_st *x509Struct, char **commonName) +{ + int result = CERTSVC_SUCCESS; + const unsigned char* data = NULL; + CERT_CONTEXT* context = NULL; + unsigned char *_commonName = NULL; + unsigned char *tmpSubjectStr = NULL; + cert_svc_name_fld_data *certFieldData = NULL; + + if (!path && !x509Struct) { + LOGE("Invalid input parameter."); + return CERTSVC_WRONG_ARGUMENT; + } + + /* If x509Struct is empty, we need to read the certificate and construct the x509 structure */ + if (!x509Struct) { + context = cert_svc_cert_context_init(); + if (!context) { + LOGE("Failed to allocate memory."); + return CERTSVC_BAD_ALLOC; + } + + result = cert_svc_load_file_to_context(context, path); + if (result != CERT_SVC_ERR_NO_ERROR) { + LOGE("Failed to load file into context."); + result = CERTSVC_FAIL; + goto err; + } + + if (!context->certBuf || !context->certBuf->data) { + LOGE("Empty certificate buffer."); + result = CERTSVC_FAIL; + goto err; + } + + data = context->certBuf->data; + d2i_X509(&x509Struct, &data, context->certBuf->size); + + if (!x509Struct) { + LOGE("[ERR][%s] Fail to construct X509 structure.", __func__); + result = CERT_SVC_ERR_INVALID_CERTIFICATE; + goto err; + } + } + + /* At this point we assume that we have the x509Struct filled with information */ + tmpSubjectStr = (unsigned char *)X509_NAME_oneline((x509Struct->cert_info->subject), NULL, 0); + if (!tmpSubjectStr) { + LOGE("[ERR][%s] Fail to parse certificate.", __func__); + result = CERTSVC_FAIL; + goto err; + } + + certFieldData = (cert_svc_name_fld_data *)malloc(sizeof(cert_svc_name_fld_data)); + if (!certFieldData) { + LOGE("Failed to allocate memory."); + result = CERTSVC_BAD_ALLOC; + goto err; + } + + certFieldData->commonName = NULL; + certFieldData->organizationName = NULL; + certFieldData->organizationUnitName = NULL; + certFieldData->emailAddress = NULL; + + result = cert_svc_util_parse_name_fld_data(tmpSubjectStr, certFieldData); + if (result != CERT_SVC_ERR_NO_ERROR) { + LOGE("[ERR][%s] Fail to parse cert_svc_name_fld_data.", __func__); + result = CERTSVC_FAIL; + goto err; + } + + result = CERTSVC_SUCCESS; + + if (certFieldData->commonName) + _copy_field(certFieldData->commonName, &_commonName); + else if (certFieldData->organizationName) + _copy_field(certFieldData->organizationName, &_commonName); + else if (certFieldData->organizationUnitName) + _copy_field(certFieldData->organizationUnitName, &_commonName); + else if (certFieldData->emailAddress) + _copy_field(certFieldData->emailAddress, &_commonName); + + if (!_commonName) { + LOGE("Failed to get common name"); + result = CERTSVC_FAIL; + goto err; + } + + *commonName = (char *)_commonName; + LOGD("Success to get common name for title. commonname[%s]", *commonName); + +err: + if (x509Struct) + X509_free(x509Struct); + + if (context) + cert_svc_cert_context_final(context); + + if (tmpSubjectStr) + OPENSSL_free(tmpSubjectStr); + + if (certFieldData) { + free(certFieldData->countryName); + free(certFieldData->localityName); + free(certFieldData->stateOrProvinceName); + free(certFieldData->organizationName); + free(certFieldData->organizationUnitName); + free(certFieldData->commonName); + free(certFieldData->emailAddress); + free(certFieldData); + } + + return result; +} diff --git a/vcore/src/vcore/utils.h b/vcore/src/vcore/utils.h new file mode 100644 index 0000000..2752b51 --- /dev/null +++ b/vcore/src/vcore/utils.h @@ -0,0 +1,14 @@ +#pragma once + +#include <openssl/x509.h> + +#ifdef __cplusplus +extern "C" { +#endif + +char *get_complete_path(const char *str1, const char *str2); +int get_common_name(const char *path, struct x509_st *x509Struct, char **commonName); + +#ifdef __cplusplus +} +#endif |