celix_status_t remoteServiceAdmin_create()

in bundles/remote_services/remote_service_admin_dfi/src/remote_service_admin_dfi.c [194:316]


celix_status_t remoteServiceAdmin_create(celix_bundle_context_t *context, remote_service_admin_t **admin) {
    celix_status_t status = CELIX_SUCCESS;

    *admin = calloc(1, sizeof(**admin));

    if (!*admin) {
        status = CELIX_ENOMEM;
    } else {
        (*admin)->context = context;
        (*admin)->exportedServices = hashMap_create(NULL, NULL, NULL, NULL);
        (*admin)->importedServices = celix_arrayList_create();

         celixThreadRwlock_create(&(*admin)->exportedServicesLock, NULL);
         celixThreadMutex_create(&(*admin)->importedServicesLock, NULL);

        (*admin)->importedEndpointUrls = celix_stringHashMap_create();//Ignore ENOMEM for now and deal with it on other PRs in the future

        (*admin)->loghelper = celix_logHelper_create(context, "celix_rsa_admin");

        long port = celix_bundleContext_getPropertyAsLong(context, RSA_PORT_KEY, RSA_PORT_DEFAULT);
        const char *ip = celix_bundleContext_getProperty(context, RSA_IP_KEY, RSA_IP_DEFAULT);
        const char *interface = celix_bundleContext_getProperty(context, RSA_INTERFACE_KEY, NULL);
        (*admin)->curlShareEnabled = celix_bundleContext_getPropertyAsBool(context, RSA_DFI_USE_CURL_SHARE_HANDLE, RSA_DFI_USE_CURL_SHARE_HANDLE_DEFAULT);

        (*admin)->dynamicIpSupport = celix_bundleContext_getPropertyAsBool(context, CELIX_RSA_DFI_DYNAMIC_IP_SUPPORT, CELIX_RSA_DFI_DYNAMIC_IP_SUPPORT_DEFAULT);

        char *detectedIp = NULL;
        if ((interface != NULL) && (remoteServiceAdmin_getIpAddress((char*)interface, &detectedIp) != CELIX_SUCCESS)) {
            celix_logHelper_log((*admin)->loghelper, CELIX_LOG_LEVEL_WARNING, "RSA: Could not retrieve IP address for interface %s", interface);
        }
        if (detectedIp != NULL) {
            ip = detectedIp;
            (*admin)->discoveryInterface = celix_utils_strdup(interface);
        } else {
            (*admin)->discoveryInterface = remoteServiceAdmin_getIFNameForIP(ip);
        }

        if (ip != NULL) {
            celix_logHelper_log((*admin)->loghelper, CELIX_LOG_LEVEL_DEBUG, "RSA: Using %s for service annunciation", ip);
            (*admin)->ip = strdup(ip);
        }

        if (detectedIp != NULL) {
            free(detectedIp);
        }

        (*admin)->curlShare = curl_share_init();
        curl_share_setopt((*admin)->curlShare, CURLSHOPT_SHARE, CURL_LOCK_DATA_CONNECT);
        curl_share_setopt((*admin)->curlShare, CURLSHOPT_SHARE, CURL_LOCK_DATA_COOKIE);
        curl_share_setopt((*admin)->curlShare, CURLSHOPT_SHARE, CURL_LOCK_DATA_DNS);
        curl_share_setopt((*admin)->curlShare, CURLSHOPT_USERDATA, *admin);

        curl_share_setopt((*admin)->curlShare, CURLSHOPT_LOCKFUNC, remoteServiceAdmin_curlshare_lock);
        curl_share_setopt((*admin)->curlShare, CURLSHOPT_UNLOCKFUNC, remoteServiceAdmin_curlshare_unlock);

        if(status == CELIX_SUCCESS && pthread_mutex_init(&(*admin)->curlMutexConnect, NULL) != 0) {
            fprintf(stderr, "Could not initialize mutex connect\n");
            status = EPERM;
        }

        if(status == CELIX_SUCCESS && pthread_mutex_init(&(*admin)->curlMutexCookie, NULL) != 0) {
            fprintf(stderr, "Could not initialize mutex cookie\n");
            status = EPERM;
        }

        if(status == CELIX_SUCCESS && pthread_mutex_init(&(*admin)->curlMutexDns, NULL) != 0) {
            fprintf(stderr, "Could not initialize mutex dns\n");
            status = EPERM;
        }

        remoteServiceAdmin_setupStopExportsThread(*admin);

        // Prepare callbacks structure. We have only one callback, the rest are NULL.
        struct mg_callbacks callbacks;
        memset(&callbacks, 0, sizeof(callbacks));
        callbacks.begin_request = remoteServiceAdmin_callback;

        char newPort[10];
        snprintf(newPort, 10, "%li", port);

        unsigned int port_counter = 0;
        bool bindToAllInterfaces = celix_bundleContext_getPropertyAsBool(context, CELIX_RSA_BIND_ON_ALL_INTERFACES, CELIX_RSA_BIND_ON_ALL_INTERFACES_DEFAULT);
        do {
            char *listeningPorts = NULL;
            if (bindToAllInterfaces || (*admin)->dynamicIpSupport) {
                asprintf(&listeningPorts,"0.0.0.0:%s", newPort);
            } else {
                asprintf(&listeningPorts,"%s:%s", (*admin)->ip, newPort);
            }

            const char *options[] = { "listening_ports", listeningPorts, "num_threads", "5", NULL};

            (*admin)->ctx = mg_start(&callbacks, (*admin), options);

            if ((*admin)->ctx != NULL) {
                celix_logHelper_log((*admin)->loghelper, CELIX_LOG_LEVEL_INFO, "RSA: Start webserver: %s", listeningPorts);
                (*admin)->port = strdup(newPort);

            } else {
                celix_logHelper_log((*admin)->loghelper, CELIX_LOG_LEVEL_ERROR, "Error while starting rsa server on port %s - retrying on port %li...", newPort, port + port_counter);
                snprintf(newPort, 10,  "%li", port + port_counter++);
            }

            free(listeningPorts);

        } while (((*admin)->ctx == NULL) && (port_counter < MAX_NUMBER_OF_RESTARTS));
    }

    bool logCalls = celix_bundleContext_getPropertyAsBool(context, RSA_LOG_CALLS_KEY, RSA_LOG_CALLS_DEFAULT);
    if (logCalls) {
        const char *f = celix_bundleContext_getProperty(context, RSA_LOG_CALLS_FILE_KEY, RSA_LOG_CALLS_FILE_DEFAULT);
        if (strncmp(f, "stdout", strlen("stdout")) == 0) {
            (*admin)->logFile = stdout;
        } else {
            (*admin)->logFile = fopen(f, "w");
            if ( (*admin)->logFile == NULL) {
                celix_logHelper_log((*admin)->loghelper, CELIX_LOG_LEVEL_WARNING, "Error opening file '%s' for logging calls. %s", f, strerror(errno));
            }
        }
    }

    return status;
}