/** * @internal * Called whenever the socket becomes readable. * ZeroMq since sends multipart messages atomically (all or nothing) * both message parts are instantly available. * * @param socket ZeroMq socket * @param context context passed to elektraIoAdapterZeroMqAttach() */ static void zeroMqRecvSocketReadable (void * socket, void * context) { ElektraZeroMqRecvPluginData * data = context; char * changeType; char * changedKeyName; zmq_msg_t message; zmq_msg_init (&message); int result = zmq_msg_recv (&message, socket, ZMQ_DONTWAIT); if (result == -1) { ELEKTRA_LOG_WARNING ("receiving change type failed: %s; aborting", zmq_strerror (zmq_errno ())); zmq_msg_close (&message); return; } if (!zmq_msg_more (&message)) { ELEKTRA_LOG_WARNING ("message has only one part; aborting"); zmq_msg_close (&message); return; } int length = zmq_msg_size (&message); changeType = elektraStrNDup (zmq_msg_data (&message), length + 1); changeType[length] = '\0'; ELEKTRA_LOG_DEBUG ("received change type %s", changeType); result = zmq_msg_recv (&message, socket, ZMQ_DONTWAIT); if (result == -1) { ELEKTRA_LOG_WARNING ("receiving key name failed: %s; aborting", zmq_strerror (zmq_errno ())); elektraFree (changeType); zmq_msg_close (&message); return; } length = zmq_msg_size (&message); changedKeyName = elektraStrNDup (zmq_msg_data (&message), length + 1); changedKeyName[length] = '\0'; ELEKTRA_LOG_DEBUG ("received key name %s", changedKeyName); // notify about changes Key * changedKey = keyNew (changedKeyName, KEY_END); data->notificationCallback (changedKey, data->notificationContext); zmq_msg_close (&message); elektraFree (changeType); elektraFree (changedKeyName); }
static void test_elektraMalloc (void) { char * buffer = 0; buffer = elektraMalloc (50); exit_if_fail (buffer, "buffer must not be 0 after allocation"); elektraRealloc ((void **)&buffer, 100); exit_if_fail (buffer, "buffer must not be 0 after reallocation"); elektraRealloc ((void **)&buffer, 20); exit_if_fail (buffer, "buffer must not be 0 after reallocation"); elektraFree (buffer); buffer = elektraCalloc (50); exit_if_fail (buffer, "buffer must not be 0 after allocation"); for (int i = 0; i < 50; ++i) { succeed_if (buffer[i] == 0, "elektraCalloc did not initialize buffer with zeros"); } elektraRealloc ((void **)&buffer, 100); exit_if_fail (buffer, "buffer must not be 0 after reallocation"); elektraRealloc ((void **)&buffer, 20); exit_if_fail (buffer, "buffer must not be 0 after reallocation"); char * dup = elektraStrNDup (buffer, 20); exit_if_fail (dup, "could not duplicate buffer"); elektraFree (buffer); buffer = 0; for (int i = 0; i < 20; ++i) { succeed_if (dup[i] == 0, "elektraStrNDup did not correctly copy zero-buffer"); } elektraFree (dup); }
/** * Main function for notification reader thread. * * Sets global variables receivedKeyName and receivedChangeType. * * @internal * * @param subSocket socket to read messages from * @return always NULL */ static void * notificationReaderThreadMain (void * filter) { void * subSocket = createTestSocket ((char *) filter); time_t start = time (NULL); zmq_msg_t message; zmq_msg_init (&message); int more; size_t moreSize = sizeof (more); int rc; int partCounter = 0; int maxParts = 2; // change type and key name int lastErrno; do { usleep (100 * 1000); // wait 100 ms lastErrno = 0; int result = zmq_msg_recv (&message, subSocket, ZMQ_DONTWAIT); // check for timeout if (time (NULL) - start > TEST_TIMEOUT) { receiveTimeout = 1; receivedChangeType = NULL; receivedKeyName = NULL; zmq_msg_close (&message); zmq_close (subSocket); return NULL; } // check for errors if (result == -1) { lastErrno = zmq_errno (); if (lastErrno != EAGAIN) { yield_error ("zmq_msg_recv failed"); printf ("zmq_msg_recv failed: %s\n", zmq_strerror (lastErrno)); zmq_msg_close (&message); zmq_close (subSocket); return NULL; } } else { rc = zmq_getsockopt (subSocket, ZMQ_RCVMORE, &more, &moreSize); if (rc < 0) { yield_error ("zmq_getsockopt failed"); printf ("zmq_getsockopt failed: %s\n", zmq_strerror (zmq_errno ())); zmq_msg_close (&message); zmq_close (subSocket); return NULL; } int length = zmq_msg_size (&message); char * buffer = elektraStrNDup (zmq_msg_data (&message), length + 1); buffer[length] = '\0'; switch (partCounter) { case 0: receivedChangeType = buffer; break; case 1: receivedKeyName = buffer; break; default: yield_error ("test inconsistency"); } partCounter++; } } while (lastErrno == EAGAIN || (more && partCounter < maxParts)); zmq_msg_close (&message); zmq_close (subSocket); return NULL; }
/**Set a new meta-information. * * Will set a new meta-information pair consisting of * metaName and newMetaString. * * Will add a new Pair for meta-information if metaName was * not added up to now. * * It will modify a existing Pair of meta-information if the * the metaName was inserted already. * * It will remove a meta information if newMetaString is 0. * * @param key the key object to work with * @param metaName the name of the meta information where you * want to change the value * @param newMetaString the new value for the meta information * @retval -1 on error if key or metaName is 0, out of memory * or names are not valid * @retval 0 if the meta-information for metaName was removed * @return size (>0) of newMetaString if meta-information was * successfully added * @see keyGetMeta() * @ingroup keymeta **/ ssize_t keySetMeta (Key * key, const char * metaName, const char * newMetaString) { Key * toSet; char * metaStringDup; ssize_t metaNameSize; ssize_t metaStringSize = 0; if (!key) return -1; if (key->flags & KEY_FLAG_RO_META) return -1; if (!metaName) return -1; metaNameSize = elektraStrLen (metaName); if (metaNameSize == -1) return -1; if (newMetaString) metaStringSize = elektraStrLen (newMetaString); // optimization: we have nothing and want to remove something: if (!key->meta && !newMetaString) return 0; toSet = keyNew (0); if (!toSet) return -1; elektraKeySetName (toSet, metaName, KEY_META_NAME | KEY_EMPTY_NAME); /*Lets have a look if the key is already inserted.*/ if (key->meta) { Key * ret; ret = ksLookup (key->meta, toSet, KDB_O_POP); if (ret) { /*It was already there, so lets drop that one*/ keyDel (ret); key->flags |= KEY_FLAG_SYNC; } } if (newMetaString) { /*Add the meta information to the key*/ metaStringDup = elektraStrNDup (newMetaString, metaStringSize); if (!metaStringDup) { // TODO: actually we might already have changed // the key keyDel (toSet); return -1; } if (toSet->data.v) elektraFree (toSet->data.v); toSet->data.c = metaStringDup; toSet->dataSize = metaStringSize; } else { /*The request is to remove the meta string. So simply drop it.*/ keyDel (toSet); return 0; } if (!key->meta) { /*Create a new place for meta information.*/ key->meta = ksNew (0, KS_END); if (!key->meta) { keyDel (toSet); return -1; } } set_bit (toSet->flags, KEY_FLAG_RO_NAME); set_bit (toSet->flags, KEY_FLAG_RO_VALUE); set_bit (toSet->flags, KEY_FLAG_RO_META); ksAppendKey (key->meta, toSet); key->flags |= KEY_FLAG_SYNC; return metaStringSize; }
/** * Copy or Clear a key. * * Most often you may prefer keyDup() which allocates * a new key and returns a duplication of another key. * * But when you need to copy into an existing key, e.g. * because it was passed by a pointer in a function * you can do so: * * @snippet keyCopy.c Basic Usage * * The reference counter will not be changed for * both keys. Affiliation to keysets * are also not affected. * * The meta data will be duplicated for the destination * key. So it will not take much additional space, even * with lots of metadata. * * When you pass a NULL-pointer as source the * data of dest will be cleaned completely * (except reference counter, see keyClear()) and * you get a fresh dest key: * * @snippet keyCopy.c Clear * * If you want to copy everything, except e.g. the value * you can use keyCopy() too: * * @snippet keyCopy.c Copy Without Value * * Restrain from coping everything yourself, because it will lead to * wrong metadata and is not able to copy empty or cascading names: * * @snippet keyCopy.c Individual Copy * * * @param dest the key which will be written to * @param source the key which should be copied * or NULL to clean the destination key * @ingroup key * @retval -1 on failure when a NULL pointer * was passed for dest or a dynamic property could not * be written. The content will be unmodified then. * @retval 0 when dest was cleaned * @retval 1 when source was successfully copied * @see keyDup() to get a duplication of a key */ int keyCopy (Key * dest, const Key * source) { if (!dest) return -1; if (test_bit (dest->flags, KEY_FLAG_RO_NAME) || test_bit (dest->flags, KEY_FLAG_RO_VALUE) || test_bit (dest->flags, KEY_FLAG_RO_META)) { return -1; } if (!source) { keyClear (dest); return 0; } // remember dynamic memory to be removed char * destKey = dest->key; void * destData = dest->data.c; KeySet * destMeta = dest->meta; // duplicate dynamic properties if (source->key) { dest->key = elektraStrNDup (source->key, source->keySize + source->keyUSize); if (!dest->key) goto memerror; } else { dest->key = 0; } if (source->data.v) { dest->data.v = elektraStrNDup (source->data.v, source->dataSize); if (!dest->data.v) goto memerror; } else { dest->data.v = 0; } if (source->meta) { dest->meta = ksDup (source->meta); if (!dest->meta) goto memerror; } else { dest->meta = 0; } // successful, now do the irreversible stuff: we obviously modified dest set_bit (dest->flags, KEY_FLAG_SYNC); // copy sizes accordingly dest->keySize = source->keySize; dest->keyUSize = source->keyUSize; dest->dataSize = source->dataSize; // free old resources of destination elektraFree (destKey); elektraFree (destData); ksDel (destMeta); return 1; memerror: elektraFree (dest->key); elektraFree (dest->data.v); ksDel (dest->meta); dest->key = destKey; dest->data.v = destData; dest->meta = destMeta; return -1; }