/** ******************************************************************************* * @brief Create a new signal message with ref count of 1. * * @param category IN category * @param method IN method (optional, NULL means none) * @param payload IN payload * * @retval message on success * @retval NULL on failure ******************************************************************************* */ _LSTransportMessage* LSTransportMessageSignalNewRef(const char *category, const char *method, const char *payload) { int category_len = strlen(category) + 1; int method_len = strlen(method) + 1; int payload_len = strlen(payload) + 1; LS_ASSERT(category_len > 1); LS_ASSERT(method_len > 1); _LSTransportMessage *message = _LSTransportMessageNewRef(category_len + method_len + payload_len); _LSTransportMessageSetType(message, _LSTransportMessageTypeSignal); char *message_body = _LSTransportMessageGetBody(message); memcpy(message_body, category, category_len); message_body += category_len; memcpy(message_body, method, method_len); message_body += method_len; memcpy(message_body, payload, payload_len); /* TODO: original code also appended the service_name of the sender (or "") * if there was no name (sh->name) */ return message; }
/** * @brief Increment ref count on message object. You MUST call this if you wish to store * LSMessage yourself. A LSMessageRef() MUST be paired with a LSMessageUnref() * lest you leak memory. * * @param message */ void LSMessageRef(LSMessage *message) { LS_ASSERT(message != NULL); LS_ASSERT(g_atomic_int_get (&message->ref) > 0); //g_debug("%s(%p)", __FUNCTION__, message); g_atomic_int_inc(&message->ref); }
/** ******************************************************************************* * @brief Increment the ref count of a client. * * @param client IN client ******************************************************************************* */ void _LSTransportClientRef(_LSTransportClient *client) { LS_ASSERT(client != NULL); LS_ASSERT(g_atomic_int_get(&client->ref) > 0); g_atomic_int_inc(&client->ref); _ls_verbose("%s: %d (%p)\n", __func__, client->ref, client); }
/** ******************************************************************************* * @brief Send a signal registration message. * * @param transport IN transport * @param reg IN true to register, false to unregister * @param category IN category (required) * @param method IN method (optional, NULL means none) * @param token OUT message token * @param lserror OUT set on error * * @retval true on success * @retval false on failure ******************************************************************************* */ bool _LSTransportSignalRegistration(_LSTransport *transport, bool reg, const char *category, const char *method, LSMessageToken *token, LSError *lserror) { /* * format: * * category + NUL * method + NUL (if method is NULL, then we just have NUL) */ bool ret = true; int category_len = strlen_safe(category) + 1; int method_len = strlen_safe(method) + 1; LOG_LS_TRACE("%s: category: %s, method: %s\n", __func__, category, method); _LSTransportMessage *message = _LSTransportMessageNewRef(category_len + method_len); if (reg) { _LSTransportMessageSetType(message, _LSTransportMessageTypeSignalRegister); } else { _LSTransportMessageSetType(message, _LSTransportMessageTypeSignalUnregister); } char *message_body = _LSTransportMessageGetBody(message); LS_ASSERT(message_body != NULL); memcpy(message_body, category, category_len); message_body += category_len; if (method_len == 1) { char nul = '\0'; memcpy(message_body, &nul, sizeof(nul)); } else { memcpy(message_body, method, method_len); } LS_ASSERT(transport->hub != NULL); if (!_LSTransportSendMessage(message, transport->hub, token, lserror)) { ret = false; } _LSTransportMessageUnref(message); return ret; }
/** * @brief Decrement ref count on message object. Object is freed if ref goes to zero. * * @param message */ void LSMessageUnref(LSMessage *message) { LS_ASSERT(message != NULL); LS_ASSERT(g_atomic_int_get (&message->ref) > 0); //g_debug("%s(%p)", __FUNCTION__, message); if (g_atomic_int_dec_and_test(&message->ref)) { _LSMessageFree(message); } }
/** ******************************************************************************* * @brief Free an incoming queue. * * @param incoming IN incoming ******************************************************************************* */ void _LSTransportIncomingFree(_LSTransportIncoming *incoming) { LS_ASSERT(incoming != NULL); /* want to have processed all incoming messages so we don't lose any */ LS_ASSERT(incoming->tmp_msg == NULL); LS_ASSERT(g_queue_is_empty(incoming->complete_messages)); g_queue_free(incoming->complete_messages); #ifdef MEMCHECK memset(incoming, 0xFF, sizeof(_LSTransportIncoming)); #endif g_slice_free(_LSTransportIncoming, incoming); }
/*------------------------------------- Determine if *this Buffer Object is currently active. -------------------------------------*/ bool BufferObject::is_bound() const noexcept { GLint typeToCheck = 0; switch (get_type()) { case buffer_use_t::VBO_BUFFER_ARRAY: typeToCheck = GL_ARRAY_BUFFER_BINDING; break; case buffer_use_t::VBO_BUFFER_ELEMENT: typeToCheck = GL_ELEMENT_ARRAY_BUFFER_BINDING; break; case buffer_use_t::VBO_BUFFER_TRANSFORM_FEEDBACK: typeToCheck = GL_TRANSFORM_FEEDBACK_BUFFER_BINDING; break; case buffer_use_t::VBO_BUFFER_UNIFORM_BUFFER: typeToCheck = GL_UNIFORM_BUFFER_BINDING; break; default: LS_LOG_ERR("Forgot to implement an enumeration for the current buffer type!"); break; } // just fail, no room for debug statements here. LS_ASSERT(typeToCheck != 0); GLint currentBuffer = 0; glGetIntegerv(typeToCheck, ¤tBuffer); return currentBuffer == (GLint)this->gpuId; }
inline void _lshandle_validate(LSHandle *sh) { if (sh && sh->history.magic_state_num != LSHANDLE_MAGIC_STATE_VALID) { Dl_info create_info; Dl_info destroy_info; bool create_info_valid = false; bool destroy_info_valid = false; if (sh->history.creator_ret_addr) { create_info_valid = dladdr(sh->history.creator_ret_addr, &create_info); } if (sh->history.destroyer_ret_addr) { destroy_info_valid = dladdr(sh->history.destroyer_ret_addr, &destroy_info); } LOG_LS_ERROR(MSGID_LS_INVALID_HANDLE, 5, PMLOGKFV("HANDLER", "%p", sh), PMLOGKS("CREATE_DLI_FNAME", create_info_valid ? create_info.dli_fname : "(unknown)"), PMLOGKS("CREATE_DLI_SNAME", create_info_valid ? create_info.dli_sname : "(unknown)"), PMLOGKS("DESTR_DLI_FNAME", destroy_info_valid ? destroy_info.dli_fname : "(unknown)"), PMLOGKS("DESTR_DLI_SNAME", destroy_info_valid ? destroy_info.dli_sname : "(unknown)"), "%s: Invalid handle", __func__); LS_ASSERT(!"Invalid LSHandle"); } }
/** ******************************************************************************* * @brief Decrement the ref count of a client. * * @param client IN client ******************************************************************************* */ void _LSTransportClientUnref(_LSTransportClient *client) { LS_ASSERT(client != NULL); LS_ASSERT(g_atomic_int_get(&client->ref) > 0); if (g_atomic_int_dec_and_test(&client->ref)) { _ls_verbose("%s: %d (%p)\n", __func__, client->ref, client); _LSTransportClientFree(client); } else { _ls_verbose("%s: %d (%p)\n", __func__, client->ref, client); } }
inline void _lshandle_validate(LSHandle *sh) { if (sh && sh->history.magic_state_num != LSHANDLE_MAGIC_STATE_VALID) { Dl_info create_info; Dl_info destroy_info; bool create_info_valid = false; bool destroy_info_valid = false; if (sh->history.creator_ret_addr) { create_info_valid = dladdr(sh->history.creator_ret_addr, &create_info); } if (sh->history.destroyer_ret_addr) { destroy_info_valid = dladdr(sh->history.destroyer_ret_addr, &destroy_info); } g_critical("%s: Invalid handle %p, created by call from %s:%s, destroyed by call from %s:%s", __func__, sh, create_info_valid ? create_info.dli_fname : "(unknown)", create_info_valid ? create_info.dli_sname : "(unknown)", destroy_info_valid ? destroy_info.dli_fname : "(unknown)", destroy_info_valid ? destroy_info.dli_sname : "(unknown)" ); LS_ASSERT(!"invalid LSHandle"); } }
/** ******************************************************************************* * @brief Get the unique name from a "ServiceStatus" message. * * @param message IN message * * @retval name string on success * @retval NULL on failure ******************************************************************************* */ const char* LSTransportServiceStatusSignalGetUniqueName(_LSTransportMessage *message) { /* TODO: we may want this eventually, it's pretty much the same as GetServiceName */ LOG_LS_ERROR(MSGID_LS_NOT_IMPLEMENTED, 0, "Not yet implemented!"); LS_ASSERT(0); return NULL; }
static void _FreeMonitorListInfoItem(_LSMonitorListInfo *info) { LS_ASSERT(info != NULL); g_free(info->unique_name); g_free(info->service_name); g_free(info->exe_path); g_free(info->service_type); g_free(info); }
/** ******************************************************************************* * @brief Free a serial map entry. * * @param entry IN entry ******************************************************************************* */ void _LSTransportSerialMapEntryFree(_LSTransportSerialMapEntry *entry) { LS_ASSERT(entry != NULL); #ifdef MEMCHECK memset(entry, 0xFF, sizeof(_LSTransportSerialMapEntry)); #endif g_slice_free(_LSTransportSerialMapEntry, entry); }
void _LSCatalogRemoveClientSubscriptions(_Catalog *catalog, _LSTransportClient *client) { LS_ASSERT(catalog != NULL); LS_ASSERT(_LSTransportClientGetUniqueName(client) != NULL); const char *client_name = _LSTransportClientGetUniqueName(client); _CatalogLock(catalog); char *key = NULL; _SubList *tokens = NULL; if (!g_hash_table_lookup_extended(catalog->client_subscriptions, client_name, (gpointer *) &key, (gpointer *) &tokens)) { LOG_LS_DEBUG("Disconnected service had no subscriptions: %s", client->service_name); _CatalogUnlock(catalog); return; } g_hash_table_steal(catalog->client_subscriptions, client_name); g_free(key); _CatalogUnlock(catalog); int i; for (i = _SubListLen(tokens) - 1; i >= 0; --i) { const char *token = _SubListGet(tokens, i); _Subscription *subs = _SubscriptionAcquire(catalog, token); if (subs) { _CatalogRemoveToken(catalog, token, true); _SubscriptionRelease(catalog, subs); } } _SubListFree(tokens); }
static void _SubscriptionRelease(_Catalog *catalog, _Subscription *subs) { if (subs) { LS_ASSERT(g_atomic_int_get(&subs->ref) > 0); if (g_atomic_int_dec_and_test(&subs->ref)) { _SubscriptionFree(catalog, subs); } } }
/** ******************************************************************************* * @brief Free an outgoing queue. * * @param outgoing IN outgoing queue ******************************************************************************* */ void _LSTransportOutgoingFree(_LSTransportOutgoing *outgoing) { LS_ASSERT(outgoing != NULL); LS_ASSERT(outgoing->queue != NULL); LS_ASSERT(outgoing->serial != NULL); while (!g_queue_is_empty(outgoing->queue)) { _LSTransportMessage *message = g_queue_pop_head(outgoing->queue); _LSTransportMessageUnref(message); } g_queue_free(outgoing->queue); _LSTransportSerialFree(outgoing->serial); #ifdef MEMCHECK memset(outgoing, 0xFF, sizeof(_LSTransportOutgoing)); #endif g_slice_free(_LSTransportOutgoing, outgoing); }
/** ******************************************************************************* * @brief Free a serial list item. * * @param list_item IN serial list item to free ******************************************************************************* */ void _LSTransportSerialListItemFree(_LSTransportSerialListItem *list_item) { LS_ASSERT(list_item != NULL); _LSTransportMessageUnref(list_item->message); #ifdef MEMCHECK memset(list_item, 0xFF, sizeof(_LSTransportSerialListItem)); #endif g_slice_free(_LSTransportSerialListItem, list_item); }
/** ******************************************************************************* * @brief Free a credentials object. * * @param cred IN credentials ******************************************************************************* */ void _LSTransportCredFree(_LSTransportCred *cred) { LS_ASSERT(cred != NULL); g_free((char*)cred->exe_path); g_free((char*)cred->cmd_line); #ifdef MEMCHECK memset(cred, 0xFF, sizeof(_LSTransportCred)); #endif g_slice_free(_LSTransportCred, cred); }
/** ******************************************************************************* * @brief Get the credentials from a unix domain socket. * * @param fd IN unix domain socket fd * @param cred IN/OUT credentials * @param lserror OUT set on error * * @retval true on success * @retval false on failure ******************************************************************************* */ bool _LSTransportGetCredentials(int fd, _LSTransportCred *cred, LSError *lserror) { LS_ASSERT(cred != NULL); #ifdef SO_PEERCRED struct ucred tmp_cred; socklen_t len = sizeof(tmp_cred); if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &tmp_cred, &len) != 0) { _LSErrorSetFromErrno(lserror, errno); return false; } cred->pid = tmp_cred.pid; cred->uid = tmp_cred.uid; cred->gid = tmp_cred.gid; /* NOV-101642: Only do the following check if we're the hub */ if (_LSTransportIsHub()) { if (tmp_cred.pid != LS_PID_INVALID) { cred->exe_path = _LSTransportPidToExe(tmp_cred.pid, lserror); if (!cred->exe_path) { return false; } cred->cmd_line = _LSTransportPidToCmdLine(tmp_cred.pid, lserror); if (!cred->cmd_line) { g_free((char*)cred->exe_path); cred->exe_path = NULL; return false; } } } #else cred->pid = LS_PID_INVALID; cred->uid = LS_UID_INVALID; cred->gid = LS_GID_INVALID; #endif return true; }
/** ******************************************************************************* * @brief Save a serial (token) in the queue and map. * * @attention locks the serial lock * * @param serial_info IN serial info * @param serial IN message serial (token) to save * @param lserror OUT set on error * * @retval true on success * @retval false on failure ******************************************************************************* */ bool _LSTransportSerialSave(_LSTransportSerial *serial_info, _LSTransportMessage *message, LSError *lserror) { LSMessageToken serial = _LSTransportMessageGetToken(message); _LSTransportSerialListItem *item = _LSTransportSerialListItemNew(serial, message); SERIAL_INFO_LOCK(&serial_info->lock); g_queue_push_tail(serial_info->queue, item); GList *list = g_queue_peek_tail_link(serial_info->queue); LS_ASSERT(list != NULL); _LSTransportSerialMapEntry *map_entry = _LSTransportSerialMapEntryNew(serial, list); LS_ASSERT(NULL == g_hash_table_lookup(serial_info->map, &map_entry->serial)); g_hash_table_insert(serial_info->map, &map_entry->serial, map_entry); SERIAL_INFO_UNLOCK(&serial_info->lock); return true; }
/** ******************************************************************************* * @brief Send a signal. * * @param transport IN transport * @param category IN category * @param method IN method (optional, NULL means none) * @param payload IN payload * @param lserror OUT set on error * * @retval true on success * @retval false on failure ******************************************************************************* */ bool LSTransportSendSignal(_LSTransport *transport, const char *category, const char *method, const char *payload, LSError *lserror) { bool ret = true; _LSTransportMessage *message = LSTransportMessageSignalNewRef(category, method, payload); LS_ASSERT(transport->hub != NULL); ret = _LSTransportSendMessage(message, transport->hub, NULL, lserror); _LSTransportMessageUnref(message); return ret; }
const char * _SubListGet(_SubList *tokens, int i) { if (i < 0 || i >= tokens->len) { LOG_LS_ERROR(MSGID_LS_SUBSCRIPTION_ERR, 0, "%s: attempting to get out of range subscription %d\n" "It is possible you forgot to follow the pattern: " " LSSubscriptionHasNext() + LSSubscriptionNext()", __FUNCTION__, i); return NULL; } LS_ASSERT(i >= 0 && i < tokens->len); return g_ptr_array_index(tokens, i); }
/** ******************************************************************************* * @brief Allocate a new incoming queue. * * @retval incoming queue on success * @retval NULL on failure ******************************************************************************* */ _LSTransportIncoming* _LSTransportIncomingNew(void) { _LSTransportIncoming *incoming = g_slice_new0(_LSTransportIncoming); if (incoming) { /* This cannot fail when using eglibc (2.15) */ if (pthread_mutex_init(&incoming->lock, NULL)) { g_slice_free(_LSTransportIncoming, incoming); return NULL; } incoming->complete_messages = g_queue_new(); LS_ASSERT(incoming->complete_messages != NULL); } return incoming; }
static _Subscription * _SubscriptionAcquire(_Catalog *catalog, const char *uniqueToken) { _CatalogLock(catalog); _Subscription *subs= g_hash_table_lookup(catalog->token_map, uniqueToken); if (subs) { LS_ASSERT(g_atomic_int_get(&subs->ref) > 0); g_atomic_int_inc(&subs->ref); } _CatalogUnlock(catalog); return subs; }
static void _CatalogCallCancelNotifications(_Catalog *catalog, const char *uniqueToken) { LS_ASSERT(uniqueToken); _CatalogLock(catalog); if (catalog->cancel_notify_list) { int idx; for (idx = 0; idx < catalog->cancel_notify_list->len; ++idx) { _SubscriberCancelNotification *scn = g_ptr_array_index(catalog->cancel_notify_list, idx); if (scn->function) { scn->function(catalog->sh, uniqueToken, scn->context); } } } _CatalogUnlock(catalog); }
/** ******************************************************************************* * @brief Get the service name from a "ServceStatus" message. The name is * allocated and should be freed. * * @param message IN message * * @retval name string on success * @retval NULL on error ******************************************************************************* */ char* LSTransportServiceStatusSignalGetServiceName(_LSTransportMessage *message) { JSchemaInfo schemaInfo; jschema_info_init(&schemaInfo, jschema_all(), NULL, NULL); LS_ASSERT(_LSTransportMessageGetType(message) == _LSTransportMessageTypeServiceDownSignal || _LSTransportMessageGetType(message) == _LSTransportMessageTypeServiceUpSignal); char *service_name = NULL; jvalue_ref service_name_obj = NULL; const char *payload = _LSTransportMessageGetPayload(message); if (!payload) { LOG_LS_ERROR(MSGID_LS_INVALID_JSON, 0, "Unable to get payload from message"); return NULL; } /* get the serviceName part of the JSON object */ jvalue_ref payload_json = jdom_parse(j_cstr_to_buffer(payload), DOMOPT_NOOPT, &schemaInfo); bool ret = jobject_get_exists(payload_json, J_CSTR_TO_BUF(SERVICE_STATUS_SERVICE_NAME), &service_name_obj); if (ret) { raw_buffer service_name_buf = jstring_get_fast(service_name_obj); service_name = g_strndup(service_name_buf.m_str, service_name_buf.m_len); } else { LOG_LS_ERROR(MSGID_LS_INVALID_JSON, 0, "Unable to get service name string from payload: %s", payload); } j_release(&payload_json); return service_name; }
_LSTransportMonitorSerial _LSTransportShmGetSerial(_LSTransportShm* shm) { LS_ASSERT(shm != NULL); _LSTransportMonitorSerial ret = MONITOR_SERIAL_INVALID; /* Make sure a rogue process didn't mess with the shared mem */ if (shm->data->front_fence == FENCE_VAL && shm->data->back_fence == FENCE_VAL) { pthread_mutex_lock(&shm->data->lock); ret = ++shm->data->serial; if (unlikely(ret == MONITOR_SERIAL_INVALID)) { ret++; } pthread_mutex_unlock(&shm->data->lock); } return ret; }
/** ******************************************************************************* * @brief Free transport serial info * * @param serial_info IN serial info ******************************************************************************* */ void _LSTransportSerialFree(_LSTransportSerial *serial_info) { LS_ASSERT(serial_info != NULL); SERIAL_INFO_LOCK(&serial_info->lock); while (!g_queue_is_empty(serial_info->queue)) { _LSTransportSerialListItem *item = g_queue_pop_head(serial_info->queue); _LSTransportSerialListItemFree(item); } g_queue_free(serial_info->queue); g_hash_table_destroy(serial_info->map); /* key and value destroy functions clean this up */ SERIAL_INFO_UNLOCK(&serial_info->lock); #ifdef MEMCHECK memset(serial_info, 0xFF, sizeof(_LSTransportSerial)); #endif g_slice_free(_LSTransportSerial, serial_info); }
/** ******************************************************************************* * @brief Get the process' command line. * * @param cred IN credentials * * @retval cmdline on success * @retval NULL on failure ******************************************************************************* */ inline const char* _LSTransportCredGetCmdLine(const _LSTransportCred *cred) { LS_ASSERT(cred != NULL); return cred->cmd_line; }
/** ******************************************************************************* * @brief Get the full path to executable. * * @param cred IN credentials * * @retval path on success * @retval NULL on failure ******************************************************************************* */ inline const char* _LSTransportCredGetExePath(const _LSTransportCred *cred) { LS_ASSERT(cred != NULL); return cred->exe_path; }