blob: f090223e6e34332d4d85acd597572375c95c423c [file] [log] [blame]
/**
*Licensed to the Apache Software Foundation (ASF) under one
*or more contributor license agreements. See the NOTICE file
*distributed with this work for additional information
*regarding copyright ownership. The ASF licenses this file
*to you 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.
*/
/*
* remote_service_admin_impl.c
*
* \date Sep 14, 2013
* \author <a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
* \copyright Apache License, Version 2.0
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/sem.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>
#include <uuid/uuid.h>
#include "remote_service_admin_shm.h"
#include "remote_service_admin_shm_impl.h"
#include "export_registration_impl.h"
#include "import_registration_impl.h"
#include "remote_constants.h"
#include "constants.h"
#include "utils.h"
#include "bundle_context.h"
#include "bundle.h"
#include "service_reference.h"
#include "service_registration.h"
static celix_status_t remoteServiceAdmin_lock(int semId, int semNr);
static celix_status_t remoteServiceAdmin_unlock(int semId, int semNr);
static int remoteServiceAdmin_getCount(int semId, int semNr);
celix_status_t remoteServiceAdmin_installEndpoint(remote_service_admin_pt admin, export_registration_pt registration, service_reference_pt reference, char *interface);
celix_status_t remoteServiceAdmin_createEndpointDescription(remote_service_admin_pt admin, service_reference_pt reference, properties_pt endpointProperties, char *interface, endpoint_description_pt *description);
celix_status_t remoteServiceAdmin_createOrAttachShm(hash_map_pt ipcSegment, remote_service_admin_pt admin, endpoint_description_pt endpointDescription, bool createIfNotFound);
celix_status_t remoteServiceAdmin_getIpcSegment(remote_service_admin_pt admin, endpoint_description_pt endpointDescription, ipc_segment_pt* ipc);
celix_status_t remoteServiceAdmin_detachIpcSegment(ipc_segment_pt ipc);
celix_status_t remoteServiceAdmin_deleteIpcSegment(ipc_segment_pt ipc);
celix_status_t remoteServiceAdmin_getSharedIdentifierFile(remote_service_admin_pt admin, char *fwUuid, char* servicename, char* outFile);
celix_status_t remoteServiceAdmin_removeSharedIdentityFile(remote_service_admin_pt admin, char *fwUuid, char* servicename);
celix_status_t remoteServiceAdmin_removeSharedIdentityFiles(remote_service_admin_pt admin);
celix_status_t remoteServiceAdmin_create(bundle_context_pt context, remote_service_admin_pt *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 = hashMap_create(utils_stringHash, NULL, utils_stringEquals, NULL);
(*admin)->exportedIpcSegment = hashMap_create(NULL, NULL, NULL, NULL);
(*admin)->importedIpcSegment = hashMap_create(NULL, NULL, NULL, NULL);
(*admin)->pollThread = hashMap_create(NULL, NULL, NULL, NULL);
(*admin)->pollThreadRunning = hashMap_create(NULL, NULL, NULL, NULL);
if (logHelper_create(context, &(*admin)->loghelper) == CELIX_SUCCESS) {
logHelper_start((*admin)->loghelper);
}
}
return status;
}
celix_status_t remoteServiceAdmin_destroy(remote_service_admin_pt* admin) {
celix_status_t status = CELIX_SUCCESS;
hashMap_destroy((*admin)->exportedServices, false, false);
hashMap_destroy((*admin)->importedServices, false, false);
hashMap_destroy((*admin)->exportedIpcSegment, false, false);
hashMap_destroy((*admin)->importedIpcSegment, false, false);
hashMap_destroy((*admin)->pollThread, false, false);
hashMap_destroy((*admin)->pollThreadRunning, false, false);
free(*admin);
*admin = NULL;
return status;
}
celix_status_t remoteServiceAdmin_stop(remote_service_admin_pt admin) {
celix_status_t status = CELIX_SUCCESS;
celixThreadMutex_lock(&admin->exportedServicesLock);
hash_map_iterator_pt iter = hashMapIterator_create(admin->exportedServices);
while (hashMapIterator_hasNext(iter)) {
array_list_pt exports = hashMapIterator_nextValue(iter);
int i;
for (i = 0; i < arrayList_size(exports); i++) {
export_registration_pt export = arrayList_get(exports, i);
exportRegistration_stopTracking(export);
}
}
hashMapIterator_destroy(iter);
celixThreadMutex_unlock(&admin->exportedServicesLock);
celixThreadMutex_lock(&admin->importedServicesLock);
iter = hashMapIterator_create(admin->importedServices);
while (hashMapIterator_hasNext(iter)) {
hash_map_entry_pt entry = hashMapIterator_nextEntry(iter);
char* service = hashMapEntry_getKey(entry);
import_registration_factory_pt importFactory = hashMapEntry_getValue(entry);
if (importFactory != NULL) {
int i;
for (i = 0; i < arrayList_size(importFactory->registrations); i++) {
import_registration_pt importRegistration = arrayList_get(importFactory->registrations, i);
if (importFactory->trackedFactory != NULL) {
importFactory->trackedFactory->unregisterProxyService(importFactory->trackedFactory->factory, importRegistration->endpointDescription);
}
}
serviceTracker_close(importFactory->proxyFactoryTracker);
importRegistrationFactory_close(importFactory);
hashMap_remove(admin->importedServices, service);
importRegistrationFactory_destroy(&importFactory);
}
}
hashMapIterator_destroy(iter);
celixThreadMutex_unlock(&admin->importedServicesLock);
// set stop-thread-variable
iter = hashMapIterator_create(admin->pollThreadRunning);
while (hashMapIterator_hasNext(iter)) {
bool *pollThreadRunning = hashMapIterator_nextValue(iter);
*pollThreadRunning = false;
}
hashMapIterator_destroy(iter);
// release lock
iter = hashMapIterator_create(admin->exportedIpcSegment);
while (hashMapIterator_hasNext(iter)) {
ipc_segment_pt ipc = hashMapIterator_nextValue(iter);
remoteServiceAdmin_unlock(ipc->semId, 1);
}
hashMapIterator_destroy(iter);
// wait till threads has stopped
iter = hashMapIterator_create(admin->pollThread);
while (hashMapIterator_hasNext(iter)) {
celix_thread_t *pollThread = hashMapIterator_nextValue(iter);
if (pollThread != NULL) {
status = celixThread_join(*pollThread, NULL);
}
}
hashMapIterator_destroy(iter);
iter = hashMapIterator_create(admin->importedIpcSegment);
while (hashMapIterator_hasNext(iter)) {
ipc_segment_pt ipc = hashMapIterator_nextValue(iter);
remoteServiceAdmin_detachIpcSegment(ipc);
free(ipc);
}
hashMapIterator_destroy(iter);
iter = hashMapIterator_create(admin->exportedIpcSegment);
while (hashMapIterator_hasNext(iter)) {
ipc_segment_pt ipc = hashMapIterator_nextValue(iter);
remoteServiceAdmin_deleteIpcSegment(ipc);
free(ipc);
}
hashMapIterator_destroy(iter);
remoteServiceAdmin_removeSharedIdentityFiles(admin);
logHelper_stop(admin->loghelper);
logHelper_destroy(&admin->loghelper);
return status;
}
static int remoteServiceAdmin_getCount(int semId, int semNr) {
int token = -1;
unsigned short semVals[3];
union semun semArg;
semArg.array = semVals;
if (semctl(semId, 0, GETALL, semArg) == 0) {
token = semArg.array[semNr];
}
return token;
}
static celix_status_t remoteServiceAdmin_lock(int semId, int semNr) {
celix_status_t status = CELIX_SUCCESS;
int semOpStatus = 0;
struct sembuf semOperation;
semOperation.sem_num = semNr;
semOperation.sem_op = -1;
semOperation.sem_flg = 0;
do {
status = CELIX_SUCCESS;
if ((semOpStatus = semop(semId, &semOperation, 1)) != 0) {
status = CELIX_BUNDLE_EXCEPTION;
}
} while (semOpStatus == -1 && errno == EINTR);
return status;
}
static celix_status_t remoteServiceAdmin_unlock(int semId, int semNr) {
celix_status_t status = CELIX_SUCCESS;
int semOpStatus = 0;
struct sembuf semOperation;
semOperation.sem_num = semNr;
semOperation.sem_op = 1;
semOperation.sem_flg = 0;
do {
status = CELIX_SUCCESS;
if ((semOpStatus = semop(semId, &semOperation, 1)) != 0) {
status = CELIX_BUNDLE_EXCEPTION;
}
} while (semOpStatus == -1 && errno == EINTR);
return status;
}
celix_status_t remoteServiceAdmin_send(remote_service_admin_pt admin, endpoint_description_pt recpEndpoint, char *request, char **reply, int *replyStatus) {
celix_status_t status = CELIX_SUCCESS;
ipc_segment_pt ipc = NULL;
if ((ipc = hashMap_get(admin->importedIpcSegment, recpEndpoint->service)) != NULL) {
int semid = ipc->semId;
/* lock critical area */
remoteServiceAdmin_lock(semid, 0);
/* write method and data */
strcpy(ipc->shmBaseAdress, request);
/* Check the status of the send-receive semaphore and reset them if not correct */
if (remoteServiceAdmin_getCount(ipc->semId, 1) > 0) {
semctl(semid, 1, SETVAL, (int) 0);
}
if (remoteServiceAdmin_getCount(ipc->semId, 2) > 0) {
semctl(semid, 2, SETVAL, (int) 0);
}
/* Inform receiver we are invoking the remote service */
remoteServiceAdmin_unlock(semid, 1);
/* Wait until the receiver finished his operations */
remoteServiceAdmin_lock(semid, 2);
/* read reply */
*reply = strdup(ipc->shmBaseAdress);
/* TODO: fix replyStatus */
*replyStatus = 0;
/* release critical area */
remoteServiceAdmin_unlock(semid, 0);
} else {
status = CELIX_ILLEGAL_STATE; /* could not find ipc segment */
}
return status;
}
static void * remoteServiceAdmin_receiveFromSharedMemory(void *data) {
recv_shm_thread_pt thread_data = data;
remote_service_admin_pt admin = thread_data->admin;
endpoint_description_pt exportedEndpointDesc = thread_data->endpointDescription;
ipc_segment_pt ipc;
if ((ipc = hashMap_get(admin->exportedIpcSegment, exportedEndpointDesc->service)) != NULL) {
bool *pollThreadRunning = hashMap_get(admin->pollThreadRunning, exportedEndpointDesc);
while (*pollThreadRunning == true) {
if ((remoteServiceAdmin_lock(ipc->semId, 1) == CELIX_SUCCESS) && (*pollThreadRunning == true)) {
// TODO: align data size
char *data = calloc(1024, sizeof(*data));
strcpy(data, ipc->shmBaseAdress);
hash_map_iterator_pt iter = hashMapIterator_create(admin->exportedServices);
while (hashMapIterator_hasNext(iter)) {
hash_map_entry_pt entry = hashMapIterator_nextEntry(iter);
array_list_pt exports = hashMapEntry_getValue(entry);
int expIt = 0;
for (expIt = 0; expIt < arrayList_size(exports); expIt++) {
export_registration_pt export = arrayList_get(exports, expIt);
if ((strcmp(exportedEndpointDesc->service, export->endpointDescription->service) == 0) && (export->endpoint != NULL)) {
char *reply = NULL;
/* TODO: fix handling of handleRequest return value*/
export->endpoint->handleRequest(export->endpoint->endpoint, data, &reply);
if (reply != NULL) {
if ((strlen(reply) * sizeof(char)) >= RSA_SHM_MEMSIZE) {
logHelper_log(admin->loghelper, OSGI_LOGSERVICE_ERROR, "receiveFromSharedMemory : size of message bigger than shared memory message. NOT SENDING.");
} else {
strcpy(ipc->shmBaseAdress, reply);
}
free(reply);
}
} else {
logHelper_log(admin->loghelper, OSGI_LOGSERVICE_ERROR, "receiveFromSharedMemory : No endpoint set for %s.", export->endpointDescription->service);
}
}
}
hashMapIterator_destroy(iter);
free(data);
remoteServiceAdmin_unlock(ipc->semId, 2);
}
}
}
free(data);
return NULL;
}
celix_status_t remoteServiceAdmin_getSharedIdentifierFile(remote_service_admin_pt admin, char *fwUuid, char* servicename, char* outFile) {
celix_status_t status = CELIX_SUCCESS;
snprintf(outFile, RSA_FILEPATH_LENGTH, "%s/%s/%s", P_tmpdir, fwUuid, servicename);
if (access(outFile, F_OK) != 0) {
char tmpDir[RSA_FILEPATH_LENGTH];
snprintf(tmpDir, RSA_FILEPATH_LENGTH, "%s/%s", P_tmpdir, fwUuid);
if(mkdir(tmpDir, 0755) == -1 ){
logHelper_log(admin->loghelper, OSGI_LOGSERVICE_ERROR, "error while creating directory %s (%s)", tmpDir, strerror(errno));
}
FILE *shid_file = fopen(outFile, "wb");
if (shid_file == NULL) {
logHelper_log(admin->loghelper, OSGI_LOGSERVICE_ERROR, "error while creating shared identifier file %s (%s)", outFile, strerror(errno));
status = CELIX_FILE_IO_EXCEPTION;
} else {
logHelper_log(admin->loghelper, OSGI_LOGSERVICE_DEBUG, "create shared identifier file %s", outFile);
fclose(shid_file);
}
} else {
logHelper_log(admin->loghelper, OSGI_LOGSERVICE_DEBUG, "shared identifier file %s already exists", outFile);
}
return status;
}
celix_status_t remoteServiceAdmin_removeSharedIdentityFile(remote_service_admin_pt admin, char *fwUuid, char* servicename) {
celix_status_t status = CELIX_SUCCESS;
char tmpPath[RSA_FILEPATH_LENGTH];
int retVal = 0;
snprintf(tmpPath, RSA_FILEPATH_LENGTH, "%s/%s/%s", P_tmpdir, fwUuid, servicename);
retVal = unlink(tmpPath);
if (retVal == 0) {
logHelper_log(admin->loghelper, OSGI_LOGSERVICE_DEBUG, "Removed shared identifier file %s", tmpPath);
} else {
logHelper_log(admin->loghelper, OSGI_LOGSERVICE_ERROR, "Cannot remove shared identifier file %s", tmpPath);
status = CELIX_FILE_IO_EXCEPTION;
}
return status;
}
celix_status_t remoteServiceAdmin_removeSharedIdentityFiles(remote_service_admin_pt admin) {
char tmpDir[RSA_FILEPATH_LENGTH];
const char* fwUuid = NULL;
bundleContext_getProperty(admin->context, OSGI_FRAMEWORK_FRAMEWORK_UUID, &fwUuid);
snprintf(tmpDir, RSA_FILEPATH_LENGTH, "%s/%s", P_tmpdir, fwUuid);
DIR *d = opendir(tmpDir);
size_t path_len = strlen(tmpDir);
int retVal = 0;
if (d) {
struct dirent *p;
while (!retVal && (p = readdir(d))) {
char* f_name;
size_t len;
if (!strcmp(p->d_name, ".") || !strcmp(p->d_name, "..")) {
continue;
}
len = path_len + strlen(p->d_name) + 2;
f_name = (char*) calloc(len, 1);
if (f_name) {
snprintf(f_name, len, "%s/%s", tmpDir, p->d_name);
retVal = unlink(f_name);
if(retVal==0){
logHelper_log(admin->loghelper, OSGI_LOGSERVICE_WARNING, "Removed shared identifier file %s (unproper clean-up?)", f_name);
}
else{
logHelper_log(admin->loghelper, OSGI_LOGSERVICE_WARNING, "Unable to remove shared identifier file %s ", f_name);
}
}
free(f_name);
}
}
closedir(d);
if (!retVal) {
rmdir(tmpDir);
}
return retVal;
}
celix_status_t remoteServiceAdmin_exportService(remote_service_admin_pt admin, char *serviceId, properties_pt properties, array_list_pt *registrations) {
celix_status_t status = CELIX_SUCCESS;
arrayList_create(registrations);
array_list_pt references = NULL;
service_reference_pt reference = NULL;
char filter[256];
const char *exportsProp = NULL;
const char *providedProp = NULL;
snprintf(filter, 256, "(%s=%s)", (char *) OSGI_FRAMEWORK_SERVICE_ID, serviceId);
bundleContext_getServiceReferences(admin->context, NULL, filter, &references);
if (arrayList_size(references) >= 1) {
reference = arrayList_get(references, 0);
}
arrayList_destroy(references);
serviceReference_getProperty(reference, (char *) OSGI_RSA_SERVICE_EXPORTED_INTERFACES, &exportsProp);
serviceReference_getProperty(reference, (char *) OSGI_FRAMEWORK_OBJECTCLASS, &providedProp);
char* exports = strndup(exportsProp, 1024*10);
char* provided = strndup(providedProp, 1024*10);
if (reference == NULL) {
logHelper_log(admin->loghelper, OSGI_LOGSERVICE_ERROR, "expected a reference for service id %s.", serviceId);
status = CELIX_ILLEGAL_STATE;
}
else if (exports == NULL || provided == NULL) {
logHelper_log(admin->loghelper, OSGI_LOGSERVICE_WARNING, "No Services to export.");
} else {
logHelper_log(admin->loghelper, OSGI_LOGSERVICE_INFO, "Export services (%s)", exports);
array_list_pt interfaces = NULL;
arrayList_create(&interfaces);
if (strcmp(utils_stringTrim(exports), "*") == 0) {
char *provided_save_ptr = NULL;
char *interface = strtok_r(provided, ",", &provided_save_ptr);
while (interface != NULL) {
arrayList_add(interfaces, utils_stringTrim(interface));
interface = strtok_r(NULL, ",", &provided_save_ptr);
}
} else {
char *provided_save_ptr = NULL;
char *pinterface = strtok_r(provided, ",", &provided_save_ptr);
while (pinterface != NULL) {
char *exports_save_ptr = NULL;
char *einterface = strtok_r(exports, ",", &exports_save_ptr);
while (einterface != NULL) {
if (strcmp(einterface, pinterface) == 0) {
arrayList_add(interfaces, einterface);
}
einterface = strtok_r(NULL, ",", &exports_save_ptr);
}
pinterface = strtok_r(NULL, ",", &provided_save_ptr);
}
}
if (arrayList_size(interfaces) != 0) {
int iter = 0;
for (iter = 0; iter < arrayList_size(interfaces); iter++) {
char *interface = arrayList_get(interfaces, iter);
export_registration_pt registration = NULL;
exportRegistration_create(admin->loghelper, reference, NULL, admin, admin->context, &registration);
arrayList_add(*registrations, registration);
remoteServiceAdmin_installEndpoint(admin, registration, reference, interface);
exportRegistration_open(registration);
exportRegistration_startTracking(registration);
if (remoteServiceAdmin_createOrAttachShm(admin->exportedIpcSegment, admin, registration->endpointDescription, true) == CELIX_SUCCESS) {
recv_shm_thread_pt recvThreadData = NULL;
if ((recvThreadData = calloc(1, sizeof(*recvThreadData))) == NULL) {
status = CELIX_ENOMEM;
} else {
recvThreadData->admin = admin;
recvThreadData->endpointDescription = registration->endpointDescription;
celix_thread_t* pollThread = calloc(1, sizeof(*pollThread));
bool *pollThreadRunningPtr = calloc(1, sizeof(*pollThreadRunningPtr));
*pollThreadRunningPtr = true;
hashMap_put(admin->pollThreadRunning, registration->endpointDescription, pollThreadRunningPtr);
// start receiving thread
status = celixThread_create(pollThread, NULL, remoteServiceAdmin_receiveFromSharedMemory, recvThreadData);
hashMap_put(admin->pollThread, registration->endpointDescription, pollThread);
}
}
}
celixThreadMutex_lock(&admin->exportedServicesLock);
hashMap_put(admin->exportedServices, reference, *registrations);
celixThreadMutex_unlock(&admin->exportedServicesLock);
}
arrayList_destroy(interfaces);
}
free(exports);
free(provided);
return status;
}
celix_status_t remoteServiceAdmin_removeExportedService(remote_service_admin_pt admin, export_registration_pt registration) {
celix_status_t status;
ipc_segment_pt ipc = NULL;
export_reference_pt ref = NULL;
status = exportRegistration_getExportReference(registration, &ref);
if (status == CELIX_SUCCESS) {
bool *pollThreadRunning = NULL;
service_reference_pt servRef;
celixThreadMutex_lock(&admin->exportedServicesLock);
exportReference_getExportedService(ref, &servRef);
array_list_pt exports = (array_list_pt)hashMap_remove(admin->exportedServices, servRef);
if(exports!=NULL){
arrayList_destroy(exports);
}
exportRegistration_close(registration);
if ((pollThreadRunning = hashMap_get(admin->pollThreadRunning, registration->endpointDescription)) != NULL) {
*pollThreadRunning = false;
if ((ipc = hashMap_get(admin->exportedIpcSegment, registration->endpointDescription->service)) != NULL) {
celix_thread_t* pollThread;
remoteServiceAdmin_unlock(ipc->semId, 1);
if ((pollThread = hashMap_get(admin->pollThread, registration->endpointDescription)) != NULL) {
status = celixThread_join(*pollThread, NULL);
if (status == CELIX_SUCCESS) {
semctl(ipc->semId, 1 , IPC_RMID);
shmctl(ipc->shmId, IPC_RMID, 0);
remoteServiceAdmin_removeSharedIdentityFile(admin, registration->endpointDescription->frameworkUUID, registration->endpointDescription->service);
hashMap_remove(admin->pollThreadRunning, registration->endpointDescription);
hashMap_remove(admin->exportedIpcSegment, registration->endpointDescription->service);
hashMap_remove(admin->pollThread, registration->endpointDescription);
free(pollThreadRunning);
free(pollThread);
free(ipc);
}
}
}
}
exportRegistration_destroy(&registration);
}
if(ref!=NULL){
free(ref);
}
celixThreadMutex_unlock(&admin->exportedServicesLock);
return status;
}
celix_status_t remoteServiceAdmin_getIpcSegment(remote_service_admin_pt admin, endpoint_description_pt endpointDescription, ipc_segment_pt* ipc) {
(*ipc) = (hashMap_containsKey(admin->importedIpcSegment, endpointDescription) == true) ? hashMap_get(admin->importedIpcSegment, endpointDescription) : NULL;
return (*ipc != NULL) ? CELIX_SUCCESS : CELIX_ILLEGAL_ARGUMENT;
}
celix_status_t remoteServiceAdmin_detachIpcSegment(ipc_segment_pt ipc) {
return (shmdt(ipc->shmBaseAdress) != -1) ? CELIX_SUCCESS : CELIX_BUNDLE_EXCEPTION;
}
celix_status_t remoteServiceAdmin_deleteIpcSegment(ipc_segment_pt ipc) {
return ((semctl(ipc->semId, 1 /*ignored*/, IPC_RMID) != -1) && (shmctl(ipc->shmId, IPC_RMID, 0) != -1)) ? CELIX_SUCCESS : CELIX_BUNDLE_EXCEPTION;
}
celix_status_t remoteServiceAdmin_createOrAttachShm(hash_map_pt ipcSegment, remote_service_admin_pt admin, endpoint_description_pt endpointDescription, bool createIfNotFound) {
celix_status_t status = CELIX_SUCCESS;
/* setup ipc sehment */
ipc_segment_pt ipc = NULL;
properties_pt endpointProperties = endpointDescription->properties;
char *shmPath = NULL;
char *shmFtokId = NULL;
char *semPath = NULL;
char *semFtokId = NULL;
if ((shmPath = (char*)properties_get(endpointProperties, (char *) RSA_SHM_PATH_PROPERTYNAME)) == NULL) {
logHelper_log(admin->loghelper, OSGI_LOGSERVICE_DEBUG, "No value found for key %s in endpointProperties.", RSA_SHM_PATH_PROPERTYNAME);
status = CELIX_BUNDLE_EXCEPTION;
} else if ((shmFtokId = (char*)properties_get(endpointProperties, (char *) RSA_SHM_FTOK_ID_PROPERTYNAME)) == NULL) {
logHelper_log(admin->loghelper, OSGI_LOGSERVICE_DEBUG, "No value found for key %s in endpointProperties.", RSA_SHM_FTOK_ID_PROPERTYNAME);
status = CELIX_BUNDLE_EXCEPTION;
} else if ((semPath = (char*)properties_get(endpointProperties, (char *) RSA_SEM_PATH_PROPERTYNAME)) == NULL) {
logHelper_log(admin->loghelper, OSGI_LOGSERVICE_DEBUG, "No value found for key %s in endpointProperties.", RSA_SEM_PATH_PROPERTYNAME);
status = CELIX_BUNDLE_EXCEPTION;
} else if ((semFtokId = (char*)properties_get(endpointProperties, (char *) RSA_SEM_FTOK_ID_PROPERTYNAME)) == NULL) {
logHelper_log(admin->loghelper, OSGI_LOGSERVICE_DEBUG, "No value found for key %s in endpointProperties.", RSA_SEM_FTOK_ID_PROPERTYNAME);
status = CELIX_BUNDLE_EXCEPTION;
} else {
key_t shmKey = ftok(shmPath, atoi(shmFtokId));
ipc = calloc(1, sizeof(*ipc));
if(ipc == NULL){
return CELIX_ENOMEM;
}
if ((ipc->shmId = shmget(shmKey, RSA_SHM_MEMSIZE, 0666)) < 0) {
logHelper_log(admin->loghelper, OSGI_LOGSERVICE_WARNING, "Could not attach to shared memory");
if (createIfNotFound == true) {
if ((ipc->shmId = shmget(shmKey, RSA_SHM_MEMSIZE, IPC_CREAT | 0666)) < 0) {
logHelper_log(admin->loghelper, OSGI_LOGSERVICE_ERROR, "Creation of shared memory segment failed.");
status = CELIX_BUNDLE_EXCEPTION;
} else if ((ipc->shmBaseAdress = shmat(ipc->shmId, 0, 0)) == (char *) -1) {
logHelper_log(admin->loghelper, OSGI_LOGSERVICE_ERROR, "Attaching of shared memory segment failed.");
status = CELIX_BUNDLE_EXCEPTION;
} else {
logHelper_log(admin->loghelper, OSGI_LOGSERVICE_INFO, "shared memory segment sucessfully created at %p.", ipc->shmBaseAdress);
}
}
} else if ((ipc->shmBaseAdress = shmat(ipc->shmId, 0, 0)) == (char *) -1) {
logHelper_log(admin->loghelper, OSGI_LOGSERVICE_ERROR, "Attaching to shared memory segment failed.");
status = CELIX_BUNDLE_EXCEPTION;
} else {
logHelper_log(admin->loghelper, OSGI_LOGSERVICE_INFO, "sucessfully attached to shared memory at %p.", ipc->shmBaseAdress);
}
}
if(ipc != NULL && status == CELIX_SUCCESS){
key_t semkey = ftok(semPath, atoi(semFtokId));
int semflg = (createIfNotFound == true) ? (0666 | IPC_CREAT) : (0666);
int semid = semget(semkey, 3, semflg);
if (semid != -1) {
// only reset semaphores if a create was supposed
if ((createIfNotFound == true) && ((semctl(semid, 0, SETVAL, (int) 1) == -1) || (semctl(semid, 1, SETVAL, (int) 0) == -1) || (semctl(semid, 2, SETVAL, (int) 0) == -1))) {
logHelper_log(admin->loghelper, OSGI_LOGSERVICE_ERROR, "error while initialize semaphores.");
}
logHelper_log(admin->loghelper, OSGI_LOGSERVICE_DEBUG, "semaphores w/ key %s and id %i added.", endpointDescription->service, semid);
ipc->semId = semid;
hashMap_put(ipcSegment, endpointDescription->service, ipc);
} else {
logHelper_log(admin->loghelper, OSGI_LOGSERVICE_ERROR, "error getting semaphores.");
status = CELIX_BUNDLE_EXCEPTION;
}
}
if(ipc != NULL && status != CELIX_SUCCESS){
free(ipc);
}
return status;
}
celix_status_t remoteServiceAdmin_installEndpoint(remote_service_admin_pt admin, export_registration_pt registration, service_reference_pt reference, char *interface) {
celix_status_t status = CELIX_SUCCESS;
properties_pt endpointProperties = properties_create();
unsigned int size = 0;
char **keys;
serviceReference_getPropertyKeys(reference, &keys, &size);
for (int i = 0; i < size; i++) {
char *key = keys[i];
const char *value = NULL;
if (serviceReference_getProperty(reference, key, &value) == CELIX_SUCCESS && strcmp(key, (char*) OSGI_RSA_SERVICE_EXPORTED_INTERFACES) != 0 && strcmp(key, (char*) OSGI_FRAMEWORK_OBJECTCLASS) != 0) {
properties_set(endpointProperties, key, value);
}
}
hash_map_entry_pt entry = hashMap_getEntry(endpointProperties, (void *) OSGI_FRAMEWORK_SERVICE_ID);
char* key = hashMapEntry_getKey(entry);
char *serviceId = (char *) hashMap_remove(endpointProperties, (void *) OSGI_FRAMEWORK_SERVICE_ID);
const char *uuid = NULL;
uuid_t endpoint_uid;
uuid_generate(endpoint_uid);
char endpoint_uuid[37];
uuid_unparse_lower(endpoint_uid, endpoint_uuid);
bundleContext_getProperty(admin->context, OSGI_FRAMEWORK_FRAMEWORK_UUID, &uuid);
properties_set(endpointProperties, (char*) OSGI_RSA_ENDPOINT_FRAMEWORK_UUID, uuid);
properties_set(endpointProperties, (char*) OSGI_FRAMEWORK_OBJECTCLASS, interface);
properties_set(endpointProperties, (char*) OSGI_RSA_ENDPOINT_SERVICE_ID, serviceId);
properties_set(endpointProperties, (char*) OSGI_RSA_ENDPOINT_ID, endpoint_uuid);
properties_set(endpointProperties, (char*) OSGI_RSA_SERVICE_IMPORTED, "true");
// properties_set(endpointProperties, (char*) OSGI_RSA_SERVICE_IMPORTED_CONFIGS, (char*) CONFIGURATION_TYPE);
if (properties_get(endpointProperties, (char *) RSA_SHM_PATH_PROPERTYNAME) == NULL) {
char sharedIdentifierFile[RSA_FILEPATH_LENGTH];
if (remoteServiceAdmin_getSharedIdentifierFile(admin, (char*)uuid, interface, sharedIdentifierFile) == CELIX_SUCCESS) {
properties_set(endpointProperties, RSA_SHM_PATH_PROPERTYNAME, sharedIdentifierFile);
} else {
properties_set(endpointProperties, (char *) RSA_SHM_PATH_PROPERTYNAME, (char *) RSA_SHM_DEFAULTPATH);
}
}
if (properties_get(endpointProperties, (char *) RSA_SHM_FTOK_ID_PROPERTYNAME) == NULL) {
properties_set(endpointProperties, (char *) RSA_SHM_FTOK_ID_PROPERTYNAME, (char *) RSA_SHM_DEFAULT_FTOK_ID);
}
if (properties_get(endpointProperties, (char *) RSA_SEM_PATH_PROPERTYNAME) == NULL) {
char sharedIdentifierFile[RSA_FILEPATH_LENGTH];
if (remoteServiceAdmin_getSharedIdentifierFile(admin, (char*)uuid, interface, sharedIdentifierFile) == CELIX_SUCCESS) {
properties_set(endpointProperties, (char *) RSA_SEM_PATH_PROPERTYNAME, sharedIdentifierFile);
} else {
properties_set(endpointProperties, (char *) RSA_SEM_PATH_PROPERTYNAME, (char *) RSA_SEM_DEFAULTPATH);
}
}
if (properties_get(endpointProperties, (char *) RSA_SEM_FTOK_ID_PROPERTYNAME) == NULL) {
properties_set(endpointProperties, (char *) RSA_SEM_FTOK_ID_PROPERTYNAME, (char *) RSA_SEM_DEFAULT_FTOK_ID);
}
endpoint_description_pt endpointDescription = NULL;
remoteServiceAdmin_createEndpointDescription(admin, reference, endpointProperties, interface, &endpointDescription);
exportRegistration_setEndpointDescription(registration, endpointDescription);
free(key);
free(serviceId);
free(keys);
return status;
}
celix_status_t remoteServiceAdmin_createEndpointDescription(remote_service_admin_pt admin, service_reference_pt reference, properties_pt endpointProperties, char *interface, endpoint_description_pt *description) {
celix_status_t status = CELIX_SUCCESS;
*description = calloc(1, sizeof(**description));
if (!*description) {
status = CELIX_ENOMEM;
} else {
if (status == CELIX_SUCCESS) {
(*description)->properties = endpointProperties;
(*description)->frameworkUUID = (char*)properties_get(endpointProperties, (char*) OSGI_RSA_ENDPOINT_FRAMEWORK_UUID);
const char *serviceId = NULL;
serviceReference_getProperty(reference, (char*)OSGI_FRAMEWORK_SERVICE_ID, &serviceId);
(*description)->serviceId = strtoull(serviceId, NULL, 0);
(*description)->id = (char*)properties_get(endpointProperties, (char*) OSGI_RSA_ENDPOINT_ID);
(*description)->service = strndup(interface, 1024*10);
}
}
return status;
}
celix_status_t remoteServiceAdmin_destroyEndpointDescription(endpoint_description_pt *description) {
celix_status_t status = CELIX_SUCCESS;
properties_destroy((*description)->properties);
free((*description)->service);
free(*description);
return status;
}
celix_status_t remoteServiceAdmin_getExportedServices(remote_service_admin_pt admin, array_list_pt *services) {
celix_status_t status = CELIX_SUCCESS;
return status;
}
celix_status_t remoteServiceAdmin_getImportedEndpoints(remote_service_admin_pt admin, array_list_pt *services) {
celix_status_t status = CELIX_SUCCESS;
return status;
}
celix_status_t remoteServiceAdmin_importService(remote_service_admin_pt admin, endpoint_description_pt endpointDescription, import_registration_pt *registration) {
celix_status_t status = CELIX_SUCCESS;
logHelper_log(admin->loghelper, OSGI_LOGSERVICE_INFO, "RSA: Import service %s", endpointDescription->service);
celixThreadMutex_lock(&admin->importedServicesLock);
import_registration_factory_pt registration_factory = (import_registration_factory_pt) hashMap_get(admin->importedServices, endpointDescription->service);
// check whether we already have a registration_factory registered in the hashmap
if (registration_factory == NULL) {
status = importRegistrationFactory_install(admin->loghelper, endpointDescription->service, admin->context, &registration_factory);
if (status == CELIX_SUCCESS) {
hashMap_put(admin->importedServices, endpointDescription->service, registration_factory);
}
}
// factory available
if (status != CELIX_SUCCESS || (registration_factory->trackedFactory == NULL)) {
logHelper_log(admin->loghelper, OSGI_LOGSERVICE_WARNING, "RSA: no proxyFactory available.");
if (status == CELIX_SUCCESS) {
status = CELIX_SERVICE_EXCEPTION;
}
} else {
// we create an importRegistration per imported service
importRegistration_create(endpointDescription, admin, (sendToHandle) &remoteServiceAdmin_send, admin->context, registration);
registration_factory->trackedFactory->registerProxyService(registration_factory->trackedFactory->factory, endpointDescription, admin, (sendToHandle) &remoteServiceAdmin_send);
arrayList_add(registration_factory->registrations, *registration);
remoteServiceAdmin_createOrAttachShm(admin->importedIpcSegment, admin, endpointDescription, false);
}
celixThreadMutex_unlock(&admin->importedServicesLock);
return status;
}
celix_status_t remoteServiceAdmin_removeImportedService(remote_service_admin_pt admin, import_registration_pt registration) {
celix_status_t status = CELIX_SUCCESS;
if (registration != NULL) {
celixThreadMutex_lock(&admin->importedServicesLock);
ipc_segment_pt ipc = NULL;
endpoint_description_pt endpointDescription = (endpoint_description_pt) registration->endpointDescription;
import_registration_factory_pt registration_factory = (import_registration_factory_pt) hashMap_get(admin->importedServices, endpointDescription->service);
// detach from IPC
if (remoteServiceAdmin_getIpcSegment(admin, endpointDescription, &ipc) != CELIX_SUCCESS) {
logHelper_log(admin->loghelper, OSGI_LOGSERVICE_ERROR, "Error while retrieving IPC segment for imported service %s.", endpointDescription->service);
} else if (remoteServiceAdmin_detachIpcSegment(ipc) != CELIX_SUCCESS) {
logHelper_log(admin->loghelper, OSGI_LOGSERVICE_ERROR, "Error while detaching IPC segment for imported service %s.", endpointDescription->service);
}
ipc = hashMap_remove(admin->importedIpcSegment,endpointDescription);
if(ipc!=NULL){
free(ipc);
}
// factory available
if ((registration_factory == NULL) || (registration_factory->trackedFactory == NULL)) {
logHelper_log(admin->loghelper, OSGI_LOGSERVICE_ERROR, "Error while retrieving registration factory for imported service %s.", endpointDescription->service);
} else {
registration_factory->trackedFactory->unregisterProxyService(registration_factory->trackedFactory->factory, endpointDescription);
arrayList_removeElement(registration_factory->registrations, registration);
importRegistration_destroy(registration);
if (arrayList_isEmpty(registration_factory->registrations) == true) {
logHelper_log(admin->loghelper, OSGI_LOGSERVICE_INFO, "closing proxy");
serviceTracker_close(registration_factory->proxyFactoryTracker);
importRegistrationFactory_close(registration_factory);
hashMap_remove(admin->importedServices, endpointDescription->service);
importRegistrationFactory_destroy(&registration_factory);
}
}
celixThreadMutex_unlock(&admin->importedServicesLock);
}
return status;
}