STATUS createCurlApiCallbacks()

in src/source/CurlApiCallbacks.c [10:180]


STATUS createCurlApiCallbacks(PCallbacksProvider pCallbacksProvider, PCHAR region, API_CALL_CACHE_TYPE cacheType, UINT64 endpointCachingPeriod,
                              PCHAR controlPlaneUrl, PCHAR certPath, PCHAR userAgentNamePostfix, PCHAR customUserAgent,
                              PCurlApiCallbacks* ppCurlApiCallbacks)
{
    ENTERS();
    STATUS retStatus = STATUS_SUCCESS, status;
    PCurlApiCallbacks pCurlApiCallbacks = NULL;

    CHK(pCallbacksProvider != NULL && ppCurlApiCallbacks != NULL, STATUS_NULL_ARG);
    CHK(certPath == NULL || STRNLEN(certPath, MAX_PATH_LEN + 1) <= MAX_PATH_LEN, STATUS_INVALID_CERT_PATH_LENGTH);
    CHK(customUserAgent == NULL || STRNLEN(customUserAgent, MAX_CUSTOM_USER_AGENT_LEN + 1) <= MAX_CUSTOM_USER_AGENT_LEN,
        STATUS_MAX_CUSTOM_USER_AGENT_LEN_EXCEEDED);
    CHK(userAgentNamePostfix == NULL ||
            STRNLEN(userAgentNamePostfix, MAX_CUSTOM_USER_AGENT_NAME_POSTFIX_LEN + 1) <= MAX_CUSTOM_USER_AGENT_NAME_POSTFIX_LEN,
        STATUS_MAX_USER_AGENT_NAME_POSTFIX_LEN_EXCEEDED);

    CHK(endpointCachingPeriod <= MAX_ENDPOINT_CACHE_UPDATE_PERIOD, STATUS_INVALID_ENDPOINT_CACHING_PERIOD);

    // Fix-up the endpoint TTL value
    if (endpointCachingPeriod == ENDPOINT_UPDATE_PERIOD_SENTINEL_VALUE) {
        endpointCachingPeriod = DEFAULT_ENDPOINT_CACHE_UPDATE_PERIOD;
    }

    // Allocate the entire structure
    pCurlApiCallbacks = (PCurlApiCallbacks) MEMCALLOC(1, SIZEOF(CurlApiCallbacks));
    CHK(pCurlApiCallbacks != NULL, STATUS_NOT_ENOUGH_MEMORY);

    // Set the version, self
    pCurlApiCallbacks->apiCallbacks.version = API_CALLBACKS_CURRENT_VERSION;
    pCurlApiCallbacks->apiCallbacks.customData = (UINT64) pCurlApiCallbacks;
    pCurlApiCallbacks->streamingRequestCount = 0;

    // Endpoint period will be the same for all streams
    pCurlApiCallbacks->cacheUpdatePeriod = endpointCachingPeriod;

    // API call caching type
    pCurlApiCallbacks->cacheType = cacheType;

    // Set invalid guard locks
    pCurlApiCallbacks->activeRequestsLock = INVALID_MUTEX_VALUE;
    pCurlApiCallbacks->activeUploadsLock = INVALID_MUTEX_VALUE;
    pCurlApiCallbacks->cachedEndpointsLock = INVALID_MUTEX_VALUE;
    pCurlApiCallbacks->shutdownLock = INVALID_MUTEX_VALUE;

    // Store the back pointer as we will be using the other callbacks
    pCurlApiCallbacks->pCallbacksProvider = pCallbacksProvider;

    // Set the callbacks
    pCurlApiCallbacks->apiCallbacks.createStreamFn = createStreamCachingCurl;
    pCurlApiCallbacks->apiCallbacks.describeStreamFn = describeStreamCachingCurl;
    pCurlApiCallbacks->apiCallbacks.getStreamingEndpointFn = getStreamingEndpointCachingCurl;
    pCurlApiCallbacks->apiCallbacks.tagResourceFn = tagResourceCachingCurl;

    pCurlApiCallbacks->apiCallbacks.createDeviceFn = createDeviceCurl;
    pCurlApiCallbacks->apiCallbacks.putStreamFn = putStreamCurl;
    pCurlApiCallbacks->apiCallbacks.freeApiCallbacksFn = freeApiCallbacksCurl;

    if (region == NULL || region[0] == '\0') {
        STRCPY(pCurlApiCallbacks->region, DEFAULT_AWS_REGION);
    } else {
        STRNCPY(pCurlApiCallbacks->region, region, MAX_REGION_NAME_LEN);
        pCurlApiCallbacks->region[MAX_REGION_NAME_LEN] = '\0';
    }

    status = getUserAgentString(userAgentNamePostfix, customUserAgent, MAX_USER_AGENT_LEN, pCurlApiCallbacks->userAgent);
    pCurlApiCallbacks->userAgent[MAX_USER_AGENT_LEN] = '\0';
    if (STATUS_FAILED(status)) {
        DLOGW("Failed to generate user agent string with error 0x%08x.", status);
    }

    // Set the control plane URL
    if (controlPlaneUrl == NULL || controlPlaneUrl[0] == '\0') {
        // Create a fully qualified URI
        SNPRINTF(pCurlApiCallbacks->controlPlaneUrl, MAX_URI_CHAR_LEN, "%s%s.%s%s", CONTROL_PLANE_URI_PREFIX, KINESIS_VIDEO_SERVICE_NAME,
                 pCurlApiCallbacks->region, CONTROL_PLANE_URI_POSTFIX);
    } else {
        STRNCPY(pCurlApiCallbacks->controlPlaneUrl, controlPlaneUrl, MAX_URI_CHAR_LEN);
    }

    // NULL terminate in case we overrun
    pCurlApiCallbacks->controlPlaneUrl[MAX_URI_CHAR_LEN] = '\0';

    if (certPath != NULL) {
        STRNCPY(pCurlApiCallbacks->certPath, certPath, MAX_PATH_LEN);
    } else {
        // empty cert path
        pCurlApiCallbacks->certPath[0] = '\0';
    }

    // Create the tracking ongoing requests
    CHK_STATUS(hashTableCreateWithParams(STREAM_MAPPING_HASH_TABLE_BUCKET_COUNT, STREAM_MAPPING_HASH_TABLE_BUCKET_LENGTH,
                                         &pCurlApiCallbacks->pActiveRequests));
    CHK_STATUS(doubleListCreate(&pCurlApiCallbacks->pActiveUploads));

    // Create the hash table for tracking endpoints
    CHK_STATUS(hashTableCreateWithParams(STREAM_MAPPING_HASH_TABLE_BUCKET_COUNT, STREAM_MAPPING_HASH_TABLE_BUCKET_LENGTH,
                                         &pCurlApiCallbacks->pCachedEndpoints));

    CHK_STATUS(hashTableCreateWithParams(STREAM_MAPPING_HASH_TABLE_BUCKET_COUNT, STREAM_MAPPING_HASH_TABLE_BUCKET_LENGTH,
                                         &pCurlApiCallbacks->pStreamsShuttingDown));

    // Create the guard locks
    pCurlApiCallbacks->activeUploadsLock = pCallbacksProvider->clientCallbacks.createMutexFn(pCallbacksProvider->clientCallbacks.customData, TRUE);
    CHK(pCurlApiCallbacks->activeUploadsLock != INVALID_MUTEX_VALUE, STATUS_INVALID_OPERATION);
    pCurlApiCallbacks->activeRequestsLock = pCallbacksProvider->clientCallbacks.createMutexFn(pCallbacksProvider->clientCallbacks.customData, TRUE);
    CHK(pCurlApiCallbacks->activeRequestsLock != INVALID_MUTEX_VALUE, STATUS_INVALID_OPERATION);
    pCurlApiCallbacks->cachedEndpointsLock = pCallbacksProvider->clientCallbacks.createMutexFn(pCallbacksProvider->clientCallbacks.customData, TRUE);
    CHK(pCurlApiCallbacks->cachedEndpointsLock != INVALID_MUTEX_VALUE, STATUS_INVALID_OPERATION);
    pCurlApiCallbacks->shutdownLock = pCallbacksProvider->clientCallbacks.createMutexFn(pCallbacksProvider->clientCallbacks.customData, TRUE);
    CHK(pCurlApiCallbacks->shutdownLock != INVALID_MUTEX_VALUE, STATUS_INVALID_OPERATION);

#if !defined __WINDOWS_BUILD__
    signal(SIGPIPE, SIG_IGN);
#endif

    // Testability hooks initialization
    pCurlApiCallbacks->hookCustomData = 0;
    pCurlApiCallbacks->curlEasyPerformHookFn = NULL;
    pCurlApiCallbacks->curlWriteCallbackHookFn = NULL;
    pCurlApiCallbacks->curlReadCallbackHookFn = NULL;
    // end testability hooks initialization

    // Initialize the global ssl callbacks
    CHK_STATUS(initializeSslCallbacks());

    // CURL global initialization
    CHK(0 == curl_global_init(CURL_GLOBAL_ALL), STATUS_CURL_LIBRARY_INIT_FAILED);

    // Not in shutdown
    ATOMIC_STORE_BOOL(&pCurlApiCallbacks->shutdown, FALSE);

    // Prepare the Stream callbacks
    pCurlApiCallbacks->streamCallbacks.version = STREAM_CALLBACKS_CURRENT_VERSION;
    pCurlApiCallbacks->streamCallbacks.customData = (UINT64) pCurlApiCallbacks;
    pCurlApiCallbacks->streamCallbacks.streamDataAvailableFn = dataAvailableCurl;
    pCurlApiCallbacks->streamCallbacks.streamClosedFn = streamClosedCurl;
    pCurlApiCallbacks->streamCallbacks.streamErrorReportFn = NULL;
    pCurlApiCallbacks->streamCallbacks.fragmentAckReceivedFn = fragmentAckReceivedCurl;
    pCurlApiCallbacks->streamCallbacks.streamShutdownFn = shutdownStreamCurl;

    // Prepare the Producer callbacks
    pCurlApiCallbacks->producerCallbacks.version = PRODUCER_CALLBACKS_CURRENT_VERSION;
    pCurlApiCallbacks->producerCallbacks.customData = (UINT64) pCurlApiCallbacks;
    pCurlApiCallbacks->producerCallbacks.clientShutdownFn = clientShutdownCurl;

    // Append to the API callback chain
    CHK_STATUS(addApiCallbacks((PClientCallbacks) pCallbacksProvider, (PApiCallbacks) pCurlApiCallbacks));

    // Append the stream callbacks to the Stream callback chain
    CHK_STATUS(addStreamCallbacks((PClientCallbacks) pCallbacksProvider, &pCurlApiCallbacks->streamCallbacks));

    // Append the producer callbacks to the Producer callback chain
    CHK_STATUS(addProducerCallbacks((PClientCallbacks) pCallbacksProvider, &pCurlApiCallbacks->producerCallbacks));

CleanUp:

    CHK_LOG_ERR(retStatus);

    if (STATUS_FAILED(retStatus)) {
        freeCurlApiCallbacks(&pCurlApiCallbacks);
        pCurlApiCallbacks = NULL;
    }

    // Set the return value if it's not NULL
    if (ppCurlApiCallbacks != NULL) {
        *ppCurlApiCallbacks = pCurlApiCallbacks;
    }

    LEAVES();
    return retStatus;
}