/**
 * @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);
}
Beispiel #2
0
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;
}
Beispiel #4
0
/**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;
}
Beispiel #5
0
/**
 * 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;
}